From 38bf43cdd608761dc51407b12d4bfeaadd7ec19a Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Fri, 29 Jan 2021 00:22:03 -0500 Subject: [PATCH 01/42] Added platformAccessory logging --- .homebridge-dev/config.json | 3 +- package-lock.json | 296 +++++++++++++++++++++--------------- package.json | 2 +- src/platformAccessory.ts | 101 ++++++------ 4 files changed, 230 insertions(+), 172 deletions(-) diff --git a/.homebridge-dev/config.json b/.homebridge-dev/config.json index 67bcc3d..a656d42 100644 --- a/.homebridge-dev/config.json +++ b/.homebridge-dev/config.json @@ -34,7 +34,8 @@ "blacklistedUniqueIDs": [""] }, "advancedOptions": { - "namesWithMacAddress": true + "namesWithMacAddress": false, + "logLevel": 5 } } ] diff --git a/package-lock.json b/package-lock.json index d1a9056..27d1783 100644 --- a/package-lock.json +++ b/package-lock.json @@ -342,13 +342,13 @@ "dev": true }, "bonjour-hap": { - "version": "3.5.11", - "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.5.11.tgz", - "integrity": "sha512-pSYWWxjx3t2vh3sMkBMxQ0QaCqFgqWFz9he9U1JSQ6Lvwev5W19J+nBQWFj55dzUOcH0rPtZh/A+k/MvI5etQw==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.2.tgz", + "integrity": "sha512-uwMGUJ2Yql/sqvxAqR4nkE4qypo5JJk7EtGMkB/ikHMHa7/0djDjB8Ct0ES+8OK8SKZzthrLngDo+e2VjcfdXw==", "dev": true, "requires": { "array-flatten": "^2.1.2", - "deep-equal": "^2.0.2", + "deep-equal": "^2.0.5", "ip": "^1.1.5", "multicast-dns": "^7.2.2", "multicast-dns-service-types": "^1.1.0" @@ -479,6 +479,16 @@ } } }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -631,9 +641,9 @@ } }, "decimal.js": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz", - "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", "dev": true }, "decompress-response": { @@ -646,22 +656,23 @@ } }, "deep-equal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.3.tgz", - "integrity": "sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", + "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", "dev": true, "requires": { - "es-abstract": "^1.17.5", - "es-get-iterator": "^1.1.0", + "call-bind": "^1.0.0", + "es-get-iterator": "^1.1.1", + "get-intrinsic": "^1.0.1", "is-arguments": "^1.0.4", "is-date-object": "^1.0.2", - "is-regex": "^1.0.5", + "is-regex": "^1.1.1", "isarray": "^2.0.5", - "object-is": "^1.1.2", + "object-is": "^1.1.4", "object-keys": "^1.1.1", - "object.assign": "^4.1.0", + "object.assign": "^4.1.2", "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.2", + "side-channel": "^1.0.3", "which-boxed-primitive": "^1.0.1", "which-collection": "^1.0.1", "which-typed-array": "^1.1.2" @@ -759,35 +770,39 @@ } }, "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "version": "1.18.0-next.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", + "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", "dev": true, "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2", "has": "^1.0.3", "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.1", + "object-inspect": "^1.9.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.3", + "string.prototype.trimstart": "^1.0.3" } }, "es-get-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", - "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", "dev": true, "requires": { - "es-abstract": "^1.17.4", + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", "has-symbols": "^1.0.1", - "is-arguments": "^1.0.4", - "is-map": "^2.0.1", - "is-set": "^2.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", "is-string": "^1.0.5", "isarray": "^2.0.5" } @@ -1063,6 +1078,17 @@ "integrity": "sha512-3EVi3ETTyJg5PSXlxLCaUVVn0pSbDf62L3Gwxne7Uq+d8adOSNWQAad4gg7WToHkcgnCJb3Wlb1P8r4Evj4GPw==", "dev": true }, + "get-intrinsic": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.0.tgz", + "integrity": "sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -1139,17 +1165,16 @@ "dev": true }, "hap-nodejs": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.7.7.tgz", - "integrity": "sha512-fWpWVJRe4kWz0/fNiDUKdTghuzKjqfmJ+cHoDqoSwwXHlCXLgdOXNEqoRx7pU8/nSlvte5ui2Q5lxSafTnB8tw==", + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.7.10.tgz", + "integrity": "sha512-582WHUCRVKFtw1ITYvKsGrGw2Hhc/AINej0LuFhCYvzPqVf2/m+v5PdgEt4wqyJSTM9rG5uoVYp1t/hoDnlLsw==", "dev": true, "requires": { - "bonjour-hap": "~3.5.10", + "bonjour-hap": "~3.6.2", "debug": "^4.1.1", "decimal.js": "^10.2.0", "fast-srp-hap": "2.0.2", "futoin-hkdf": "~1.3.2", - "ip": "^1.1.3", "node-persist": "^0.0.11", "tweetnacl": "^1.0.3" } @@ -1182,14 +1207,14 @@ "dev": true }, "homebridge": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.1.1.tgz", - "integrity": "sha512-eOmHjRSkmkCD3iUqQKAo1fcSFs8gZCAW4LVjBYpxH6mEgKQlYxh9tUtgEIzny6bkplYmOOahQPHSjzfNTDjr6w==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.1.7.tgz", + "integrity": "sha512-A+cf5ZBatZu34wEVc1S5ztNtNjIbA31jwOMSZ6so8TeAQfcIYJRDHueHD7FgslMxkHol27nXt9vVMrugH4LtLA==", "dev": true, "requires": { "chalk": "^4.1.0", "commander": "5.1.0", - "hap-nodejs": "^0.7.4", + "hap-nodejs": "^0.7.10", "node-persist": "^0.0.11", "qrcode-terminal": "^0.12.0", "semver": "^7.3.2", @@ -1197,10 +1222,13 @@ }, "dependencies": { "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } } } }, @@ -1273,15 +1301,18 @@ "dev": true }, "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } }, "is-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.0.tgz", - "integrity": "sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", "dev": true }, "is-binary-path": { @@ -1294,15 +1325,18 @@ } }, "is-boolean-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.1.tgz", - "integrity": "sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } }, "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", "dev": true }, "is-ci": { @@ -1352,9 +1386,15 @@ } }, "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true + }, + "is-negative-zero": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", - "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", "dev": true }, "is-npm": { @@ -1388,18 +1428,18 @@ "dev": true }, "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", "dev": true, "requires": { "has-symbols": "^1.0.1" } }, "is-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", - "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", "dev": true }, "is-string": { @@ -1418,13 +1458,14 @@ } }, "is-typed-array": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.3.tgz", - "integrity": "sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.4.tgz", + "integrity": "sha512-ILaRgn4zaSrVNXNGtON6iFNotXW3hAPF3+0fB1usg2jFlWqo5fEDdmJkz0zBfoi7Dgskr8Khi2xZ8cXqZEfXNA==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.0", - "es-abstract": "^1.17.4", + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", "foreach": "^2.0.5", "has-symbols": "^1.0.1" } @@ -1543,6 +1584,15 @@ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -1683,19 +1733,19 @@ "dev": true }, "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", "dev": true }, "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", - "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", + "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" } }, "object-keys": { @@ -1705,15 +1755,15 @@ "dev": true }, "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" } }, "once": { @@ -1880,13 +1930,13 @@ } }, "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "regexpp": { @@ -1974,13 +2024,14 @@ "dev": true }, "side-channel": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", - "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, "requires": { - "es-abstract": "^1.17.0-next.1", - "object-inspect": "^1.7.0" + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" } }, "signal-exit": { @@ -2053,23 +2104,23 @@ } }, "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" } }, "strip-ansi": { @@ -2389,16 +2440,16 @@ } }, "which-boxed-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz", - "integrity": "sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, "requires": { - "is-bigint": "^1.0.0", - "is-boolean-object": "^1.0.0", - "is-number-object": "^1.0.3", - "is-string": "^1.0.4", - "is-symbol": "^1.0.2" + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" } }, "which-collection": { @@ -2414,13 +2465,14 @@ } }, "which-typed-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.2.tgz", - "integrity": "sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz", + "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==", "dev": true, "requires": { "available-typed-arrays": "^1.0.2", - "es-abstract": "^1.17.5", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", "foreach": "^2.0.5", "function-bind": "^1.1.1", "has-symbols": "^1.0.1", @@ -2475,6 +2527,12 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 28a7e14..877694a 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@typescript-eslint/eslint-plugin": "^3.8.0", "@typescript-eslint/parser": "^3.8.0", "eslint": "^7.6.0", - "homebridge": "^1.1.1", + "homebridge": "^1.1.7", "nodemon": "^2.0.4", "rimraf": "^3.0.2", "ts-node": "^8.10.2", diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 4f25725..d40b212 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -101,6 +101,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // see https://developers.homebridge.io/#/service/Lightbulb // register handlers for the Brightness Characteristic + this.service.getCharacteristic(this.platform.Characteristic.Brightness) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) @@ -110,6 +111,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if( this.myDevice.lightParameters.hasColor){ // register handlers for the Hue Characteristic + this.logs.trace('Adding Hue characteristic to device.'); this.service.getCharacteristic(this.platform.Characteristic.Hue) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) @@ -117,6 +119,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { .on(CharacteristicEventTypes.GET, this.getHue.bind(this)); // GET - bind to the 'getHue` method below // register handlers for the Saturation Characteristic + this.logs.trace('Adding Saturation characteristic to device.'); this.service.getCharacteristic(this.platform.Characteristic.Saturation) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) @@ -128,15 +131,16 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if(this.myDevice.lightParameters.hasCCT){ // register handlers for the Saturation Characteristic + this.logs.trace('Adding ColorTemperature characteristic to device.'); this.service.getCharacteristic(this.platform.Characteristic.ColorTemperature) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) .on(CharacteristicEventTypes.SET, this.setColorTemperature.bind(this)) // SET - bind to the 'setSaturation` method below .on(CharacteristicEventTypes.GET, this.getColorTemperature.bind(this)); // GET - bind to the 'getSaturation` method below - // register handlers for the On/Off Characteristic } } else { - + //device is switch, register it as such + this.logs.trace('Adding Switch service to device.'); this.service = this.accessory.getService(this.platform.Service.Switch) ?? this.accessory.addService(this.platform.Service.Switch); this.service.getCharacteristic(this.platform.Characteristic.ConfiguredName) .removeAllListeners(CharacteristicEventTypes.SET) @@ -145,12 +149,13 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } // register handlers for the On/Off Characteristic + this.logs.trace('Adding On characteristic to device.'); this.service.getCharacteristic(this.platform.Characteristic.On) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) .on(CharacteristicEventTypes.SET, this.setOn.bind(this)) // SET - bind to the `setOn` method below .on(CharacteristicEventTypes.GET, this.getOn.bind(this)); // GET - bind to the `getOn` method below - //this.service2.updateCharacteristic(this.platform.Characteristic.On, false); + this.updateLocalState(); // set the service name, this is what is displayed as the default name on the Home app // in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method. @@ -182,6 +187,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setHue(value: CharacteristicValue, callback: CharacteristicSetCallback) { + this.logs.debug('Setting accessory %o\'s Hue value: %o', this.myDevice.displayName, value); this.setColortemp = false; this.lightState.HSL.hue = value as number; this.colorCommand = true; @@ -190,6 +196,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setSaturation(value: CharacteristicValue, callback: CharacteristicSetCallback) { + this.logs.debug('Setting accessory %o\'s Saturation value: %o', this.myDevice.displayName, value); this.setColortemp = false; this.lightState.HSL.saturation = value as number; this.colorCommand = true; @@ -198,6 +205,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setBrightness(value: CharacteristicValue, callback: CharacteristicSetCallback) { + this.logs.debug('Setting accessory %o\'s Brightness value: %o', this.myDevice.displayName, value); this.lightState.brightness = value as number; this.colorCommand = true; this.processRequest(); @@ -205,6 +213,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setColorTemperature(value: CharacteristicValue, callback: CharacteristicSetCallback) { + this.logs.debug('Setting accessory %o\'s Color Temperature value: %o', this.myDevice.displayName, value); this.setColortemp = true; this.lightState.CCT = value as number; this.colorCommand = true; @@ -220,7 +229,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { }*/ setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) { - + this.logs.debug('Setting accessory %o\'s On value: %o', this.myDevice.displayName, value); this.lightState.isOn = value as boolean; this.processRequest(); callback(null); @@ -233,41 +242,28 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start Getters // getHue(callback: CharacteristicGetCallback) { - - const hue = this.lightState.HSL.hue; - - //update state with actual values asynchronously - this.logs.debug('Get Characteristic Hue -> %o for device: %o ', hue, this.myDevice.displayName); - if(!this.setColortemp){ - this.updateLocalState(); + const hue = this.lightState.HSL.hue; + if(!this.setColortemp){ //if we are not in Color Temperature mode, allow HB to update HK with Hue values + this.logs.debug('Returning accessory %o\'s cached Hue value: %o', this.myDevice.displayName, hue); + this.updateLocalState(); //update state with actual values asynchronously } callback(null, hue); } getColorTemperature(callback: CharacteristicGetCallback) { - const CCT = this.lightState.CCT; - - //update state with actual values asynchronously - this.logs.debug('Get Characteristic Hue -> %o for device: %o ', CCT, this.myDevice.displayName); - if(this.setColortemp){ - this.updateLocalState(); + if(this.setColortemp){ //if we are in Color Temperature mode, allow HB to update HK with CCT values + this.logs.debug('Returning accessory %o\'s cached Color Temperature value: %o', this.myDevice.displayName, CCT); + this.updateLocalState(); //update state with actual values asynchronously } - callback(null, CCT); + callback(null, CCT); //immediately return cached state to prevent laggy HomeKit UI } getBrightness(callback: CharacteristicGetCallback) { - - // implement your own code to check if the device is on const brightness = this.lightState.brightness; - - // dont update the actual values from brightness, it is impossible to determine by rgb values alone - //this.getState(); - - this.logs.debug('Get Characteristic Brightness -> %o for device: %o ', brightness, this.myDevice.displayName); - this.updateLocalState(); - - callback(null, brightness); + this.logs.debug('Returning accessory %o\'s cached Brightness value: %o', this.myDevice.displayName, brightness); + this.updateLocalState(); //update state with actual values asynchronously + callback(null, brightness); //immediately return cached state to prevent laggy HomeKit UI } /** @@ -278,12 +274,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getOn(callback: CharacteristicGetCallback) { const isOn = this.lightState.isOn; - - //update state with actual values asynchronously - this.updateLocalState(); - - this.logs.debug('Get Characteristic On -> %o for device: %o ', isOn, this.myDevice.displayName); - callback(null, isOn); + this.logs.debug('Returning accessory %o\'s cached Power value: %o', this.myDevice.displayName, isOn); + this.updateLocalState(); //update state with actual values asynchronously + callback(null, isOn); //immediately return cached state to prevent laggy HomeKit UI } //================================================= @@ -292,7 +285,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // Start State Get/Set // - /** ** @updateLocalState * retrieve light's state object from transport class @@ -301,14 +293,17 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { async updateLocalState() { if( this.deviceWriteInProgress || this.deviceUpdateInProgress || this.deviceReadInProgress){ + this.logs.trace('Accessory %o already has write/update/read in progress. Skipping updateLocalState.', this.myDevice.displayName); return; } + this.deviceReadInProgress = true; try { let state; let scans = 0; while(state == null && scans <= 5){ + this.logs.debug('Retrieving accessory %o\'s current state...', this.myDevice.displayName); state = await this.transport.getState(1000); //retrieve a state object from transport class showing light's current r,g,b,ww,cw, etc scans++; } @@ -393,8 +388,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); await this.send([0x31, r, g, b, 0x00, mask, 0x0F], true, _timeout); //8th byte checksum calculated later in send() - - }//updateDeviceState @@ -413,29 +406,30 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { * the closer to 90/270 the stronger both warmWhite and coldWhite become simultaniously */ hueToWhiteTemperature() { - const hsl = this.lightState.HSL; + const hue = this.lightState.HSL.hue; let multiplier = 0; const whiteTemperature = { warmWhite: 0, coldWhite: 0 }; - - if (hsl.hue <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue + if (hue <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue whiteTemperature.warmWhite = 255; - multiplier = ((hsl.hue / 90)); + multiplier = ((hue / 90)); whiteTemperature.coldWhite = Math.round((255 * multiplier)); - } else if (hsl.hue > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue + } else if (hue > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue whiteTemperature.warmWhite = 255; - multiplier = (1 - (hsl.hue - 270) / 90); + multiplier = (1 - (hue - 270) / 90); whiteTemperature.coldWhite = Math.round((255 * multiplier)); - } else if (hsl.hue > 180 && hsl.hue <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue + } else if (hue > 180 && hue <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue whiteTemperature.coldWhite = 255; - multiplier = ((hsl.hue - 180) / 90); + multiplier = ((hue - 180) / 90); whiteTemperature.warmWhite = Math.round((255 * multiplier)); - } else if (hsl.hue > 90 && hsl.hue <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue + } else if (hue > 90 && hue <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue whiteTemperature.coldWhite = 255; - multiplier = (1 - (hsl.hue - 90) / 90); + multiplier = (1 - (hue - 90) / 90); whiteTemperature.warmWhite = Math.round((255 * multiplier)); } this.lightState.whiteValues = whiteTemperature; + this.logs.trace('Calculated accessory %o\'s white values: %o from hue: %o', this.myDevice.displayName, whiteTemperature, hue); + return whiteTemperature; } //hueToWhiteTemperature @@ -455,6 +449,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { whiteTemperature.warmWhite = Math.round((127 * multiplier)); } this.lightState.whiteValues = whiteTemperature; + this.logs.trace('Calculated accessory %o\'s white values: %o from CCT: %o', this.myDevice.displayName, whiteTemperature, CCT); + + return whiteTemperature; } @@ -462,19 +459,21 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { async send(command: number[], useChecksum = true, _timeout = 200) { + this.logs.trace('Sending the following command to accessory %o: %o', this.myDevice.displayName, command); const buffer = Buffer.from(command); - const output = await this.transport.send(buffer, useChecksum, _timeout); - //this.logs.debug('Recieved the following response', output); + this.logs.trace('Received the following resonse from accessory %o: %o', this.myDevice.displayName, output); } //send cacheCurrentLightState(){ - this.lightStateTemporary.HSL = this.lightState.HSL; + this.logs.trace('Caching accessory %o\'s current state', this.myDevice.displayName); + this.lightStateTemporary = this.lightState; } async restoreCachedLightState(){ - this.lightState.HSL = this.lightStateTemporary.HSL; + this.logs.trace('Restoring accessory %o\'s cached state', this.myDevice.displayName); + this.lightState = this.lightStateTemporary; this.updateDeviceState(); } //================================================= From 7285232d8d42431069f82aed867caabc1ce8671d Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sun, 26 Sep 2021 12:18:55 -0400 Subject: [PATCH 02/42] minor changes, still many bugs --- nodemon.json | 2 +- package-lock.json | 1337 ++++++++++++++++++++++++--------------------- package.json | 22 +- src/platform.ts | 21 +- 4 files changed, 732 insertions(+), 650 deletions(-) diff --git a/nodemon.json b/nodemon.json index e62280a..9e864a0 100644 --- a/nodemon.json +++ b/nodemon.json @@ -5,4 +5,4 @@ "ext": "ts", "ignore": [], "exec": "tsc && homebridge -I -D -U C:/Users/zacka/.homebridge-two" -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 27d1783..5c54fd8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,27 +5,27 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { "@babel/highlight": "^7.10.4" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true }, "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -40,9 +40,75 @@ "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true } } }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@homebridge/ciao": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.2.tgz", + "integrity": "sha512-31IfDKMqxfT+uVNXj0/TmYMou57gP8CUrh0vABzsc5QMsoCQ4Oo5uYQp0oJJyzxTBkF2pFvjR3XlWAapl0VyCg==", + "dev": true, + "requires": { + "debug": "^4.3.1", + "fast-deep-equal": "^3.1.3", + "source-map-support": "^0.5.19", + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", + "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==", + "dev": true + }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -58,12 +124,6 @@ "defer-to-connect": "^1.0.1" } }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -71,15 +131,15 @@ "dev": true }, "@types/json-schema": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz", - "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, "@types/node": { - "version": "14.14.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", - "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==", + "version": "14.17.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.19.tgz", + "integrity": "sha512-jjYI6NkyfXykucU6ELEoT64QyKOdvaA6enOqKtP4xUsGY0X0ZUZz29fUmrTRo+7v7c6TgDu82q3GHHaCEkqZwA==", "dev": true }, "@types/promise-queue": { @@ -89,87 +149,71 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.8.0.tgz", - "integrity": "sha512-lFb4VCDleFSR+eo4Ew+HvrJ37ZH1Y9ZyE+qyP7EiwBpcCVxwmUc5PAqhShCQ8N8U5vqYydm74nss+a0wrrCErw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.10.1.tgz", + "integrity": "sha512-PQg0emRtzZFWq6PxBcdxRH3QIQiyFO3WCVpRL3fgj5oQS3CDs3AeAKfv4DxNhzn8ITdNJGJ4D3Qw8eAJf3lXeQ==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "3.8.0", + "@typescript-eslint/experimental-utils": "3.10.1", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", "semver": "^7.3.2", "tsutils": "^3.17.1" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - } } }, "@typescript-eslint/experimental-utils": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.8.0.tgz", - "integrity": "sha512-o8T1blo1lAJE0QDsW7nSyvZHbiDzQDjINJKyB44Z3sSL39qBy5L10ScI/XwDtaiunoyKGLiY9bzRk4YjsUZl8w==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz", + "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/types": "3.8.0", - "@typescript-eslint/typescript-estree": "3.8.0", + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/typescript-estree": "3.10.1", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.8.0.tgz", - "integrity": "sha512-u5vjOBaCsnMVQOvkKCXAmmOhyyMmFFf5dbkM3TIbg3MZ2pyv5peE4gj81UAbTHwTOXEwf7eCQTUMKrDl/+qGnA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.10.1.tgz", + "integrity": "sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "3.8.0", - "@typescript-eslint/types": "3.8.0", - "@typescript-eslint/typescript-estree": "3.8.0", + "@typescript-eslint/experimental-utils": "3.10.1", + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/typescript-estree": "3.10.1", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/types": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.8.0.tgz", - "integrity": "sha512-8kROmEQkv6ss9kdQ44vCN1dTrgu4Qxrd2kXr10kz2NP5T8/7JnEfYNxCpPkArbLIhhkGLZV3aVMplH1RXQRF7Q==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz", + "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.8.0.tgz", - "integrity": "sha512-MTv9nPDhlKfclwnplRNDL44mP2SY96YmPGxmMbMy6x12I+pERcxpIUht7DXZaj4mOKKtet53wYYXU0ABaiXrLw==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz", + "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==", "dev": true, "requires": { - "@typescript-eslint/types": "3.8.0", - "@typescript-eslint/visitor-keys": "3.8.0", + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/visitor-keys": "3.10.1", "debug": "^4.1.1", "glob": "^7.1.6", "is-glob": "^4.0.1", "lodash": "^4.17.15", "semver": "^7.3.2", "tsutils": "^3.17.1" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - } } }, "@typescript-eslint/visitor-keys": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.8.0.tgz", - "integrity": "sha512-gfqQWyVPpT9NpLREXNR820AYwgz+Kr1GuF3nf1wxpHD6hdxI62tq03ToomFnDxY0m3pUB39IF7sil7D5TQexLA==", + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz", + "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==", "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" @@ -182,21 +226,21 @@ "dev": true }, "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, "ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -214,6 +258,12 @@ "string-width": "^3.0.0" }, "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -236,6 +286,15 @@ "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } } } }, @@ -246,9 +305,9 @@ "dev": true }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { @@ -278,9 +337,9 @@ } }, "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -302,12 +361,6 @@ "sprintf-js": "~1.0.2" } }, - "array-filter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", - "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", - "dev": true - }, "array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", @@ -315,19 +368,22 @@ "dev": true }, "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "at-least-node": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true }, "available-typed-arrays": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", - "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", - "dev": true, - "requires": { - "array-filter": "^1.0.0" - } + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true }, "balanced-match": { "version": "1.0.0", @@ -336,90 +392,38 @@ "dev": true }, "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, "bonjour-hap": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.2.tgz", - "integrity": "sha512-uwMGUJ2Yql/sqvxAqR4nkE4qypo5JJk7EtGMkB/ikHMHa7/0djDjB8Ct0ES+8OK8SKZzthrLngDo+e2VjcfdXw==", + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.3.tgz", + "integrity": "sha512-qyLU96ICCYbpOFiMCjA3aNYH5Jc83XH1YX6+EXWukyyiNXzXH2LZv8AVmGW33FceF3gfUM4jYoKX2xChtNDUnA==", "dev": true, "requires": { "array-flatten": "^2.1.2", "deep-equal": "^2.0.5", "ip": "^1.1.5", - "multicast-dns": "^7.2.2", + "multicast-dns": "^7.2.3", "multicast-dns-service-types": "^1.1.0" } }, "boxen": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", - "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", "dev": true, "requires": { "ansi-align": "^3.0.0", - "camelcase": "^5.3.1", - "chalk": "^3.0.0", - "cli-boxes": "^2.2.0", - "string-width": "^4.1.0", - "term-size": "^2.1.0", - "type-fest": "^0.8.1", - "widest-line": "^3.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" } }, "brace-expansion": { @@ -463,9 +467,9 @@ }, "dependencies": { "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "requires": { "pump": "^3.0.0" @@ -496,15 +500,15 @@ "dev": true }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -512,12 +516,11 @@ }, "dependencies": { "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, @@ -528,9 +531,9 @@ "dev": true }, "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -539,19 +542,19 @@ } }, "chokidar": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz", - "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", "dev": true, "requires": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.1.2", - "glob-parent": "~5.1.0", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.4.0" + "readdirp": "~3.6.0" } }, "ci-info": { @@ -561,9 +564,9 @@ "dev": true }, "cli-boxes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", - "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", "dev": true }, "clone-response": { @@ -632,20 +635,14 @@ "dev": true }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, - "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", - "dev": true - }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -685,9 +682,9 @@ "dev": true }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "defer-to-connect": { @@ -712,13 +709,12 @@ "dev": true }, "dns-packet": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-4.2.0.tgz", - "integrity": "sha512-bn1AKpfkFbm0MIioOMHZ5qJzl2uypdBwI4nYNsqvhjsegBhcKJUlCrMPWLx6JEezRjxZmxhtIz/FkBEur2l8Cw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.0.tgz", + "integrity": "sha512-Nce7YLu6YCgWRvOmDBsJMo9M5/jV3lEZ5vUWnWXYmwURvPylHvq7nkDWhNmk1ZQoZZOP7oQh/S0lSxbisKOfHg==", "dev": true, "requires": { - "ip": "^1.1.5", - "safe-buffer": "^5.1.1" + "@leichtgewicht/ip-codec": "^2.0.1" } }, "doctrine": { @@ -731,9 +727,9 @@ } }, "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", - "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, "requires": { "is-obj": "^2.0.0" @@ -770,25 +766,29 @@ } }, "es-abstract": { - "version": "1.18.0-next.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz", - "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==", + "version": "1.18.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", + "integrity": "sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.1", - "object-inspect": "^1.9.0", + "is-regex": "^1.1.4", + "is-string": "^1.0.7", + "object-inspect": "^1.11.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.3", - "string.prototype.trimstart": "^1.0.3" + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" } }, "es-get-iterator": { @@ -825,34 +825,38 @@ "dev": true }, "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "eslint": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.6.0.tgz", - "integrity": "sha512-QlAManNtqr7sozWm5TF4wIH9gmUm2hE3vNRUvyoYAa4y1l5/jxD/PQStEjBMQtCqZmSep8UxrcecI60hOpe61w==", + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^1.3.0", - "espree": "^7.2.0", - "esquery": "^1.2.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -860,7 +864,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -869,35 +873,26 @@ "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^5.2.3", + "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } } } }, "eslint-scope": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz", - "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "esrecurse": "^4.1.0", + "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, @@ -917,13 +912,13 @@ "dev": true }, "espree": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.2.0.tgz", - "integrity": "sha512-H+cQ3+3JYRMEIOl87e7QdHX70ocly5iW4+dttuR8iYSPr/hXKFb+7dBsZ7+u1adC4VrnPlTkv0+OwuPnDop19g==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { - "acorn": "^7.3.1", - "acorn-jsx": "^5.2.0", + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", "eslint-visitor-keys": "^1.3.0" } }, @@ -934,29 +929,37 @@ "dev": true }, "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" }, "dependencies": { "estraverse": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", - "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true } } }, "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "estraverse": "^4.1.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } } }, "estraverse": { @@ -990,18 +993,18 @@ "dev": true }, "fast-srp-hap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.2.tgz", - "integrity": "sha512-wABhZRrFhlovqJQ1HygOUB4R6WZW2hmlpvVYh2dVCy8BPLabDrB/Tu6XI3B4QfmhtHk8s1OeiFqJHY7FBsphug==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.3.tgz", + "integrity": "sha512-4P8TBD0all202L9FbeSsWc9qDlpaYp065VbUwbuNYZDYdOJ02UlWaDkai6d/+6/I8/sdtVYAVd17PEZDKbqopQ==", "dev": true }, "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { - "flat-cache": "^2.0.1" + "flat-cache": "^3.0.4" } }, "fill-range": { @@ -1014,31 +1017,19 @@ } }, "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "dependencies": { - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, "foreach": { @@ -1047,6 +1038,18 @@ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", "dev": true }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1054,9 +1057,9 @@ "dev": true }, "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "optional": true }, @@ -1073,15 +1076,15 @@ "dev": true }, "futoin-hkdf": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.3.2.tgz", - "integrity": "sha512-3EVi3ETTyJg5PSXlxLCaUVVn0pSbDf62L3Gwxne7Uq+d8adOSNWQAad4gg7WToHkcgnCJb3Wlb1P8r4Evj4GPw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.3.3.tgz", + "integrity": "sha512-oR75fYk3B3X9/B02Y6vusrBKucrpC6VjxhRL+C6B7FwUpuSRHbhBNG3AZbcE/xPyJmEQWsyqUFp3VeNNbA3S7A==", "dev": true }, "get-intrinsic": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.0.tgz", - "integrity": "sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -1098,6 +1101,16 @@ "pump": "^3.0.0" } }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -1113,30 +1126,30 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" } }, "global-dirs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", - "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", "dev": true, "requires": { - "ini": "^1.3.5" + "ini": "2.0.0" } }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "got": { @@ -1159,24 +1172,35 @@ } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, "hap-nodejs": { - "version": "0.7.10", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.7.10.tgz", - "integrity": "sha512-582WHUCRVKFtw1ITYvKsGrGw2Hhc/AINej0LuFhCYvzPqVf2/m+v5PdgEt4wqyJSTM9rG5uoVYp1t/hoDnlLsw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.9.4.tgz", + "integrity": "sha512-wGYq6nQ8c5+V7iLr9Fa7XpOGAntmB0ejfOsjoIhXe/WHOXX9gGDwYgQTHg+dwmJZjW7RBoOyRRdB7/oa/NYovw==", "dev": true, "requires": { + "@homebridge/ciao": "~1.1.2", "bonjour-hap": "~3.6.2", - "debug": "^4.1.1", - "decimal.js": "^10.2.0", - "fast-srp-hap": "2.0.2", + "debug": "^4.3.1", + "fast-srp-hap": "2.0.3", "futoin-hkdf": "~1.3.2", + "ip": "^1.1.3", "node-persist": "^0.0.11", + "source-map-support": "^0.5.19", + "tslib": "^2.1.0", "tweetnacl": "^1.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + } } }, "has": { @@ -1188,6 +1212,12 @@ "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -1195,11 +1225,20 @@ "dev": true }, "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "has-yarn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", @@ -1207,29 +1246,18 @@ "dev": true }, "homebridge": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.1.7.tgz", - "integrity": "sha512-A+cf5ZBatZu34wEVc1S5ztNtNjIbA31jwOMSZ6so8TeAQfcIYJRDHueHD7FgslMxkHol27nXt9vVMrugH4LtLA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.3.4.tgz", + "integrity": "sha512-I2vxabWpKHly3htXvOgnJbO79pXzrorz6/htRUCD3UTWXnzURqUFhevv9c/Mji3YeKxluIXCyXyiGAuDfx1m3A==", "dev": true, "requires": { "chalk": "^4.1.0", "commander": "5.1.0", - "hap-nodejs": "^0.7.10", - "node-persist": "^0.0.11", + "fs-extra": "^9.1.0", + "hap-nodejs": "0.9.4", "qrcode-terminal": "^0.12.0", - "semver": "^7.3.2", + "semver": "^7.3.4", "source-map-support": "^0.5.19" - }, - "dependencies": { - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } } }, "http-cache-semantics": { @@ -1251,9 +1279,9 @@ "dev": true }, "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -1289,11 +1317,22 @@ "dev": true }, "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -1301,19 +1340,23 @@ "dev": true }, "is-arguments": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", - "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dev": true, "requires": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, "is-bigint": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", - "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", - "dev": true + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } }, "is-binary-path": { "version": "2.1.0", @@ -1325,18 +1368,19 @@ } }, "is-boolean-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", - "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, "requires": { - "call-bind": "^1.0.0" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", "dev": true }, "is-ci": { @@ -1349,10 +1393,13 @@ } }, "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-extglob": { "version": "2.1.1", @@ -1376,13 +1423,13 @@ } }, "is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, "requires": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" } }, "is-map": { @@ -1398,9 +1445,9 @@ "dev": true }, "is-npm": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", - "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", "dev": true }, "is-number": { @@ -1410,10 +1457,13 @@ "dev": true }, "is-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", - "dev": true + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-obj": { "version": "2.0.0", @@ -1422,18 +1472,19 @@ "dev": true }, "is-path-inside": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", - "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" } }, "is-set": { @@ -1443,31 +1494,34 @@ "dev": true }, "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } }, "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.2" } }, "is-typed-array": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.4.tgz", - "integrity": "sha512-ILaRgn4zaSrVNXNGtON6iFNotXW3hAPF3+0fB1usg2jFlWqo5fEDdmJkz0zBfoi7Dgskr8Khi2xZ8cXqZEfXNA==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", + "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.2", - "call-bind": "^1.0.0", - "es-abstract": "^1.18.0-next.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", "foreach": "^2.0.5", - "has-symbols": "^1.0.1" + "has-tostringtag": "^1.0.0" } }, "is-typedarray": { @@ -1513,9 +1567,9 @@ "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -1540,6 +1594,16 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -1569,15 +1633,33 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -1600,6 +1682,14 @@ "dev": true, "requires": { "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "make-error": { @@ -1645,12 +1735,12 @@ "dev": true }, "multicast-dns": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.2.tgz", - "integrity": "sha512-XqSMeO8EWV/nOXOpPV8ztIpNweVfE1dSpz6SQvDPp71HD74lMXjt4m/mWB1YBMG0kHtOodxRWc5WOb/UNN1A5g==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.3.tgz", + "integrity": "sha512-TzxgGSLRLB7tqAlzjgd2x2ZE0cDsGFq4rs9W4yE5xp+7hlRXeUQGtXZsTGfGw2FwWB45rfe8DtXMYBpZGMLUng==", "dev": true, "requires": { - "dns-packet": "^4.0.0", + "dns-packet": "^5.2.2", "thunky": "^1.0.2" } }, @@ -1677,9 +1767,9 @@ } }, "nodemon": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", - "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.13.tgz", + "integrity": "sha512-UMXMpsZsv1UXUttCn6gv8eQPhn6DR4BW+txnL3IN5IHqrCwcrT/yWHfL35UsClGXknTH79r5xbu+6J1zNHuSyA==", "dev": true, "requires": { "chokidar": "^3.2.2", @@ -1690,14 +1780,14 @@ "semver": "^5.7.1", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^4.0.0" + "undefsafe": "^2.0.3", + "update-notifier": "^5.1.0" }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -1727,24 +1817,24 @@ "dev": true }, "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", "dev": true }, "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", "dev": true }, "object-is": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", - "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, @@ -1805,6 +1895,14 @@ "registry-auth-token": "^4.0.0", "registry-url": "^5.0.0", "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "parent-module": { @@ -1829,9 +1927,9 @@ "dev": true }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "prelude-ls": { @@ -1880,9 +1978,9 @@ "dev": true }, "pupa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", - "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", "dev": true, "requires": { "escape-goat": "^2.0.0" @@ -1912,6 +2010,12 @@ "strip-json-comments": "~2.0.1" }, "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -1921,9 +2025,9 @@ } }, "readdirp": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", - "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "requires": { "picomatch": "^2.2.1" @@ -1940,15 +2044,15 @@ } }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "registry-auth-token": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz", - "integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", "dev": true, "requires": { "rc": "^1.2.8" @@ -1963,6 +2067,12 @@ "rc": "^1.2.8" } }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1987,17 +2097,14 @@ "glob": "^7.1.3" } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "semver-diff": { "version": "3.1.1", @@ -2006,6 +2113,14 @@ "dev": true, "requires": { "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "shebang-command": { @@ -2035,27 +2150,30 @@ } }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", + "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", "dev": true }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } } } }, @@ -2082,62 +2200,43 @@ "dev": true }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } + "strip-ansi": "^6.0.1" } }, "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } + "ansi-regex": "^5.0.1" } }, "strip-json-comments": { @@ -2156,48 +2255,39 @@ } }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" }, "dependencies": { - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true } } }, - "term-size": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", - "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", - "dev": true - }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -2248,15 +2338,15 @@ } }, "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "requires": { "tslib": "^1.8.1" @@ -2278,9 +2368,9 @@ } }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, "typedarray-to-buffer": { @@ -2293,11 +2383,23 @@ } }, "typescript": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", - "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", "dev": true }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "undefsafe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", @@ -2333,83 +2435,38 @@ "crypto-random-string": "^2.0.0" } }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, "update-notifier": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz", - "integrity": "sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", "dev": true, "requires": { - "boxen": "^4.2.0", - "chalk": "^3.0.0", + "boxen": "^5.0.0", + "chalk": "^4.1.0", "configstore": "^5.0.1", "has-yarn": "^2.1.0", "import-lazy": "^2.1.0", "is-ci": "^2.0.0", - "is-installed-globally": "^0.3.1", - "is-npm": "^4.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", "is-yarn-global": "^0.3.0", - "latest-version": "^5.0.0", - "pupa": "^2.0.1", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", "semver-diff": "^3.1.1", "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -2425,9 +2482,9 @@ } }, "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "which": { @@ -2465,18 +2522,17 @@ } }, "which-typed-array": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz", - "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", + "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", "dev": true, "requires": { - "available-typed-arrays": "^1.0.2", - "call-bind": "^1.0.0", - "es-abstract": "^1.18.0-next.1", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", "foreach": "^2.0.5", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.1", - "is-typed-array": "^1.1.3" + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.7" } }, "widest-line": { @@ -2494,21 +2550,34 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", diff --git a/package.json b/package.json index 877694a..fc32180 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,10 @@ "version": "1.9.3-beta.4", "description": "Dynamically Discover and Add MagicHome Bulbs and Controllers to Homebrige.", "license": "Apache-2.0", + "files": [ + "LICENSE", + "dist" + ], "repository": { "type": "git", "url": "https://github.com/Zacknetic/HomebridgeMagicHome-DynamicPlatform" @@ -28,7 +32,7 @@ ], "engines": { "node": ">=10.17.0", - "homebridge": ">0.4.53" + "homebridge": ">=1.0.0" }, "main": "dist/index.js", "scripts": { @@ -58,20 +62,20 @@ ], "dependencies": { "color-convert": "^2.0.1", - "lodash": "^4.17.20", + "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", "promise-queue": "^2.2.5" }, "devDependencies": { - "@types/node": "^14.0.23", + "@types/node": "^14.17.19", "@types/promise-queue": "^2.2.0", - "@typescript-eslint/eslint-plugin": "^3.8.0", - "@typescript-eslint/parser": "^3.8.0", - "eslint": "^7.6.0", - "homebridge": "^1.1.7", - "nodemon": "^2.0.4", + "@typescript-eslint/eslint-plugin": "^3.10.1", + "@typescript-eslint/parser": "^3.10.1", + "eslint": "^7.32.0", + "homebridge": "^1.3.4", + "nodemon": "^2.0.13", "rimraf": "^3.0.2", "ts-node": "^8.10.2", - "typescript": "^3.9.7" + "typescript": "^3.9.10" } } diff --git a/src/platform.ts b/src/platform.ts index 3321d30..b6430fa 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -1,5 +1,3 @@ -import { APIEvent } from 'homebridge'; -import type { API, DynamicPlatformPlugin, Logger, PlatformAccessory, PlatformConfig } from 'homebridge'; import { PLATFORM_NAME, PLUGIN_NAME } from './settings'; import { join } from 'path'; import { loadJson } from './magichome-interface/utils'; @@ -14,11 +12,21 @@ import { RGBWWStrip } from './accessories/RGBWWStrip'; import { CCTStrip } from './accessories/CCTStrip'; import { cloneDeep } from 'lodash'; import { Logs } from './logs'; -import { Discover } from './magichome-interface/Discover'; -import { Transport } from './magichome-interface/Transport'; +import { + API, + APIEvent, + CharacteristicEventTypes, + CharacteristicSetCallback, + CharacteristicValue, + DynamicPlatformPlugin, + HAP, + Logging, + PlatformAccessory, + PlatformAccessoryEvent, + PlatformConfig, +} from 'homebridge'; + import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -import { IDeviceProps, IDeviceDiscoveredProps, IDeviceQueriedProps, ILightParameters } from './magichome-interface/types'; -import { getPrettyName as getUniqueIdName, lightTypesMap} from './magichome-interface/LightMap'; import { MagicHomeAccessory, ControllerTypes } from './magichome-interface/types'; //const NEW_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0x81, 0x8a, 0x8b]); //const LEGACY_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0xEF, 0x01, 0x77]); @@ -93,6 +101,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin accessory.context.pendingRegistration = true; // add the restored accessory to the accessories cache so we can track if it has already been registered this.accessories.push(accessory); + } /** From 7bc99ea857da68cd03acc968430790daa572c0b7 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Wed, 29 Sep 2021 20:53:46 -0400 Subject: [PATCH 03/42] logic cleanup --- .eslintrc | 2 +- package-lock.json | 99 +++++ package.json | 1 + src/AccessoryGenerator.ts | 150 ++++++++ src/logs.ts | 25 +- src/magichome-interface/types.ts | 108 ++---- src/platform.ts | 599 +++++++++++++++---------------- 7 files changed, 595 insertions(+), 389 deletions(-) create mode 100644 src/AccessoryGenerator.ts diff --git a/.eslintrc b/.eslintrc index fa36b77..aa29d6a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,7 +14,7 @@ ], "rules": { "quotes": ["warn", "single"], - "indent": ["warn", 2, { "SwitchCase": 1 }], + //"indent": ["warn", 2, { "SwitchCase": 1 }], "linebreak-style": ["error", "unix"], "semi": ["warn", "always"], "comma-dangle": ["warn", "always-multiline"], diff --git a/package-lock.json b/package-lock.json index 5c54fd8..0e127ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -702,6 +702,11 @@ "object-keys": "^1.0.12" } }, + "dgram": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dgram/-/dgram-1.0.1.tgz", + "integrity": "sha1-N/OyAPgDOl/3WTAwicgc42G2UcM=" + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -765,6 +770,11 @@ "ansi-colors": "^4.1.1" } }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, "es-abstract": { "version": "1.18.6", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", @@ -1613,6 +1623,11 @@ "json-buffer": "3.0.0" } }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -1675,6 +1690,34 @@ "yallist": "^4.0.0" } }, + "magichome-core": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/magichome-core/-/magichome-core-0.0.13.tgz", + "integrity": "sha512-CkJCjVrvTXWsrRag3I7KFRdZeZFdDd7t9OsMz+d/Hc5HKm8ohKJg+Y3qSArTe3ArW3uU7I43fgLsBbB/vdxhJQ==", + "requires": { + "color-convert": "^2.0.1", + "dgram": "^1.0.1", + "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", + "promise-queue": "^2.2.5" + } + }, + "magichome-platform": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.4.tgz", + "integrity": "sha512-xmUul6J1ABCuIofh9+cVN2ZR3WSz2IcSP6Pg47G9RElnAcuQFsqVg7OJxoUvjOlO6esjGQ5Rdvd0fi/6t4jXqw==", + "requires": { + "dgram": "^1.0.1", + "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", + "magichome-core": ">0.0.12", + "promise-queue": "^2.2.5", + "promise-retry": "^2.0.1", + "prompt-sync": "^4.2.0", + "prompts": "^2.4.1", + "uuid": "^8.3.2" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -1955,6 +1998,47 @@ "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=" }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "prompt-sync": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz", + "integrity": "sha512-BuEzzc5zptP5LsgV5MZETjDaKSWfchl5U9Luiu8SKp7iZWD5tZalOxvNcZRwv+d2phNFr8xlbxmFNcRKfJOzJw==", + "requires": { + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "prompts": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", + "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -2088,6 +2172,11 @@ "lowercase-keys": "^1.0.0" } }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -2155,6 +2244,11 @@ "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", "dev": true }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -2481,6 +2575,11 @@ "prepend-http": "^2.0.0" } }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", diff --git a/package.json b/package.json index fc32180..f8e1e2a 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "color-convert": "^2.0.1", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", + "magichome-platform": "0.0.4", "promise-queue": "^2.2.5" }, "devDependencies": { diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts new file mode 100644 index 0000000..c23fd2a --- /dev/null +++ b/src/AccessoryGenerator.ts @@ -0,0 +1,150 @@ +import { BaseController, ControllerGenerator } from 'magichome-platform'; +import { MagicHomeAccessory } from './magichome-interface/types'; +import { + API, + APIEvent, + DynamicPlatformPlugin, + HAP, + Logging, + PlatformAccessory, + PlatformConfig, +} from 'homebridge'; + +import { homekitInterface } from './magichome-interface/types'; + +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +import { on } from 'events'; +import { create } from 'domain'; + +const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; +const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; + +class AccessoryGenerator { + private log; + + public readonly accessoriesFromDiskMap: Map = new Map(); + + private hap: HAP; + private api: API; + private config: PlatformConfig; + private controllerGenerator: ControllerGenerator; + + constructor({ hap, api, log, config, accessoriesFromDiskMap, controllerGenerator }) { + this.hap = hap; + this.api = api; + this.log = log; + this.accessoriesFromDiskMap = accessoriesFromDiskMap; + this.controllerGenerator = controllerGenerator; + } + + async generateAccessories() { + return await this.controllerGenerator.discoverControllers().then(async controllers => { + return this.discoverAccessories(controllers); + }).catch(error => { + this.log.error(error); + }); + } + + /** + * + * 1. iterate through scanned controllers + * a. exist already as a homebridge accessory? + * i. yes: + * 1. check if it's allowed, if not, skip+remove + * 2. check it for inconsistencies and fix + * 3. register it with homekit again and reset the "last seen" to 0 + * 4. remove it from the diskMap so we later know that it was seen + * ii. no: + * 1. check if it's allowed, if not, skip + * 2. create a new accessory Object and new homeKit interface + * 3. register it with homekit and set "last seen" to 0 + * 2. iterate through all remaining disk devices not yet removed by our scan function + * a. is it allowed, less than allocated number of restarts ( maybe add this to isAllowed)... if not, skip+remove + * b. warn user about device + * c. increment number of times unseen + * d. register with homekit again + * e. add new homeKit interface + * + * note: need a way to just do a base protodevice scan on concurrent scans because current method creates new objects + * which is quite wasteful... + */ + + discoverAccessories(controllers: Map) { + + const accessoriesFromScanList: MagicHomeAccessory[] = []; + + controllers.forEach((controller) => { + const { + protoDevice: { uniqueId, ipAddress, modelNumber }, + deviceState, deviceAPI, + } = controller.getCachedDeviceInformation(); + const homebridgeUUID = this.hap.uuid.generate(uniqueId); + + if (this.accessoriesFromDiskMap[homebridgeUUID]) { + const existingAccessory = this.accessoriesFromDiskMap[homebridgeUUID]; + this.accessoriesFromDiskMap.delete[homebridgeUUID]; + this.processExistingAccessory(existingAccessory); + + } else { + const newAccessory = this.createNewAccessory({ controller, homebridgeUUID }); + accessoriesFromScanList.push(newAccessory); //add it to master accessory list + this.log.printDeviceInfo('Registering new accessory...!', newAccessory); + } + + }); + + this.registerNewAccessories(accessoriesFromScanList); + } + + createNewAccessory({ controller, homebridgeUUID }): MagicHomeAccessory { + const { + protoDevice: { uniqueId, ipAddress, modelNumber }, + deviceState, deviceAPI: { description }, + } = controller.getCachedDeviceInformation(); + + if (!this.isAllowed(uniqueId)) { + this.log.warn(`Warning! New device with Unique ID: ${uniqueId} is blacklisted or is not whitelisted.\n`); + return null; + } + + const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; + newAccessory.context = { controller: controller, displayName: description, scansSinceSeen: 0 }; + try { + new homekitInterface[description](this, newAccessory, this.config); + } catch (error) { + this.log.error('[1] The controllerLogicType does not exist in accessoryType list. Did you migrate this? controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); + this.log.error('device object: ', newAccessory.context.controller); + } + + return newAccessory; + } + + processExistingAccessory(existingAccessory: MagicHomeAccessory){ + + } + + registerNewAccessories(newAccessories: MagicHomeAccessory[]) { + // link the accessory to your platform + this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); + + } + + registerExistingAccessories(existingAccessories: MagicHomeAccessory[]) { + this.api.updatePlatformAccessories(existingAccessories); + } + + + isAllowed(uniqueId): boolean { + + const blacklistedUniqueIDs = this.config.deviceManagement.blacklistedUniqueIDs; + const isWhitelist: boolean = this.config.deviceManagement.blacklistOrWhitelist.includes('whitelist'); + const onList: boolean = (blacklistedUniqueIDs).includes(uniqueId); + + const isAllowed = isWhitelist ? onList : !onList; + + return isAllowed; + } + + // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; + +} \ No newline at end of file diff --git a/src/logs.ts b/src/logs.ts index 3721973..fa8c5f8 100644 --- a/src/logs.ts +++ b/src/logs.ts @@ -1,37 +1,38 @@ -import type { Logger } from 'homebridge'; +import { Logging } from 'homebridge'; export class Logs { - constructor(private logger: Logger, private readonly level = 3) { + constructor(private logger: Logging, private readonly level = 3) { logs = this; + this.level = level; } - trace (message, ...parameters: any[]) { + trace(message, ...parameters: any[]) { if (this.level == 5) { - this.logger.info(message, parameters); + this.logger.info(message, ...parameters); } } - debug (message, ...parameters: any[]) { + debug(message, ...parameters: any[]) { if (this.level >= 4) { - this.logger.info(message, parameters); + this.logger.info(message, ...parameters); } } - info (message, ...parameters: any[]) { + info(message, ...parameters: any[]) { if (this.level >= 3) { - this.logger.info(message, parameters); + this.logger.info(message, ...parameters); } } - warn (message, ...parameters: any[]) { + warn(message, ...parameters: any[]) { if (this.level >= 2) { - this.logger.warn(message, parameters); + this.logger.warn(message, ...parameters); } } - error (message, ...parameters: any[]) { + error(message, ...parameters: any[]) { if (this.level >= 1) { - this.logger.error(message, parameters); + this.logger.error(message, ...parameters); } } } diff --git a/src/magichome-interface/types.ts b/src/magichome-interface/types.ts index 6e5a018..7e115d1 100644 --- a/src/magichome-interface/types.ts +++ b/src/magichome-interface/types.ts @@ -1,79 +1,41 @@ import type { PlatformAccessory } from 'homebridge'; - -export interface IDeviceDiscoveredProps { - ipAddress: string; - uniqueId: string; - modelNumber: string; -} - -export interface IDeviceQueriedProps { - lightParameters: ILightParameters; - controllerHardwareVersion: string | number; - controllerFirmwareVersion: string | number; -} - -export interface ILightParameters { - controllerLogicType: ControllerTypes; - convenientName: string; - simultaneousCCT: boolean; - hasColor: boolean; - hasCCT: boolean; - hasBrightness: boolean; -} - -export enum ControllerTypes { - RGBWStrip = 'RGBWStrip', - RGBWWStrip = 'RGBWWStrip', - CCTStrip = 'CCTStrip', - DimmerStrip = 'DimmerStrip', - GRBStrip = 'GRBStrip', - RGBWWBulb = 'RGBWWBulb', - RGBWBulb = 'RGBWBulb', - Switch = 'Switch', - RGBStrip = 'RGBStrip' -} - -export type IDeviceProps = IDeviceDiscoveredProps & IDeviceQueriedProps & { - UUID: string; - cachedIPAddress: string; - displayName: string; - restartsSinceSeen: number; - lastKnownState?: ILightState; -} - -export interface ILightState { - isOn: boolean; - RGB: IColorRGB; - HSL?: IColorHSL; - whiteValues: IWhites; - brightness?: number; - colorTemperature?: number; - debugBuffer?: Buffer; - controllerHardwareVersion?: string; - controllerFirmwareVersion?: string; -} - -export interface IColorRGB { - red: number; - green: number; - blue:number; -} +import { BaseController } from 'magichome-platform'; + +import { Switch } from '../accessories/Switch'; +import { DimmerStrip } from '../accessories/DimmerStrip'; +import { RGBStrip } from '../accessories/RGBStrip'; +import { GRBStrip } from '../accessories/GRBStrip'; +import { RGBWBulb } from '../accessories/RGBWBulb'; +import { RGBWWBulb } from '../accessories/RGBWWBulb'; +import { RGBWStrip } from '../accessories/RGBWStrip'; +import { RGBWWStrip } from '../accessories/RGBWWStrip'; +import { CCTStrip } from '../accessories/CCTStrip'; + + +export const homekitInterface = { + 'Power Socket': Switch, + 'Dimmer': DimmerStrip, + 'GRB Strip': GRBStrip, + 'RGB Strip': RGBStrip, + 'RGBW Non-Simultaneous': RGBWBulb, + 'RGBWW Non-Simultaneous': RGBWWBulb, + 'RGBW Simultaneous': RGBWStrip, + 'RGBWW Simultaneous': RGBWWStrip, + 'CCT Strip': CCTStrip, +}; export interface IColorHSL { - hue: number; - saturation: number; - luminance: number; + hue: number; + saturation: number; + luminance: number; } -export interface IWhites { - warmWhite: number; - coldWhite: number; -} -export interface MagicHomeAccessory extends PlatformAccessory{ - context: { - displayName: string; - device: IDeviceProps; - pendingRegistration?: boolean; - } - } \ No newline at end of file +export interface MagicHomeAccessory extends PlatformAccessory { + context: { + displayName: string; + scansSinceSeen: number, + controller: BaseController; + pendingRegistration?: boolean; + } +} \ No newline at end of file diff --git a/src/platform.ts b/src/platform.ts index b6430fa..0c65714 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -1,91 +1,96 @@ -import { PLATFORM_NAME, PLUGIN_NAME } from './settings'; import { join } from 'path'; import { loadJson } from './magichome-interface/utils'; -import { Switch } from './accessories/Switch'; -import { DimmerStrip } from './accessories/DimmerStrip'; -import { RGBStrip } from './accessories/RGBStrip'; -import { GRBStrip } from './accessories/GRBStrip'; -import { RGBWBulb } from './accessories/RGBWBulb'; -import { RGBWWBulb } from './accessories/RGBWWBulb'; -import { RGBWStrip } from './accessories/RGBWStrip'; -import { RGBWWStrip } from './accessories/RGBWWStrip'; -import { CCTStrip } from './accessories/CCTStrip'; import { cloneDeep } from 'lodash'; import { Logs } from './logs'; import { API, APIEvent, - CharacteristicEventTypes, - CharacteristicSetCallback, - CharacteristicValue, DynamicPlatformPlugin, HAP, Logging, PlatformAccessory, - PlatformAccessoryEvent, PlatformConfig, } from 'homebridge'; +import { ControllerGenerator } from 'magichome-platform'; +import { ICommandOptions, IDeviceAPI, IDeviceCommand, IProtoDevice } from 'magichome-platform'; + + import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; import { MagicHomeAccessory, ControllerTypes } from './magichome-interface/types'; +import { BaseController } from 'magichome-platform/dist/DeviceControllers/BaseController'; //const NEW_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0x81, 0x8a, 0x8b]); //const LEGACY_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0xEF, 0x01, 0x77]); -const accessoryType = { - Switch, - DimmerStrip, - GRBStrip, - RGBStrip, - RGBWBulb, - RGBWWBulb, - RGBWStrip, - RGBWWStrip, - CCTStrip, +/** + */ +const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; + +const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; +let hap: HAP; +let Accessory: typeof PlatformAccessory; + +export = (api: API) => { + hap = api.hap; + Accessory = api.platformAccessory; + + api.registerPlatform(PLATFORM_NAME, HomebridgeMagichomeDynamicPlatform); }; + /** * HomebridgePlatform * This class is the main constructor for your plugin, this is where you should * parse the user config and discover/register accessories with Homebridge. */ -export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { - public readonly Service = this.api.hap.Service; - public readonly Characteristic = this.api.hap.Characteristic; +class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { + private log; + private readonly api: API; // this is used to track restored cached accessories - public readonly accessories: MagicHomeAccessory[] = []; + public count = 1; + private periodicDiscovery: NodeJS.Timeout | null = null; - private logs: Logs; - + public readonly config: PlatformConfig; + + public readonly accessories: MagicHomeAccessory[] = []; + private readonly controllerGenerator: ControllerGenerator; constructor( - public readonly hbLogger: Logger, - public readonly config: PlatformConfig, - public readonly api: API, + hbLogger: Logging, + config: PlatformConfig, + api: API, ) { - if (this.config.advancedOptions.logLevel) { - this.logs = new Logs(hbLogger, this.config.advancedOptions.logLevel); - } else { - this.logs = new Logs(hbLogger); - } + + this.controllerGenerator = new ControllerGenerator(); + this.log = new Logs(hbLogger, this.config.advancedOptions.logLevel); + + this.api = api; //this.logs = getLogger(); - this.logs.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); - this.logs.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); + this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); + this.log.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); // When this event is fired it means Homebridge has restored all cached accessories from disk. // Dynamic Platform plugins should only register new accessories after this event was fired, // in order to ensure they weren't added to homebridge already. This event can also be used // to start discovery of new accessories. - this.api.on(APIEvent.DID_FINISH_LAUNCHING, () => { - this.logs.debug('Executed didFinishLaunching callback'); - this.count = 1; - // run the method to discover / register your devices as accessories - this.discoverDevices(true); - // Periodic scan for devices - this.periodicDiscovery = setInterval( () => this.discoverDevices(false), 30000); + + api.on(APIEvent.DID_FINISH_LAUNCHING, () => { + this.log.debug('Homebridge Magichome Dynamic Platform didFinishLaunching'); + this.initializePlatforn(); + }); + } + + async initializePlatforn(){ + + this.count = 1; + await this.discoverDevices().then(devices => { + }); + + this.periodicDiscovery = setInterval(() => await this.discoverDevices(), 30000); } /** @@ -94,14 +99,14 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin */ configureAccessory(accessory: MagicHomeAccessory) { - this.logs.debug('%o - Loading accessory from cache...', this.count++, accessory.context.device.displayName); + this.log.debug('%o - Loading accessory from cache...', this.count++, accessory.context.controller.); // set cached accessory as not recently seen // if found later to be a match with a discovered device, will change to true accessory.context.device.restartsSinceSeen++; accessory.context.pendingRegistration = true; // add the restored accessory to the accessories cache so we can track if it has already been registered this.accessories.push(accessory); - + } /** @@ -110,159 +115,126 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user */ - async discoverDevices(dgb: boolean | null) { - const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; - const pendingUpdate = new Set(); - const recentlyRegisteredDevices = new Set(); - - let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - let discover = new Discover(this.logs, this.config); - let devicesDiscovered: IDeviceDiscoveredProps[] = await discover.scan(2000); - - while(devicesDiscovered.length === 0 && scans <5){ - this.logs.debug('( Scan: %o ) Discovered zero devices... rescanning...', scans + 1); - devicesDiscovered = await discover.scan(2000); - scans++; - } + async discoverDevices(): Promise> { - discover = null; - if (devicesDiscovered.length === 0){ - this.logs.debug('\nDiscovered zero devices!\n'); - } else { - this.logs.debug('\nDiscovered %o devices.\n', devicesDiscovered.length); - } - - // loop over the discovered devices and register each one if it has not already been registered - for ( const deviceDiscovered of devicesDiscovered) { - let existingAccessory: MagicHomeAccessory = null; - try { - // generate a unique id for the accessory this should be generated from - const generatedUUID = this.api.hap.uuid.generate(deviceDiscovered.uniqueId); - // check that the device has not already been registered by checking the - // cached devices we stored in the `configureAccessory` method above - existingAccessory = this.accessories.find(accessory => accessory.UUID === generatedUUID); - - if (!existingAccessory) { - if(!this.createNewAccessory(deviceDiscovered, generatedUUID)) { - continue; - } - recentlyRegisteredDevices.add(deviceDiscovered.uniqueId); - registeredDevices++; - newDevices++; - - } else { - // This deviceDiscovered already exist in cache! + return new Promise >(async (resolve, reject) => { + const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; + const pendingUpdate = new Set(); + const recentlyRegisteredDevices = new Set(); - // Check if cached device complies to the device model, - if(!isValidDeviceModel(existingAccessory.context.device, null)) { - //`Device "${uniqueId}" is online, but has outdated data model. Attempting to update it. - this.logs.debug(`The known device "${deviceDiscovered.uniqueId}" seen during discovery has outdated data model (pre v1.8.6). Rebuilding device. `, deviceDiscovered); + let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; + let devicesDiscovered: Map = await this.controllerGenerator.discoverControllers(); + // let discover = new Discover(this.log, this.config); - // ****** RECONSTRUCT DEVICE - patch existingAccessory with updated data ***** - const initialState = await this.getInitialState (deviceDiscovered.ipAddress, 10000); - const deviceQueryData:IDeviceQueriedProps = await this.determineController(deviceDiscovered); + while (!devicesDiscovered && scans < 5) { + this.log.debug('( Scan: %o ) Discovered zero devices... rescanning...', scans + 1); + devicesDiscovered = await this.controllerGenerator.discoverControllers(); + scans++; + } - if(!initialState || !deviceQueryData){ - this.logs.error('Warning! Device type could not be determined for device: %o, this is usually due to an unresponsive device.\n Please restart homebridge. If the problem persists, ensure the device works in the "Magichome Pro" app.\n file an issue on github with an uploaded log\n', - deviceDiscovered.uniqueId); - continue; - } + // discover = null; + if (!devicesDiscovered) { + this.log.debug('\nDiscovered zero devices!\n'); + } else { + this.log.debug('\nDiscovered %o devices.\n', 'FIX ME'); + resolve(devicesDiscovered) + } + }); + } - const oldName = existingAccessory.context.displayName || - existingAccessory.context.device?.lightParameters?.convenientName || - deviceQueryData.lightParameters.convenientName; - - const rootProps = {UUID: generatedUUID, cachedIPAddress: deviceDiscovered.ipAddress, restartsSinceSeen: 0, displayName: oldName, lastKnownState: initialState}; - const deviceData: IDeviceProps = Object.assign(rootProps, deviceDiscovered, deviceQueryData); - existingAccessory.context.device = deviceData; - // ****** RECONSTRUCT DEVICE ***** - - if(isValidDeviceModel(existingAccessory.context.device, this.logs)){ - this.logs.debug(`[discovered+cached] Device "${deviceDiscovered.uniqueId}" successfully repaired!`); - } else { - this.logs.error(`[discovered+cached] Device "${deviceDiscovered.uniqueId}" was not repaired successfully. Ensure it can be controlled in the MagicHome app then restart homebridge to try again while it is online.`); - continue; - } + tempFunction() { + // loop over the discovered devices and register each one if it has not already been registered + devicesDiscovered.forEach(controller => { - } - if(!this.registerExistingAccessory(deviceDiscovered, existingAccessory)){ + + let existingAccessory: MagicHomeAccessory = null; + try { + const { protoDevice: { uniqueId, ipAddress, modelNumber }, deviceState, deviceAPI } = controller.getCachedDeviceInformation(); + + existingAccessory = this.accessories.find(accessory => accessory.UUID === uniqueId); + + if (!existingAccessory) { + if (!this.createNewAccessory(controller, uniqueId)) { continue; } - - // add to list of registered devices, so we can show a summary in the end - recentlyRegisteredDevices.add(deviceDiscovered.uniqueId); + recentlyRegisteredDevices.add(uniqueId); registeredDevices++; - } + newDevices++; + + } else { + + } } catch (error) { - this.logs.error('[discovered+cached] platform.ts discoverDevices() accessory creation has thrown the following error: %o', error); - this.logs.error('[discovered+cached] The existingAccessory object is: ', existingAccessory); - this.logs.error('[discovered+cached] The deviceDiscovered object is: ', deviceDiscovered); + this.log.error('[discovered+cached] platform.ts discoverDevices() accessory creation has thrown the following error: %o', error); + this.log.error('[discovered+cached] The existingAccessory object is: ', existingAccessory); + this.log.error('[discovered+cached] The controller object is: ', controller); } - } + }); + //================================================= // End Cached Devices // - + //***************** Device Pruning Start *****************// - + //if config settings are enabled, devices that are no longer seen //will be pruned, removing them from the cache. Usefull for removing //unplugged or unresponsive accessories - for (const accessory of this.accessories){ + for (const accessory of this.accessories) { try { - - if(!isValidDeviceModel(accessory.context.device, null)) { + + if (!isValidDeviceModel(accessory.context.device, null)) { // only offline, cached devices, old data model, should trigger here. const { uniqueId } = accessory.context.device; - this.logs.debug(`Device "${uniqueId}" was not seen during discovery. Ensure it can be controlled in the MagicHome app. Rescan in 30 seconds...`); + this.log.debug(`Device "${uniqueId}" was not seen during discovery. Ensure it can be controlled in the MagicHome app. Rescan in 30 seconds...`); pendingUpdate.add(uniqueId); continue; } - - if(accessory.context.device?.displayName && accessory.context.device.displayName.toString().toLowerCase().includes('delete')){ + + if (accessory.context.device?.displayName && accessory.context.device.displayName.toString().toLowerCase().includes('delete')) { this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - this.logs.warn('Successfully pruned accessory: ', accessory.context.device.displayName, + this.log.warn('Successfully pruned accessory: ', accessory.context.device.displayName, 'due to being marked for deletion\n'); continue; - - //if the config parameters for pruning are set to true, prune any devices that haven't been seen - //for more restarts than the accepted ammount - } else if(this.config.pruning.pruneMissingCachedAccessories || this.config.pruning.pruneAllAccessoriesNextRestart){ - if(accessory.context.device.restartsSinceSeen >= this.config.pruning.restartsBeforeMissingAccessoriesPruned || this.config.pruning.pruneAllAccessoriesNextRestart){ + + //if the config parameters for pruning are set to true, prune any devices that haven't been seen + //for more restarts than the accepted ammount + } else if (this.config.pruning.pruneMissingCachedAccessories || this.config.pruning.pruneAllAccessoriesNextRestart) { + if (accessory.context.device.restartsSinceSeen >= this.config.pruning.restartsBeforeMissingAccessoriesPruned || this.config.pruning.pruneAllAccessoriesNextRestart) { this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - this.logs.warn('Successfully pruned accessory:', accessory.context.device.displayName, - 'which had not being seen for (',accessory.context.device.restartsSinceSeen,') restart(s).\n'); + this.log.warn('Successfully pruned accessory:', accessory.context.device.displayName, + 'which had not being seen for (', accessory.context.device.restartsSinceSeen, ') restart(s).\n'); continue; } } //simple warning to notify user that their accessory hasn't been seen in n restarts - if(accessory.context.device.restartsSinceSeen > 0){ - //logic for removing blacklisted devices - - if(!this.isAllowed(accessory.context.device.uniqueId)){ - this.logs.warn('Warning! Accessory: %o will be pruned as its Unique ID: %o is blacklisted or is not whitelisted.\n', + if (accessory.context.device.restartsSinceSeen > 0) { + //logic for removing blacklisted devices + + if (!this.isAllowed(accessory.context.device.uniqueId)) { + this.log.warn('Warning! Accessory: %o will be pruned as its Unique ID: %o is blacklisted or is not whitelisted.\n', accessory.context.device.displayName, accessory.context.device.uniqueId); - try{ + try { this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - } catch(err){ - this.logs.debug('Accessory: %o count not be pruned. Likely it had never been registered.\n', + } catch (err) { + this.log.debug('Accessory: %o count not be pruned. Likely it had never been registered.\n', accessory.context.device.displayName, accessory.context.device.uniqueId); } continue; } - this.logs.debug(`Warning! Continuing to register cached accessory "${accessory.context.device.uniqueId}" despite not being seen for ${accessory.context.device.restartsSinceSeen} restarts.`); + this.log.debug(`Warning! Continuing to register cached accessory "${accessory.context.device.uniqueId}" despite not being seen for ${accessory.context.device.restartsSinceSeen} restarts.`); // create the accessory handler let lightAccessory: HomebridgeMagichomeDynamicPlatformAccessory = null; try { lightAccessory = new accessoryType[accessory.context.device.lightParameters.controllerLogicType](this, accessory, this.config); } catch (error) { - this.logs.error('[1] The controllerLogicType does not exist in accessoryType list. Did you migrate this? controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); - this.logs.error('device object: ', accessory.context.device); + this.log.error('[1] The controllerLogicType does not exist in accessoryType list. Did you migrate this? controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); + this.log.error('device object: ', accessory.context.device); continue; } @@ -272,115 +244,97 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin unseenDevices++; } - + } catch (error) { - this.logs.error('platform.ts discoverDevices() accessory pruning has thrown the following error: %o',error); - this.logs.error('The context object is: ',accessory.context); + this.log.error('platform.ts discoverDevices() accessory pruning has thrown the following error: %o', error); + this.log.error('The context object is: ', accessory.context); } } - this.logs.debug('\nRegistered %o Magichome device(s). \nNew devices: %o \nCached devices that were seen this restart: %o' - + '\nCached devices that were not seen this restart: %o\n', - registeredDevices, - newDevices, - registeredDevices-newDevices-unseenDevices, - unseenDevices); + this.log.debug('\nRegistered %o Magichome device(s). \nNew devices: %o \nCached devices that were seen this restart: %o' + + '\nCached devices that were not seen this restart: %o\n', + registeredDevices, + newDevices, + registeredDevices - newDevices - unseenDevices, + unseenDevices); // Discovery summary: - if(recentlyRegisteredDevices.size > 0){ + if (recentlyRegisteredDevices.size > 0) { const found = recentlyRegisteredDevices.size; const pending = Array.from(pendingUpdate).length; const pendingStr = pending > 0 ? ` Pending update: ${pending} devices` : ''; - this.logs.debug(`Discovery summary: Found ${found} devices.${pendingStr}`); + this.log.debug(`Discovery summary: Found ${found} devices.${pendingStr}`); } this.count = 1; // reset the device logging counter }//discoveredDevices + prepareExistingAccessory() { + // This deviceDiscovered already exist in cache! - isAllowed(uniqueId):boolean{ - - const blacklistedUniqueIDs = this.config.deviceManagement.blacklistedUniqueIDs; - let isAllowed = true; - try { + // Check if cached device complies to the device model, + if (!isValidDeviceModel(existingAccessory.context.device, null)) { + //`Device "${uniqueId}" is online, but has outdated data model. Attempting to update it. + this.log.debug(`The known device "${uniqueId}" seen during discovery has outdated data model (pre v1.8.6). Rebuilding device. `, controller); - if(blacklistedUniqueIDs !== undefined - && this.config.deviceManagement.blacklistOrWhitelist !== undefined){ - if (((blacklistedUniqueIDs).includes(uniqueId) - && (this.config.deviceManagement.blacklistOrWhitelist).includes('blacklist')) - || (!(blacklistedUniqueIDs).includes(uniqueId)) - && (this.config.deviceManagement.blacklistOrWhitelist).includes('whitelist')){ - isAllowed = false; - } - } - } catch (error) { - this.logs.debug(error); - } - return isAllowed; - } + // ****** RECONSTRUCT DEVICE - patch existingAccessory with updated data ***** + // const initialState = await this.getInitialState(ipAddress, 10000); + //const deviceQueryData: IDeviceQueriedProps = await this.determineController(deviceDiscovered); - async getInitialState(ipAddress, _timeout = 500){ + // if (!initialState || !deviceQueryData) { + // this.log.error('Warning! Device type could not be determined for device: %o, this is usually due to an unresponsive device.\n Please restart homebridge. If the problem persists, ensure the device works in the "Magichome Pro" app.\n file an issue on github with an uploaded log\n', + // deviceDiscovered.uniqueId); + // continue; + // } - const transport = new Transport(ipAddress, this.config); - try{ - let scans = 0, data; + // const oldName = existingAccessory.context.displayName || + // existingAccessory.context.device?.lightParameters?.convenientName || + // deviceQueryData.lightParameters.convenientName; - while(data == null && scans < 5){ - - data = await transport.getState(_timeout); - scans++; + existingAccessory.context.controller = controller; + // ****** RECONSTRUCT DEVICE ***** + + if (isValidDeviceModel(existingAccessory.context.device, this.log)) { + this.log.debug(`[discovered+cached] Device "${uniqueId}" successfully repaired!`); + } else { + this.log.error(`[discovered+cached] Device "${uniqueId}" was not repaired successfully. Ensure it can be controlled in the MagicHome app then restart homebridge to try again while it is online.`); + continue; } - return data; - - } catch (error) { - this.logs.debug(error); - } - } - - async determineController(discoveredDevice):Promise { - const { ipAddress } = discoveredDevice || {}; - if(typeof ipAddress !== 'string' ){ - this.logs.error('Cannot determine controller because invalid IP address. Device:', discoveredDevice); - return null; } - const initialState = await this.getInitialState (ipAddress, 10000); - if( initialState == undefined){ - this.logs.debug('Cannot determine controller. Device unreacheable.', discoveredDevice); - return null; + + if (!this.registerExistingAccessory(controller, existingAccessory)) { + continue; } - let lightParameters: ILightParameters; - const controllerHardwareVersion = initialState.controllerHardwareVersion; - const controllerFirmwareVersion = initialState.controllerFirmwareVersion; - - this.logs.debug('Attempting to assign controller to new device: UniqueId: %o \nIpAddress %o \nModel: %o\nHardware Version: %o \nDevice Type: %o\n', - discoveredDevice.uniqueId, discoveredDevice.ipAddress,discoveredDevice.modelNumber, initialState.controllerHardwareVersion.toString(16), initialState.controllerFirmwareVersion.toString(16)); - - //set the lightVersion so that we can give the device a useful name and later know how which protocol to use - - if(lightTypesMap.has(controllerHardwareVersion)){ - this.logs.debug('Device %o: Hardware Version: %o with Firmware Version: %o matches known device type records', - discoveredDevice.uniqueId, - controllerHardwareVersion.toString(16), - controllerFirmwareVersion.toString(16)); - lightParameters = lightTypesMap.get(controllerHardwareVersion); - } else { - this.logs.warn('Unknown device version number: %o... unable to create accessory.' , controllerHardwareVersion.toString(16)); - this.logs.warn('Please create an issue at https://github.com/Zacknetic/HomebridgeMagicHome-DynamicPlatform/issues and upload your homebridge.log'); - return null; + // add to list of registered devices, so we can show a summary in the end + recentlyRegisteredDevices.add(uniqueId); + registeredDevices++; + } + + isAllowed(uniqueId): boolean { + + const blacklistedUniqueIDs = this.config.deviceManagement.blacklistedUniqueIDs; + let isAllowed = true; + try { + + if (blacklistedUniqueIDs !== undefined + && this.config.deviceManagement.blacklistOrWhitelist !== undefined) { + if (((blacklistedUniqueIDs).includes(uniqueId) + && (this.config.deviceManagement.blacklistOrWhitelist).includes('blacklist')) + || (!(blacklistedUniqueIDs).includes(uniqueId)) + && (this.config.deviceManagement.blacklistOrWhitelist).includes('whitelist')) { + isAllowed = false; + } + } + } catch (error) { + this.log.debug(error); } - this.logs.debug('Controller Logic Type assigned to %o', lightParameters.controllerLogicType); - - return { - lightParameters, - controllerHardwareVersion: controllerHardwareVersion, - controllerFirmwareVersion: controllerFirmwareVersion, - }; + return isAllowed; } /** @@ -390,28 +344,28 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin * @param deviceDiscovered * @param generatedUUID */ - async createNewAccessory(deviceDiscovered:IDeviceDiscoveredProps, generatedUUID):Promise{ - const unsupportedModels: string[] = [ '000-0000']; //AK001-ZJ210 is suported... + async createNewAccessory(deviceDiscovered: IDeviceDiscoveredProps, generatedUUID): Promise { + const unsupportedModels: string[] = ['000-0000']; //AK001-ZJ210 is suported... - const deviceQueryData:IDeviceQueriedProps = await this.determineController(deviceDiscovered); + const deviceQueryData: IDeviceQueriedProps = await this.determineController(deviceDiscovered); - if(deviceQueryData == null){ - if( unsupportedModels.includes(deviceDiscovered.modelNumber)){ - this.logs.warn('Warning! Discovered device did not respond to query. Device is in the unsupported device list.\nFile an issue on github requesting support. Details:', deviceDiscovered); + if (deviceQueryData == null) { + if (unsupportedModels.includes(deviceDiscovered.modelNumber)) { + this.log.warn('Warning! Discovered device did not respond to query. Device is in the unsupported device list.\nFile an issue on github requesting support. Details:', deviceDiscovered); } else { - this.logs.warn('Warning! Discovered device did not respond to query. This is usually due to an unresponsive device.\nPlease restart homebridge. If the problem persists, ensure the device works in the "Magichome Pro" app.\nFile an issue on github with an uploaded log.', deviceDiscovered); + this.log.warn('Warning! Discovered device did not respond to query. This is usually due to an unresponsive device.\nPlease restart homebridge. If the problem persists, ensure the device works in the "Magichome Pro" app.\nFile an issue on github with an uploaded log.', deviceDiscovered); } return false; } //check if device is on blacklist or is not on whitelist - if(!this.isAllowed(deviceDiscovered.uniqueId)){ - this.logs.warn('Warning! New device with Unique ID: %o is blacklisted or is not whitelisted.\n', + if (!this.isAllowed(deviceDiscovered.uniqueId)) { + this.log.warn('Warning! New device with Unique ID: %o is blacklisted or is not whitelisted.\n', deviceDiscovered.uniqueId); return false; } // if user has oped, use unique name such as "Bulb AABBCCDD" - if( this.config.advancedOptions && this.config.advancedOptions.namesWithMacAddress ){ + if (this.config.advancedOptions && this.config.advancedOptions.namesWithMacAddress) { const uniqueIdName = getUniqueIdName(deviceDiscovered.uniqueId, deviceQueryData.lightParameters.controllerLogicType); deviceQueryData.lightParameters.convenientName = uniqueIdName; } @@ -419,21 +373,21 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; // set its restart prune counter to 0 as it has been seen this session - const deviceData: IDeviceProps = Object.assign({UUID: generatedUUID, cachedIPAddress: deviceDiscovered.ipAddress, restartsSinceSeen: 0, displayName: deviceQueryData.lightParameters.convenientName}, deviceDiscovered, deviceQueryData); - accessory.context.device = deviceData; + const deviceData: IDeviceProps = Object.assign({ UUID: generatedUUID, cachedIPAddress: deviceDiscovered.ipAddress, restartsSinceSeen: 0, displayName: deviceQueryData.lightParameters.convenientName }, deviceDiscovered, deviceQueryData); + accessory.context.device = deviceData; + - this.printDeviceInfo('Registering new accessory...!', accessory); // link the accessory to your platform this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - + // create the accessory handler let lightAccessory: HomebridgeMagichomeDynamicPlatformAccessory = null; try { lightAccessory = new accessoryType[accessory.context.device.lightParameters.controllerLogicType](this, accessory, this.config); } catch (error) { - this.logs.error('[2] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); - this.logs.error('device object: ', accessory.context.device); + this.log.error('[2] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); + this.log.error('device object: ', accessory.context.device); return false; } this.accessories.push(accessory); @@ -442,15 +396,15 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin } /** - * Accessory Generation Method Two: UUID has been seen before. Load from cache. - * Test if seen accessory "is allowed" and that the IP address is identical - * @param deviceDiscovered - * @param existingAccessory - */ - registerExistingAccessory(deviceDiscovered, existingAccessory:MagicHomeAccessory):boolean{ - - if(!this.isAllowed(existingAccessory.context.device.uniqueId)){ - this.logs.warn('Warning! Accessory: %o will be pruned as its Unique ID: %o is blacklisted or is not whitelisted.\n', + * Accessory Generation Method Two: UUID has been seen before. Load from cache. + * Test if seen accessory "is allowed" and that the IP address is identical + * @param deviceDiscovered + * @param existingAccessory + */ + registerExistingAccessory(deviceDiscovered, existingAccessory: MagicHomeAccessory): boolean { + + if (!this.isAllowed(existingAccessory.context.device.uniqueId)) { + this.log.warn('Warning! Accessory: %o will be pruned as its Unique ID: %o is blacklisted or is not whitelisted.\n', existingAccessory.context.device.displayName, existingAccessory.context.device.uniqueId); this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]); return false; @@ -464,36 +418,36 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const ipHasNotChanged = existingAccessory.context.device.cachedIPAddress === deviceDiscovered.ipAddress; const { pendingRegistration } = existingAccessory.context; const registrationComplete = !pendingRegistration; - if(registrationComplete && ipHasNotChanged){ - this.logs.debug(`Device ${existingAccessory.context.device.uniqueId} already registered. Registration update not required`) ; + if (registrationComplete && ipHasNotChanged) { + this.log.debug(`Device ${existingAccessory.context.device.uniqueId} already registered. Registration update not required`); return false; } - if(!ipHasNotChanged){ - this.logs.warn('Ip address discrepancy found for accessory: %o\n Expected ip address: %o\n Discovered ip address: %o' , - existingAccessory.context.device.displayName, existingAccessory.context.device.cachedIPAddress, deviceDiscovered.ipAddress); + if (!ipHasNotChanged) { + this.log.warn('Ip address discrepancy found for accessory: %o\n Expected ip address: %o\n Discovered ip address: %o', + existingAccessory.context.device.displayName, existingAccessory.context.device.cachedIPAddress, deviceDiscovered.ipAddress); // overwrite the ip address of the existing accessory to the newly disovered ip address existingAccessory.context.device.cachedIPAddress = deviceDiscovered.ipAddress; - this.logs.warn('Ip address successfully reassigned to: %o\n ', existingAccessory.context.device.cachedIPAddress); + this.log.warn('Ip address successfully reassigned to: %o\n ', existingAccessory.context.device.cachedIPAddress); } this.printDeviceInfo('Registering existing accessory...', existingAccessory); - + // create the accessory handler let lightAccessory: HomebridgeMagichomeDynamicPlatformAccessory = null; try { - if( !existingAccessory.context?.device?.lightParameters?.controllerLogicType || accessoryType[existingAccessory.context?.device?.lightParameters?.controllerLogicType] === undefined){ - this.logs.error('[registerExistingAccessory] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', existingAccessory.context.device?.lightParameters?.controllerLogicType); - this.logs.error('[registerExistingAccessory] device object: ', existingAccessory.context.device); + if (!existingAccessory.context?.device?.lightParameters?.controllerLogicType || accessoryType[existingAccessory.context?.device?.lightParameters?.controllerLogicType] === undefined) { + this.log.error('[registerExistingAccessory] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', existingAccessory.context.device?.lightParameters?.controllerLogicType); + this.log.error('[registerExistingAccessory] device object: ', existingAccessory.context.device); return false; } lightAccessory = new accessoryType[existingAccessory.context.device.lightParameters.controllerLogicType](this, existingAccessory, this.config); } catch (error) { - this.logs.error('[registerExistingAccessory] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', existingAccessory.context.device?.lightParameters?.controllerLogicType); - this.logs.error('[registerExistingAccessory] device object: ', existingAccessory.context.device); - this.logs.error(error); + this.log.error('[registerExistingAccessory] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', existingAccessory.context.device?.lightParameters?.controllerLogicType); + this.log.error('[registerExistingAccessory] device object: ', existingAccessory.context.device); + this.log.error(error); return false; } @@ -504,66 +458,105 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin return true; } - printDeviceInfo(message: string, accessory: MagicHomeAccessory){ - this.logs.info( '%o - ' + message + - '\nDisplay Name: %o \nController Logic Type: %o \nModel: %o \nUnique ID: %o \nIP-Address: %o \nHardware Version: %o \nFirmware Version: %o \n', - this.count++, - accessory.context.device.displayName, - accessory.context.device.lightParameters?.controllerLogicType, - accessory.context.device.modelNumber, - accessory.context.device.uniqueId, - accessory.context.device.ipAddress, - accessory.context.device.controllerHardwareVersion?.toString(16), - accessory.context.device.controllerFirmwareVersion?.toString(16)); + printDeviceInfo(message: string, accessory: MagicHomeAccessory) { + this.log.info('%o - ' + message + + '\nDisplay Name: %o \nController Logic Type: %o \nModel: %o \nUnique ID: %o \nIP-Address: %o \nHardware Version: %o \nFirmware Version: %o \n', + this.count++, + accessory.context.device.displayName, + accessory.context.device.lightParameters?.controllerLogicType, + accessory.context.device.modelNumber, + accessory.context.device.uniqueId, + accessory.context.device.ipAddress, + accessory.context.device.controllerHardwareVersion?.toString(16), + accessory.context.device.controllerFirmwareVersion?.toString(16)); } async send(transport, command: number[], useChecksum = true, _timeout = 200) { const buffer = Buffer.from(command); const output = await transport.send(buffer, useChecksum, _timeout); - this.logs.debug('Recived the following response', output); + this.log.debug('Recived the following response', output); } //send - static isValidDeviceModel(_device: IDeviceProps, logger):boolean{ + static isValidDeviceModel(_device: IDeviceProps, logger): boolean { const device = cloneDeep(_device); - try{ + try { const { lightParameters } = device || {}; const rootProps = ['UUID', 'cachedIPAddress', 'restartsSinceSeen', 'displayName', 'ipAddress', 'uniqueId', 'modelNumber', 'lightParameters', 'controllerHardwareVersion', 'controllerFirmwareVersion']; - const lightProps = [ 'controllerLogicType', 'convenientName', 'simultaneousCCT', 'hasColor', 'hasBrightness']; - - const missingRootProps = rootProps.filter( k => device[k] === undefined || device[k] == null); - const missingLightProps = lightProps.filter( k => lightParameters[k] === undefined || lightParameters[k] == null); - + const lightProps = ['controllerLogicType', 'convenientName', 'simultaneousCCT', 'hasColor', 'hasBrightness']; + + const missingRootProps = rootProps.filter(k => device[k] === undefined || device[k] == null); + const missingLightProps = lightProps.filter(k => lightParameters[k] === undefined || lightParameters[k] == null); + const missingProps = [...missingRootProps, ...missingLightProps]; - + // special case: props that can be null: 'lastKnownState' - if(device.lastKnownState === undefined) { + if (device.lastKnownState === undefined) { missingProps.push('lastKnownState'); } - if( !Object.values(ControllerTypes).includes( lightParameters.controllerLogicType ) ){ - if(logger){ - logger.error(`[isValidDeviceModel] The ContollerLogicType "${lightParameters.controllerLogicType}" is unknown.` ); + if (!Object.values(ControllerTypes).includes(lightParameters.controllerLogicType)) { + if (logger) { + logger.error(`[isValidDeviceModel] The ContollerLogicType "${lightParameters.controllerLogicType}" is unknown.`); } return false; } - - - if(missingProps.length > 0){ - if(logger){ - logger.error('[isValidDeviceModel] unable to validate device model. Missing properties: ', missingProps ); + + + if (missingProps.length > 0) { + if (logger) { + logger.error('[isValidDeviceModel] unable to validate device model. Missing properties: ', missingProps); logger.debug('\nThree things are certain:\nDeath, taxes and lost data.\nGuess which has occurred.'); } return false; } - + return true; - } catch (err){ + } catch (err) { return false; } } + addAccessory(name: string) { + this.log.info("Adding new accessory with name %s", name); + + // uuid must be generated from a unique but not changing data source, name should not be used in the most cases. But works in this specific example. + const uuid = hap.uuid.generate(name); + const accessory = new Accessory(name, uuid); + + accessory.addService(hap.Service.Lightbulb, "Test Light"); + + this.configureAccessory(accessory); // abusing the configureAccessory here + + this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); + } + + removeAccessories() { + // we don't have any special identifiers, we just remove all our accessories + + this.log.info("Removing all accessories"); + + this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, this.accessories); + this.accessories.splice(0, this.accessories.length); // clear out the array + } + + createHttpService() { + this.requestServer = http.createServer(this.handleRequest.bind(this)); + this.requestServer.listen(18081, () => this.log.info("Http server listening on 18081...")); + } + + private handleRequest(request: IncomingMessage, response: ServerResponse) { + if (request.url === "/add") { + this.addAccessory(new Date().toISOString()); + } else if (request.url === "/remove") { + this.removeAccessories(); + } + + response.writeHead(204); // 204 No content + response.end(); + } + }//ZackneticMagichomePlatform class \ No newline at end of file From f454071720f7e9f61545534c4f1b432910666867 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Wed, 29 Sep 2021 21:00:17 -0400 Subject: [PATCH 04/42] process existing accessory 0.1 --- src/AccessoryGenerator.ts | 71 ++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index c23fd2a..92dd62b 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -37,7 +37,7 @@ class AccessoryGenerator { this.controllerGenerator = controllerGenerator; } - async generateAccessories() { + public async generateAccessories() { return await this.controllerGenerator.discoverControllers().then(async controllers => { return this.discoverAccessories(controllers); }).catch(error => { @@ -69,9 +69,9 @@ class AccessoryGenerator { * which is quite wasteful... */ - discoverAccessories(controllers: Map) { + rescanAccessories(controllers: Map) { - const accessoriesFromScanList: MagicHomeAccessory[] = []; + const newAccessoriesList: MagicHomeAccessory[] = []; controllers.forEach((controller) => { const { @@ -84,16 +84,52 @@ class AccessoryGenerator { const existingAccessory = this.accessoriesFromDiskMap[homebridgeUUID]; this.accessoriesFromDiskMap.delete[homebridgeUUID]; this.processExistingAccessory(existingAccessory); + + } else { + const newAccessory = this.createNewAccessory({ controller, homebridgeUUID }); + newAccessoriesList.push(newAccessory); //add it to new accessory list + this.log.printDeviceInfo('Registering new accessory...!', newAccessory); + } + + }); + + this.registerNewAccessories(newAccessoriesList); //register new accessories from scan + } + + discoverAccessories(controllers: Map) { + + const newAccessoriesList: MagicHomeAccessory[] = []; + const existingAccessoriesList: MagicHomeAccessory[] = []; + + controllers.forEach((controller) => { + const { + protoDevice: { uniqueId, ipAddress, modelNumber }, + deviceState, deviceAPI, + } = controller.getCachedDeviceInformation(); + const homebridgeUUID = this.hap.uuid.generate(uniqueId); + + if (this.accessoriesFromDiskMap[homebridgeUUID]) { + + const existingAccessory = this.accessoriesFromDiskMap[homebridgeUUID]; + const ipAddressOld = controller.getCachedDeviceInformation().protoDevice.ipAddress; + const processedAccessory = this.processExistingAccessory({existingAccessory, ipAddressNew}); + + this.accessoriesFromDiskMap.delete[homebridgeUUID]; + + existingAccessoriesList.push(processedAccessory); + this.log.printDeviceInfo('Registering existing accessory...!', processedAccessory); + } else { const newAccessory = this.createNewAccessory({ controller, homebridgeUUID }); - accessoriesFromScanList.push(newAccessory); //add it to master accessory list + newAccessoriesList.push(newAccessory); //add it to new accessory list this.log.printDeviceInfo('Registering new accessory...!', newAccessory); } }); - this.registerNewAccessories(accessoriesFromScanList); + this.registerNewAccessories(newAccessoriesList); //register new accessories from scan + this.registerExistingAccessories(existingAccessoriesList); } createNewAccessory({ controller, homebridgeUUID }): MagicHomeAccessory { @@ -104,13 +140,13 @@ class AccessoryGenerator { if (!this.isAllowed(uniqueId)) { this.log.warn(`Warning! New device with Unique ID: ${uniqueId} is blacklisted or is not whitelisted.\n`); - return null; + return; } const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; - newAccessory.context = { controller: controller, displayName: description, scansSinceSeen: 0 }; + newAccessory.context = { displayName: description, scansSinceSeen: 0 }; try { - new homekitInterface[description](this, newAccessory, this.config); + new homekitInterface[description](this, newAccessory, this.config, controller); } catch (error) { this.log.error('[1] The controllerLogicType does not exist in accessoryType list. Did you migrate this? controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); this.log.error('device object: ', newAccessory.context.controller); @@ -119,8 +155,25 @@ class AccessoryGenerator { return newAccessory; } - processExistingAccessory(existingAccessory: MagicHomeAccessory){ + processExistingAccessory({existingAccessory, ipAddressNew}) { + const deviceInfo = existingAccessory.context.controller.getCachedDeviceInformation(); + const { + protoDevice: { uniqueId, ipAddress, modelNumber }, + deviceState, deviceAPI: { description }, +} = deviceInfo; + + if (!this.isAllowed(uniqueId)) { + this.log.warn(`Warning! New device with Unique ID: ${uniqueId} is blacklisted or is not whitelisted.\n`); + return; + } + + if(ipAddressNew !== ipAddress) { + ipAddress = ipAddressNew; + } + + + } registerNewAccessories(newAccessories: MagicHomeAccessory[]) { From bf10102ea60a05a332f79b91f0dc72a2210de00f Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Wed, 29 Sep 2021 21:35:53 -0400 Subject: [PATCH 05/42] device logic 0.2 --- src/AccessoryGenerator.ts | 26 +++++++++++++------------- src/magichome-interface/types.ts | 1 - 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 92dd62b..5a2840e 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -112,12 +112,12 @@ class AccessoryGenerator { const existingAccessory = this.accessoriesFromDiskMap[homebridgeUUID]; const ipAddressOld = controller.getCachedDeviceInformation().protoDevice.ipAddress; - const processedAccessory = this.processExistingAccessory({existingAccessory, ipAddressNew}); + const processedAccessory = this.processExistingAccessory({ existingAccessory, ipAddressNew }); this.accessoriesFromDiskMap.delete[homebridgeUUID]; existingAccessoriesList.push(processedAccessory); - + this.log.printDeviceInfo('Registering existing accessory...!', processedAccessory); } else { @@ -148,28 +148,28 @@ class AccessoryGenerator { try { new homekitInterface[description](this, newAccessory, this.config, controller); } catch (error) { - this.log.error('[1] The controllerLogicType does not exist in accessoryType list. Did you migrate this? controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); - this.log.error('device object: ', newAccessory.context.controller); + this.log.error('The controllerLogicType does not exist in accessoryType list.'); } return newAccessory; } - processExistingAccessory({existingAccessory, ipAddressNew}) { - const deviceInfo = existingAccessory.context.controller.getCachedDeviceInformation(); - const { - protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState, deviceAPI: { description }, -} = deviceInfo; - + processExistingAccessory({ controller, existingAccessory }) { + + const deviceInfo = existingAccessory.context.controller.getCachedDeviceInformation(); + const { + protoDevice: { uniqueId, ipAddress, modelNumber }, + deviceState, deviceAPI: { description }, + } = deviceInfo; + if (!this.isAllowed(uniqueId)) { this.log.warn(`Warning! New device with Unique ID: ${uniqueId} is blacklisted or is not whitelisted.\n`); return; } - if(ipAddressNew !== ipAddress) { - ipAddress = ipAddressNew; + if (ipAddressNew !== ipAddress) { + deviceInfo.protoDevice.ipAddress = ipAddressNew; } diff --git a/src/magichome-interface/types.ts b/src/magichome-interface/types.ts index 7e115d1..3822861 100644 --- a/src/magichome-interface/types.ts +++ b/src/magichome-interface/types.ts @@ -35,7 +35,6 @@ export interface MagicHomeAccessory extends PlatformAccessory { context: { displayName: string; scansSinceSeen: number, - controller: BaseController; pendingRegistration?: boolean; } } \ No newline at end of file From 4acfebf83abab1786456812f4e8f4da208f55b69 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Thu, 30 Sep 2021 01:06:33 -0400 Subject: [PATCH 06/42] accessory logic 0.3 --- src/AccessoryGenerator.ts | 83 ++++++++++++++++---------------- src/magichome-interface/types.ts | 3 +- src/platform.ts | 30 ++---------- 3 files changed, 46 insertions(+), 70 deletions(-) diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 5a2840e..29e1b3a 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -20,12 +20,12 @@ const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; class AccessoryGenerator { - private log; public readonly accessoriesFromDiskMap: Map = new Map(); private hap: HAP; private api: API; + private log; private config: PlatformConfig; private controllerGenerator: ControllerGenerator; @@ -71,29 +71,7 @@ class AccessoryGenerator { rescanAccessories(controllers: Map) { - const newAccessoriesList: MagicHomeAccessory[] = []; - - controllers.forEach((controller) => { - const { - protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState, deviceAPI, - } = controller.getCachedDeviceInformation(); - const homebridgeUUID = this.hap.uuid.generate(uniqueId); - - if (this.accessoriesFromDiskMap[homebridgeUUID]) { - const existingAccessory = this.accessoriesFromDiskMap[homebridgeUUID]; - this.accessoriesFromDiskMap.delete[homebridgeUUID]; - this.processExistingAccessory(existingAccessory); - - } else { - const newAccessory = this.createNewAccessory({ controller, homebridgeUUID }); - newAccessoriesList.push(newAccessory); //add it to new accessory list - this.log.printDeviceInfo('Registering new accessory...!', newAccessory); - } - - }); - - this.registerNewAccessories(newAccessoriesList); //register new accessories from scan + // } discoverAccessories(controllers: Map) { @@ -111,8 +89,7 @@ class AccessoryGenerator { if (this.accessoriesFromDiskMap[homebridgeUUID]) { const existingAccessory = this.accessoriesFromDiskMap[homebridgeUUID]; - const ipAddressOld = controller.getCachedDeviceInformation().protoDevice.ipAddress; - const processedAccessory = this.processExistingAccessory({ existingAccessory, ipAddressNew }); + const processedAccessory = this.processExistingAccessory(controller, existingAccessory); this.accessoriesFromDiskMap.delete[homebridgeUUID]; @@ -121,7 +98,7 @@ class AccessoryGenerator { this.log.printDeviceInfo('Registering existing accessory...!', processedAccessory); } else { - const newAccessory = this.createNewAccessory({ controller, homebridgeUUID }); + const newAccessory = this.createNewAccessory(controller, homebridgeUUID); newAccessoriesList.push(newAccessory); //add it to new accessory list this.log.printDeviceInfo('Registering new accessory...!', newAccessory); } @@ -132,19 +109,18 @@ class AccessoryGenerator { this.registerExistingAccessories(existingAccessoriesList); } - createNewAccessory({ controller, homebridgeUUID }): MagicHomeAccessory { + createNewAccessory(controller: BaseController, homebridgeUUID: string): MagicHomeAccessory { const { protoDevice: { uniqueId, ipAddress, modelNumber }, deviceState, deviceAPI: { description }, } = controller.getCachedDeviceInformation(); if (!this.isAllowed(uniqueId)) { - this.log.warn(`Warning! New device with Unique ID: ${uniqueId} is blacklisted or is not whitelisted.\n`); return; } const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; - newAccessory.context = { displayName: description, scansSinceSeen: 0 }; + newAccessory.context = { displayName: description as string, restartsSinceSeen: 0, cachedController: controller }; try { new homekitInterface[description](this, newAccessory, this.config, controller); } catch (error) { @@ -154,25 +130,19 @@ class AccessoryGenerator { return newAccessory; } - processExistingAccessory({ controller, existingAccessory }) { - - const deviceInfo = existingAccessory.context.controller.getCachedDeviceInformation(); + processExistingAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { const { protoDevice: { uniqueId, ipAddress, modelNumber }, deviceState, deviceAPI: { description }, - } = deviceInfo; - + } = controller.getCachedDeviceInformation(); - if (!this.isAllowed(uniqueId)) { - this.log.warn(`Warning! New device with Unique ID: ${uniqueId} is blacklisted or is not whitelisted.\n`); + if (!this.isAllowed(uniqueId) || !this.isFresh(existingAccessory)) { return; } - if (ipAddressNew !== ipAddress) { - deviceInfo.protoDevice.ipAddress = ipAddressNew; - } - + existingAccessory.context.cachedController = controller; + return existingAccessory; } @@ -186,8 +156,32 @@ class AccessoryGenerator { this.api.updatePlatformAccessories(existingAccessories); } + isFresh(existingAccessory: MagicHomeAccessory): boolean { + const cachedDeviceInfo = existingAccessory.context.cachedController.getCachedDeviceInformation(); + let isFresh = true; + const { + protoDevice: { uniqueId, ipAddress, modelNumber }, + deviceState, deviceAPI: { description }, + } = cachedDeviceInfo; + + if (existingAccessory.context.displayName.toString().toLowerCase().includes('delete')) { + + this.unregisterAccessory(existingAccessory, + `Successfully pruned accessory: ${existingAccessory.context.displayName} + due to being marked for deletion\n`); + isFresh = false; + } else if (this.config.pruning.has('pruneRestarts')) { + if (existingAccessory.context.restartsSinceSeen >= this.config.pruning.pruneRestarts) { + this.unregisterAccessory(existingAccessory, `Successfully pruned accessory: ${existingAccessory.context.displayName} + which had not being seen for ${existingAccessory.context.restartsSinceSeen} restart(s).\n`); + isFresh = false; + } + } - isAllowed(uniqueId): boolean { + return isFresh; + } + + isAllowed(uniqueId: string): boolean { const blacklistedUniqueIDs = this.config.deviceManagement.blacklistedUniqueIDs; const isWhitelist: boolean = this.config.deviceManagement.blacklistOrWhitelist.includes('whitelist'); @@ -198,6 +192,11 @@ class AccessoryGenerator { return isAllowed; } + unregisterAccessory(existingAccessory: MagicHomeAccessory, reason: string) { + this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]); + this.log.warn(reason); + } + // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; } \ No newline at end of file diff --git a/src/magichome-interface/types.ts b/src/magichome-interface/types.ts index 3822861..9e025ca 100644 --- a/src/magichome-interface/types.ts +++ b/src/magichome-interface/types.ts @@ -34,7 +34,8 @@ export interface IColorHSL { export interface MagicHomeAccessory extends PlatformAccessory { context: { displayName: string; - scansSinceSeen: number, + restartsSinceSeen: number, pendingRegistration?: boolean; + cachedController: BaseController; } } \ No newline at end of file diff --git a/src/platform.ts b/src/platform.ts index 0c65714..df2e888 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -83,7 +83,7 @@ class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { }); } - async initializePlatforn(){ + async initializePlatforn() { this.count = 1; await this.discoverDevices().then(devices => { @@ -117,7 +117,7 @@ class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { */ async discoverDevices(): Promise> { - return new Promise >(async (resolve, reject) => { + return new Promise>(async (resolve, reject) => { const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; const pendingUpdate = new Set(); const recentlyRegisteredDevices = new Set(); @@ -186,32 +186,8 @@ class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { for (const accessory of this.accessories) { try { - if (!isValidDeviceModel(accessory.context.device, null)) { - // only offline, cached devices, old data model, should trigger here. - const { uniqueId } = accessory.context.device; - this.log.debug(`Device "${uniqueId}" was not seen during discovery. Ensure it can be controlled in the MagicHome app. Rescan in 30 seconds...`); - pendingUpdate.add(uniqueId); - continue; - } - - if (accessory.context.device?.displayName && accessory.context.device.displayName.toString().toLowerCase().includes('delete')) { - this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - this.log.warn('Successfully pruned accessory: ', accessory.context.device.displayName, - 'due to being marked for deletion\n'); - continue; - - //if the config parameters for pruning are set to true, prune any devices that haven't been seen - //for more restarts than the accepted ammount - } else if (this.config.pruning.pruneMissingCachedAccessories || this.config.pruning.pruneAllAccessoriesNextRestart) { - if (accessory.context.device.restartsSinceSeen >= this.config.pruning.restartsBeforeMissingAccessoriesPruned || this.config.pruning.pruneAllAccessoriesNextRestart) { - this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - this.log.warn('Successfully pruned accessory:', accessory.context.device.displayName, - 'which had not being seen for (', accessory.context.device.restartsSinceSeen, ') restart(s).\n'); - continue; - } - } //simple warning to notify user that their accessory hasn't been seen in n restarts - if (accessory.context.device.restartsSinceSeen > 0) { + if (accessory.context.restartsSinceSeen > 0) { //logic for removing blacklisted devices if (!this.isAllowed(accessory.context.device.uniqueId)) { From 5ca04cc92eddae7c34a6ab307f4cce82de7c6699 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Thu, 30 Sep 2021 18:16:24 -0400 Subject: [PATCH 07/42] mvp --- nodemon.json | 2 +- src/AccessoryGenerator.ts | 68 ++-- src/accessories/CCTStrip.ts | 2 +- src/accessories/DimmerStrip.ts | 6 +- src/accessories/GRBStrip.ts | 8 +- src/accessories/RGBStrip.ts | 8 +- src/accessories/RGBWBulb.ts | 24 +- src/accessories/RGBWStrip.ts | 32 +- src/accessories/RGBWWBulb.ts | 124 +++---- src/accessories/RGBWWStrip.ts | 144 ++++---- src/accessories/Switch.ts | 2 +- src/index.ts | 42 ++- src/magichome-interface/Discover.ts | 73 ---- src/magichome-interface/LightMap.ts | 201 ----------- src/magichome-interface/Network.ts | 38 --- src/magichome-interface/Transport.ts | 163 --------- src/magichome-interface/types.ts | 2 +- src/platform.ts | 487 +++------------------------ src/platformAccessory.ts | 429 +++++++---------------- 19 files changed, 411 insertions(+), 1444 deletions(-) delete mode 100644 src/magichome-interface/Discover.ts delete mode 100644 src/magichome-interface/LightMap.ts delete mode 100644 src/magichome-interface/Network.ts delete mode 100644 src/magichome-interface/Transport.ts diff --git a/nodemon.json b/nodemon.json index 9e864a0..86914d2 100644 --- a/nodemon.json +++ b/nodemon.json @@ -4,5 +4,5 @@ ], "ext": "ts", "ignore": [], - "exec": "tsc && homebridge -I -D -U C:/Users/zacka/.homebridge-two" + "exec": "tsc && homebridge -I -D" } diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 29e1b3a..c30670c 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -2,24 +2,17 @@ import { BaseController, ControllerGenerator } from 'magichome-platform'; import { MagicHomeAccessory } from './magichome-interface/types'; import { API, - APIEvent, - DynamicPlatformPlugin, HAP, - Logging, - PlatformAccessory, PlatformConfig, } from 'homebridge'; import { homekitInterface } from './magichome-interface/types'; - -import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -import { on } from 'events'; -import { create } from 'domain'; +import { config } from 'process'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; -class AccessoryGenerator { +export class AccessoryGenerator { public readonly accessoriesFromDiskMap: Map = new Map(); @@ -29,20 +22,23 @@ class AccessoryGenerator { private config: PlatformConfig; private controllerGenerator: ControllerGenerator; - constructor({ hap, api, log, config, accessoriesFromDiskMap, controllerGenerator }) { + constructor(hap, api, log, config, accessoriesFromDiskMap, controllerGenerator) { this.hap = hap; this.api = api; this.log = log; + this.config = config; this.accessoriesFromDiskMap = accessoriesFromDiskMap; this.controllerGenerator = controllerGenerator; } public async generateAccessories() { + this.log.warn('started to generate accessories'); return await this.controllerGenerator.discoverControllers().then(async controllers => { return this.discoverAccessories(controllers); }).catch(error => { this.log.error(error); }); + } /** @@ -79,11 +75,9 @@ class AccessoryGenerator { const newAccessoriesList: MagicHomeAccessory[] = []; const existingAccessoriesList: MagicHomeAccessory[] = []; - controllers.forEach((controller) => { - const { - protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState, deviceAPI, - } = controller.getCachedDeviceInformation(); + for (const [uniqueId, controller] of Object.entries(controllers)) { + this.log.warn(controller); + const homebridgeUUID = this.hap.uuid.generate(uniqueId); if (this.accessoriesFromDiskMap[homebridgeUUID]) { @@ -94,54 +88,67 @@ class AccessoryGenerator { this.accessoriesFromDiskMap.delete[homebridgeUUID]; existingAccessoriesList.push(processedAccessory); + this.log.warn('registering existing accessory'); - this.log.printDeviceInfo('Registering existing accessory...!', processedAccessory); + //this.log.printDeviceInfo('Registering existing accessory...!', processedAccessory); } else { const newAccessory = this.createNewAccessory(controller, homebridgeUUID); newAccessoriesList.push(newAccessory); //add it to new accessory list - this.log.printDeviceInfo('Registering new accessory...!', newAccessory); + //this.log.printDeviceInfo('Registering new accessory...!', newAccessory); + this.log.warn('registering new accessory'); + } - }); + } this.registerNewAccessories(newAccessoriesList); //register new accessories from scan this.registerExistingAccessories(existingAccessoriesList); } createNewAccessory(controller: BaseController, homebridgeUUID: string): MagicHomeAccessory { + + const cachedInformation = controller.getCachedDeviceInformation(); const { protoDevice: { uniqueId, ipAddress, modelNumber }, deviceState, deviceAPI: { description }, - } = controller.getCachedDeviceInformation(); + } = cachedInformation; + if (!this.isAllowed(uniqueId)) { return; } const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; - newAccessory.context = { displayName: description as string, restartsSinceSeen: 0, cachedController: controller }; + newAccessory.context = { displayName: description as string, restartsSinceSeen: 0, cachedInformation }; + try { - new homekitInterface[description](this, newAccessory, this.config, controller); + new homekitInterface[description](this.hap, this.api, newAccessory, this.config, controller); } catch (error) { this.log.error('The controllerLogicType does not exist in accessoryType list.'); + this.log.error(error); } - return newAccessory; } processExistingAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { + const cachedInformation = controller.getCachedDeviceInformation(); const { protoDevice: { uniqueId, ipAddress, modelNumber }, deviceState, deviceAPI: { description }, - } = controller.getCachedDeviceInformation(); + } = cachedInformation; - if (!this.isAllowed(uniqueId) || !this.isFresh(existingAccessory)) { + if (!this.isAllowed(uniqueId) || !this.isFresh(cachedInformation, existingAccessory)) { return; } - existingAccessory.context.cachedController = controller; - + existingAccessory.context.cachedInformation = cachedInformation; + try { + new homekitInterface[description](this.hap, this.api, existingAccessory, this.config, controller); + } catch (error) { + this.log.error('The controllerLogicType does not exist in accessoryType list.'); + this.log.error(error); + } return existingAccessory; } @@ -156,13 +163,14 @@ class AccessoryGenerator { this.api.updatePlatformAccessories(existingAccessories); } - isFresh(existingAccessory: MagicHomeAccessory): boolean { - const cachedDeviceInfo = existingAccessory.context.cachedController.getCachedDeviceInformation(); + isFresh(cachedInformation, existingAccessory: MagicHomeAccessory): boolean { + + let isFresh = true; const { protoDevice: { uniqueId, ipAddress, modelNumber }, deviceState, deviceAPI: { description }, - } = cachedDeviceInfo; + } = cachedInformation; if (existingAccessory.context.displayName.toString().toLowerCase().includes('delete')) { @@ -170,7 +178,7 @@ class AccessoryGenerator { `Successfully pruned accessory: ${existingAccessory.context.displayName} due to being marked for deletion\n`); isFresh = false; - } else if (this.config.pruning.has('pruneRestarts')) { + } else if (this.config.pruning.pruneRestarts) { if (existingAccessory.context.restartsSinceSeen >= this.config.pruning.pruneRestarts) { this.unregisterAccessory(existingAccessory, `Successfully pruned accessory: ${existingAccessory.context.displayName} which had not being seen for ${existingAccessory.context.restartsSinceSeen} restart(s).\n`); diff --git a/src/accessories/CCTStrip.ts b/src/accessories/CCTStrip.ts index 8358785..0376313 100644 --- a/src/accessories/CCTStrip.ts +++ b/src/accessories/CCTStrip.ts @@ -33,7 +33,7 @@ export class CCTStrip extends HomebridgeMagichomeDynamicPlatformAccessory { // + (this.lightState.whiteValues.warmWhite/1.27)), 0, 100)); } - this.cacheCurrentLightState(); + //this.cacheCurrentLightState(); } } \ No newline at end of file diff --git a/src/accessories/DimmerStrip.ts b/src/accessories/DimmerStrip.ts index 1aec398..3ba3f42 100644 --- a/src/accessories/DimmerStrip.ts +++ b/src/accessories/DimmerStrip.ts @@ -9,10 +9,10 @@ export class DimmerStrip extends HomebridgeMagichomeDynamicPlatformAccessory { async updateHomekitState() { this.lightState.brightness = this.lightState.RGB.red / 2.5; //create local constant for brightness - this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + //this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); if( this.lightState.isOn ){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); + //this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); } } @@ -22,7 +22,7 @@ export class DimmerStrip extends HomebridgeMagichomeDynamicPlatformAccessory { //**** local variables ****\\ const brightness = Math.round((2.5 * this.lightState.brightness)); - await this.send([0x31, brightness, 0x00, 0x00, 0x03, 0x01, 0x0F]); //8th byte checksum calculated later in send() + //await this.send([0x31, brightness, 0x00, 0x00, 0x03, 0x01, 0x0F]); //8th byte checksum calculated later in send() }//setColor diff --git a/src/accessories/GRBStrip.ts b/src/accessories/GRBStrip.ts index 1bf1897..52abc2c 100644 --- a/src/accessories/GRBStrip.ts +++ b/src/accessories/GRBStrip.ts @@ -24,12 +24,12 @@ export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { if(this.eightByteProtocol == 0){ - await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() + // await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() } else if(this.eightByteProtocol == 1){ - await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); + //await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); } else if (this.eightByteProtocol == 2){ - this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() + //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; + // await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() } diff --git a/src/accessories/RGBStrip.ts b/src/accessories/RGBStrip.ts index 70689e6..c03ba19 100644 --- a/src/accessories/RGBStrip.ts +++ b/src/accessories/RGBStrip.ts @@ -23,12 +23,12 @@ export class RGBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); if(this.eightByteProtocol == 0){ - await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() + //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() } else if(this.eightByteProtocol == 1){ - await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); + // await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); } else if (this.eightByteProtocol == 2){ - this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() + //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; + //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() } }//setColor } \ No newline at end of file diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index ec60202..deb5d42 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -42,25 +42,25 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { } if(this.eightByteProtocol == 0){ - await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() + //await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() } else if(this.eightByteProtocol == 1){ - await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); + // await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); } else if (this.eightByteProtocol == 2){ - this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() + //this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; + //await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() } } async updateHomekitState(){ - this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - } else if (this.lightState.isOn){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); - } + // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); + // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); + // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ + // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); + // } else if (this.lightState.isOn){ + // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); + // } } } \ No newline at end of file diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index c4e3f32..15d0678 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -56,25 +56,25 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); } - if(this.eightByteProtocol == 0){ - await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - } else if(this.eightByteProtocol == 1){ - await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); - } else if (this.eightByteProtocol == 2){ - this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - } + // if(this.eightByteProtocol == 0){ + // await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() + // } else if(this.eightByteProtocol == 1){ + // await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); + // } else if (this.eightByteProtocol == 2){ + // this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; + // await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() + // } }//setColor async updateHomekitState(){ - this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - } else if (this.lightState.isOn){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); - } + // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); + // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); + // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ + // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); + // } else if (this.lightState.isOn){ + // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); + // } } } \ No newline at end of file diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index 8e046bc..75df6e7 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -5,82 +5,82 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { async updateDeviceState(_timeout = 200) { - //**** local variables ****\\ - const hsl = this.lightState.HSL; - const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - const whites = this.hueToWhiteTemperature(); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - const brightness = this.lightState.brightness; + // //**** local variables ****\\ + // const hsl = this.lightState.HSL; + // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB + // // const whites = this.hueToWhiteTemperature(); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" + // const brightness = this.lightState.brightness; - // this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + // // this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - let mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - //we default the mask to turn on color. Other values can still be set, they just wont turn on + // let mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) + // //we default the mask to turn on color. Other values can still be set, they just wont turn on - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - let ww = Math.round(((clamp(whites.warmWhite, 0, 255) / 100) * brightness)); - let cw = Math.round(((clamp(whites.coldWhite, 0, 255) / 100) * brightness)); + // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + // let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); + // let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); + // let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); + // let ww = Math.round(((clamp(whites.warmWhite, 0, 255) / 100) * brightness)); + // let cw = Math.round(((clamp(whites.coldWhite, 0, 255) / 100) * brightness)); - if (hsl.hue == 31 && (hsl.saturation == 33)) { - r = 0; - g = 0; - b = 0; - ww = Math.round((255 / 100) * brightness); - cw = 0; - mask = 0x0F; - //this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); - } else if ((hsl.hue == 208 && (hsl.saturation == 17))) { - r = 0; - g = 0; - b = 0; - ww = 0; - cw = Math.round((255 / 100) * brightness); - mask = 0x0F; - // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); + // if (hsl.hue == 31 && (hsl.saturation == 33)) { + // r = 0; + // g = 0; + // b = 0; + // ww = Math.round((255 / 100) * brightness); + // cw = 0; + // mask = 0x0F; + // //this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); + // } else if ((hsl.hue == 208 && (hsl.saturation == 17))) { + // r = 0; + // g = 0; + // b = 0; + // ww = 0; + // cw = Math.round((255 / 100) * brightness); + // mask = 0x0F; + // // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); - //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). - //White colors were already calculated above - } else if ((hsl.saturation < this.colorWhiteThreshold)) { - r = 0; - g = 0; - b = 0; - mask = 0x0F; - // this.platform.log.debug('Setting warmWhite and coldWhite without colors: ww:%o cw:%o', ww, cw); - } else { //else set warmWhite and coldWhite to zero. Color mask already set at top + // //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). + // //White colors were already calculated above + // } else if ((hsl.saturation < this.colorWhiteThreshold)) { + // r = 0; + // g = 0; + // b = 0; + // mask = 0x0F; + // // this.platform.log.debug('Setting warmWhite and coldWhite without colors: ww:%o cw:%o', ww, cw); + // } else { //else set warmWhite and coldWhite to zero. Color mask already set at top - ww = 0; - cw = 0; - //this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); + // ww = 0; + // cw = 0; + // //this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); - } - await this.send([0x31, r, g, b, ww, cw, mask, 0x0F], true, _timeout); //9th byte checksum calculated later in send() + // } + // await this.send([0x31, r, g, b, ww, cw, mask, 0x0F], true, _timeout); //9th byte checksum calculated later in send() }//setColor async updateHomekitState() { - this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - } else if (this.lightState.isOn){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(((this.lightState.whiteValues.coldWhite/2.55) + (this.lightState.whiteValues.warmWhite/2.55)), 0, 100)); - if(this.lightState.whiteValues.warmWhite>this.lightState.whiteValues.coldWhite){ - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.coldWhite/255))); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, 0); - } else { - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.warmWhite/255))); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, 180); - } - } - this.cacheCurrentLightState(); + // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); + // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); + // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ + // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); + // } else if (this.lightState.isOn){ + // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(((this.lightState.whiteValues.coldWhite/2.55) + (this.lightState.whiteValues.warmWhite/2.55)), 0, 100)); + // if(this.lightState.whiteValues.warmWhite>this.lightState.whiteValues.coldWhite){ + // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.coldWhite/255))); + // this.service.updateCharacteristic(this.platform.Characteristic.Hue, 0); + // } else { + // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.warmWhite/255))); + // this.service.updateCharacteristic(this.platform.Characteristic.Hue, 180); + // } + // } + // this.cacheCurrentLightState(); } } \ No newline at end of file diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index c50a0bc..f6ae850 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -5,94 +5,94 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { async updateDeviceState() { - //**** local variables ****\\ - const hsl = this.lightState.HSL; - let [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - const whites = this.hueToWhiteTemperature(); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - const brightness = this.lightState.brightness; + // //**** local variables ****\\ + // const hsl = this.lightState.HSL; + // let [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB + // const whites = this.hueToWhiteTemperature(); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" + // const brightness = this.lightState.brightness; - //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - let mask = 0xFF; + // let mask = 0xFF; - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - let ww = Math.round(((clamp(whites.warmWhite, 0, 255) / 100) * brightness)); - let cw = Math.round(((clamp(whites.coldWhite, 0, 255) / 100) * brightness)); + // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + // let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); + // let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); + // let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); + // let ww = Math.round(((clamp(whites.warmWhite, 0, 255) / 100) * brightness)); + // let cw = Math.round(((clamp(whites.coldWhite, 0, 255) / 100) * brightness)); - if (hsl.hue == 31 && hsl.saturation == 33) { + // if (hsl.hue == 31 && hsl.saturation == 33) { - r = 0; - g = 0; - b = 0; - ww = Math.round((255 / 100) * brightness); - cw = 0; - mask = 0x0F; - // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); + // r = 0; + // g = 0; + // b = 0; + // ww = Math.round((255 / 100) * brightness); + // cw = 0; + // mask = 0x0F; + // // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); - } else if (hsl.hue == 208 && hsl.saturation == 17) { - r = 0; - g = 0; - b = 0; - ww = 0; - cw = Math.round((255 / 100) * brightness); - mask = 0x0F; - // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); + // } else if (hsl.hue == 208 && hsl.saturation == 17) { + // r = 0; + // g = 0; + // b = 0; + // ww = 0; + // cw = Math.round((255 / 100) * brightness); + // mask = 0x0F; + // // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); - //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). - //White colors were already calculated above - } else if (hsl.saturation < this.colorOffThresholdSimultaniousDevices) { - // this.platform.log.debug('Turning off color'); - r = 0; - g = 0; - b = 0; - // this.platform.log.debug('Setting only white: ww:%o cw:%o', ww, cw); + // //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). + // //White colors were already calculated above + // } else if (hsl.saturation < this.colorOffThresholdSimultaniousDevices) { + // // this.platform.log.debug('Turning off color'); + // r = 0; + // g = 0; + // b = 0; + // // this.platform.log.debug('Setting only white: ww:%o cw:%o', ww, cw); - //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" - //set RGB to 100% saturation and 100% brightness - //this allows brightness to only affect the white colors, creating beautiful white+color balance - //we've set the color saturation to 100% because the higher the white level the more washed out the colors become - //the white brightness effectively acts as the saturation value - } else if (hsl.saturation < this.colorWhiteThresholdSimultaniousDevices && this.simultaniousDevicesColorWhite) { + // //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" + // //set RGB to 100% saturation and 100% brightness + // //this allows brightness to only affect the white colors, creating beautiful white+color balance + // //we've set the color saturation to 100% because the higher the white level the more washed out the colors become + // //the white brightness effectively acts as the saturation value + // } else if (hsl.saturation < this.colorWhiteThresholdSimultaniousDevices && this.simultaniousDevicesColorWhite) { - [red, green, blue] = convertHSLtoRGB({ hue: hsl.hue, saturation: 100, luminance: hsl.luminance}); //re-generate rgb with full saturation - r = red; - g = green; - b = blue; - // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); + // [red, green, blue] = convertHSLtoRGB({ hue: hsl.hue, saturation: 100, luminance: hsl.luminance}); //re-generate rgb with full saturation + // r = red; + // g = green; + // b = blue; + // // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); - //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs - } else { - ww = 0; - cw = 0; - // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); - } + // //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs + // } else { + // ww = 0; + // cw = 0; + // // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); + // } - await this.send([0x31, r, g, b, ww, cw, mask, 0x0F]); //9th byte checksum calculated later in send() + // await this.send([0x31, r, g, b, ww, cw, mask, 0x0F]); //9th byte checksum calculated later in send() }//setColor async updateHomekitState() { - this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - } else if (this.lightState.isOn){ - this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(((this.lightState.whiteValues.coldWhite/2.55) + (this.lightState.whiteValues.warmWhite/2.55)), 0, 100)); - if(this.lightState.whiteValues.warmWhite>this.lightState.whiteValues.coldWhite){ - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.coldWhite/255))); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, 0); - } else { - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.warmWhite/255))); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, 180); - } - } + // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); + // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); + // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ + // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); + // } else if (this.lightState.isOn){ + // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(((this.lightState.whiteValues.coldWhite/2.55) + (this.lightState.whiteValues.warmWhite/2.55)), 0, 100)); + // if(this.lightState.whiteValues.warmWhite>this.lightState.whiteValues.coldWhite){ + // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.coldWhite/255))); + // this.service.updateCharacteristic(this.platform.Characteristic.Hue, 0); + // } else { + // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.warmWhite/255))); + // this.service.updateCharacteristic(this.platform.Characteristic.Hue, 180); + // } + // } } } \ No newline at end of file diff --git a/src/accessories/Switch.ts b/src/accessories/Switch.ts index d646343..3aca931 100644 --- a/src/accessories/Switch.ts +++ b/src/accessories/Switch.ts @@ -8,7 +8,7 @@ export class Switch extends HomebridgeMagichomeDynamicPlatformAccessory { */ async updateHomekitState() { - this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); } diff --git a/src/index.ts b/src/index.ts index c1c1e2c..6e03296 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,40 @@ -import type { API } from 'homebridge'; -import { PLATFORM_NAME } from './settings'; -import { HomebridgeMagichomeDynamicPlatform } from './platform'; +import { join } from 'path'; +import { loadJson } from './magichome-interface/utils'; +import { cloneDeep } from 'lodash'; +import { Logs } from './logs'; +import { + API, + APIEvent, + DynamicPlatformPlugin, + HAP, + Logging, + PlatformAccessory, + PlatformConfig, +} from 'homebridge'; + +import { ICommandOptions, IDeviceAPI, IDeviceCommand, IProtoDevice, ControllerGenerator } from 'magichome-platform'; + +// import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +import { MagicHomeAccessory } from './magichome-interface/types'; +import { BaseController } from 'magichome-platform/dist/DeviceControllers/BaseController'; +//const NEW_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0x81, 0x8a, 0x8b]); +//const LEGACY_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0xEF, 0x01, 0x77]); +import { AccessoryGenerator } from './AccessoryGenerator'; /** - * This method registers the platform with Homebridge */ + +const controllerGenerator = new ControllerGenerator(); + +let hap: HAP; +import { PLATFORM_NAME } from './settings'; +import { HomebridgeMagichomeDynamicPlatform } from './platform'; + +let Accessory: typeof PlatformAccessory; export = (api: API) => { - api.registerPlatform('homebridge-magichome-dynamic-platform', PLATFORM_NAME, HomebridgeMagichomeDynamicPlatform); -} - \ No newline at end of file + hap = api.hap; + Accessory = api.platformAccessory; + + api.registerPlatform(PLATFORM_NAME, HomebridgeMagichomeDynamicPlatform); +}; diff --git a/src/magichome-interface/Discover.ts b/src/magichome-interface/Discover.ts deleted file mode 100644 index c097cb0..0000000 --- a/src/magichome-interface/Discover.ts +++ /dev/null @@ -1,73 +0,0 @@ -import dgram from 'dgram'; -import { Network } from './Network'; - -import { Logs } from '../logs'; -import type { PlatformConfig } from 'homebridge'; -import { IDeviceDiscoveredProps } from '../magichome-interface/types'; - -const BROADCAST_PORT = 48899; -const BROADCAST_MAGIC_STRING = 'HF-A11ASSISTHREAD'; - -export class Discover { - public count = 1; - constructor( - public readonly logs: Logs, - private readonly config: PlatformConfig, - ){} - - - async scan(timeout = 500): Promise { - - return new Promise((resolve, reject) => { - const userInterfaces = Network.subnets(); - const clients: IDeviceDiscoveredProps[] = []; - const socket = dgram.createSocket('udp4'); - - socket.on('error', (err) => { - socket.close(); - reject(err); - }); - - socket.on('message', (msg) => { - const parts = msg.toString().split(','); - - if (parts.length !== 3) { - return; - } - const [ipAddress, uniqueId, modelNumber] = parts; - - if (clients.findIndex((item) => item.uniqueId === uniqueId) === -1) { - clients.push({ ipAddress, uniqueId, modelNumber }); - this.logs.debug('\n%o - Discovered device...\nUniqueId: %o \nIpAddress %o \nModel: %o\n.', this.count++, uniqueId, ipAddress,modelNumber); - } else { - this.logs.debug('\n%o - A device has been discovered that already exists. Likely due to a "fun" network layout...\nUniqueId: %o \nIpAddress %o \nModel: %o\n already exists.', this.count++, uniqueId, ipAddress,modelNumber); - } - - }); - - socket.on('listening', () => { - socket.setBroadcast(true); - - const addressAlreadyScanned: string[] = []; - for (const userInterface of userInterfaces){ - if( addressAlreadyScanned.includes(userInterface.broadcast)){ - this.logs.debug('Skipping redundant scan of broadcast-address %o for Magichome devices.', userInterface.broadcast); - continue; - } - addressAlreadyScanned.push(userInterface.broadcast); - this.logs.debug('Scanning broadcast-address: %o for Magichome devices...', userInterface.broadcast); - socket.send(BROADCAST_MAGIC_STRING, BROADCAST_PORT, userInterface.broadcast); - } - }); - - socket.bind(BROADCAST_PORT); - - setTimeout(() => { - socket.close(); - resolve(clients); - }, timeout); - }); - } - -} - diff --git a/src/magichome-interface/LightMap.ts b/src/magichome-interface/LightMap.ts deleted file mode 100644 index dd31bbf..0000000 --- a/src/magichome-interface/LightMap.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { ILightParameters, ControllerTypes } from './types'; - -const lightTypesMap: Map = new Map([ - [ - 0x04, - { - controllerLogicType: ControllerTypes.RGBWStrip, - convenientName: 'RGBW Simultaneous', - simultaneousCCT: true, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x06, - { - controllerLogicType: ControllerTypes.RGBWStrip, - convenientName: 'RGBW Simultaneous', - simultaneousCCT: true, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x07, - { - controllerLogicType: ControllerTypes.RGBWWStrip, - convenientName: 'RGBWW Simultaneous', - simultaneousCCT: true, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x09, - { - controllerLogicType: ControllerTypes.CCTStrip, - convenientName: 'CCT Strip', - simultaneousCCT: false, - hasColor: false, - hasCCT: true, - hasBrightness: true, - }, - ], - [ - 0x21, - { - controllerLogicType: ControllerTypes.DimmerStrip, - convenientName: 'Dimmer', - simultaneousCCT: false, - hasColor: false, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x25, - { - controllerLogicType: ControllerTypes.RGBWWStrip, - convenientName: 'RGBWW Simultaneous', - simultaneousCCT: true, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x33, - { - controllerLogicType: ControllerTypes.GRBStrip, - convenientName: 'GRB Strip', - simultaneousCCT: true, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x35, - { - controllerLogicType: ControllerTypes.RGBWWBulb, - convenientName: 'RGBWW Non-Simultaneous', - simultaneousCCT: false, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x41, - { - controllerLogicType: ControllerTypes.DimmerStrip, - convenientName: 'Dimmer', - simultaneousCCT: false, - hasColor: false, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x44, - { - controllerLogicType: ControllerTypes.RGBWBulb, - convenientName: 'RGBW Non-Simultaneous', - simultaneousCCT: false, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x52, - { - controllerLogicType: ControllerTypes.RGBWWBulb, - convenientName: 'RGBWW Non-Simultaneous', - simultaneousCCT: false, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x65, - { - controllerLogicType: ControllerTypes.DimmerStrip, - convenientName: 'Dimmer', - simultaneousCCT: false, - hasColor: false, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0x93, - { - controllerLogicType: ControllerTypes.Switch, - convenientName: 'Power Socket', - simultaneousCCT: false, - hasColor: false, - hasCCT: false, - hasBrightness: false, - }, - ], - [ - 0x97, - { - controllerLogicType: ControllerTypes.Switch, - convenientName: 'Power Socket', - simultaneousCCT: false, - hasColor: false, - hasCCT: false, - hasBrightness: false, - }, - ], - [ - 0xa1, - { - controllerLogicType: ControllerTypes.RGBStrip, - convenientName: 'RGB Strip', - simultaneousCCT: false, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], - [ - 0xa2, - { - controllerLogicType: ControllerTypes.RGBStrip, - convenientName: 'RGB Strip', - simultaneousCCT: false, - hasColor: true, - hasCCT: false, - hasBrightness: true, - }, - ], -]); - -function getPrettyName(uniqueId:string, controllerLogicType:string | null):string{ - const uniqueIdTruc = uniqueId.slice(-6); - let deviceType = 'LED'; - if(controllerLogicType){ - if( isType(controllerLogicType, 'bulb') ) { - deviceType = 'Bulb'; - } else if( isType(controllerLogicType, 'strip') ){ - deviceType = 'Strip'; - }else if( isType(controllerLogicType, 'switch') ){ - deviceType = 'Switch'; - } - } - return `${deviceType} ${uniqueIdTruc}`; -} - -function isType(a,b){ - return a.toLowerCase().indexOf(b) > -1; -} - -export { lightTypesMap, getPrettyName }; \ No newline at end of file diff --git a/src/magichome-interface/Network.ts b/src/magichome-interface/Network.ts deleted file mode 100644 index d917523..0000000 --- a/src/magichome-interface/Network.ts +++ /dev/null @@ -1,38 +0,0 @@ -import Os from 'os'; - -export class Network { - static masks(cidr: string): { [key: string]: string } { - const subnet = parseInt(cidr.split('/').pop() || '24', 10); - const ipaddress = (cidr.split('/').shift() || '').split('.').map((b) => parseInt(b, 10)); - const masks: number[] | undefined = (`${('1').repeat(subnet)}${'0'.repeat(32 - subnet)}`).match(/.{1,8}/g)?.map((b) => parseInt(b, 2)); - const inverted = masks?.map((b) => b ^ 255); // eslint-disable-line no-bitwise - const base = ipaddress.map((block: number, index: number) => block & masks![index]); // eslint-disable-line no-bitwise - const broadcast = base.map((block: number, index: number) => block | inverted![index]); // eslint-disable-line no-bitwise - return { - base: base.join('.'), - broadcast: broadcast.join('.'), - }; - } - - static network(): string[] { - const ifaces: NodeJS.Dict = Os.networkInterfaces(); - const results: string[] = []; - Object.keys(ifaces).forEach((ifname: string) => { - ifaces[ifname]!.forEach((iface: Os.NetworkInterfaceInfo) => { - if (iface.family !== 'IPv4' || iface.internal !== false) { - return; - } - if (results.indexOf(iface.address) === -1) { - results.push(`${iface.cidr}`); - } - }); - }); - return results; - } - - static subnets(): { [key: string]: string }[] { - const network: string[] = Network.network(); - const masks: { [key: string]: string }[] = network.map((n) => Network.masks(n)); - return masks; - } -} \ No newline at end of file diff --git a/src/magichome-interface/Transport.ts b/src/magichome-interface/Transport.ts deleted file mode 100644 index b5c1429..0000000 --- a/src/magichome-interface/Transport.ts +++ /dev/null @@ -1,163 +0,0 @@ -import net from 'net'; -import Queue from 'promise-queue'; -import { checksum } from './utils'; -import type { PlatformConfig } from 'homebridge'; -import { getLogs } from '../logs'; - -const COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0x81, 0x8a, 0x8b]); - -const PORT = 5577; - -function wait(emitter: net.Socket, eventName: string, timeout: number) { - - return new Promise((resolve, reject) => { - let complete = false; - - const waitTimeout: any = setTimeout(() => { - complete = true; // mark the job as done - resolve(null); - }, timeout); - - // listen for the first event, then stop listening (once) - emitter.once(eventName, (args: any ) => { - clearTimeout(waitTimeout); // stop the timeout from executing - - if (!complete) { - complete = true; // mark the job as done - resolve(args); - } - }); - - emitter.once('close', () => { - clearTimeout(waitTimeout); // stop the timeout from executing - - // if the socket closed before we resolved the promise, reject the promise - if (!complete) { - complete = true; - reject(null); - } - }); - - // handle the first error and reject the promise - emitter.on('error', (e) => { - clearTimeout(waitTimeout); // stop the timeout from executing - - if (!complete) { - complete = true; - reject(e); - } - }); - - }); -} - -export class Transport { - logs = getLogs(); - host: any; - socket: any; - queue: any; - /** - * @param {string} host - hostname - * @param {number} timeout - connection timeout (in seconds) - */ - constructor(host: any, public readonly config: PlatformConfig) { - this.host = host; - this.socket = null; - this.queue = new Queue(1, Infinity); // 1 concurrent, infinite size - } - - async connect(fn: any, _timeout = 200) { - const options = { - host: this.host, - port: PORT, - timeout: _timeout, - }; - - let result; - try { - this.socket = net.connect(options); - await wait(this.socket, 'connect', _timeout = 200); - result = await fn(); - return result; - } catch (e) { - const { code, address, port } = e; - if(code){ - // No need to show error here, shown upstream - // this.log.debug(`Unable to connect to ${address} ${port} (code: ${code})`); - } else { - this.logs.error('transport.ts error:', e); - } - } finally { - this.socket.end(); - this.socket.destroy(); - - } - - return null; - } - - disconnect() { - this.socket.end(); - this.socket = null; - } - - async send(buffer: any, useChecksum = true, _timeout = 2000) { - return this.queue.add(async () => ( - this.connect(async () => { - await this.write(buffer, useChecksum, _timeout); - return this.read(_timeout); - }) - )); - } - - async write(buffer: any, useChecksum = true, _timeout = 200) { - let sent; - if(useChecksum){ - - const chk = checksum(buffer); - const payload = Buffer.concat([buffer, Buffer.from([chk])]); - sent = this.socket.write(payload, useChecksum, _timeout); - - } else { - sent = this.socket.write(buffer, useChecksum, _timeout); - } - - // wait for drain event which means all data has been sent - if (sent !== true) { - await wait(this.socket, 'drain', _timeout); - } - } - - async read(_timeout = 200) { - const data = await wait(this.socket, 'data', _timeout); - return data; - } - - async getState(_timeout = 500){ - try { - const data = await this.send(COMMAND_QUERY_STATE, true, _timeout); - if (data == null) { - return null; - } - return { - - debugBuffer: data, - controllerHardwareVersion: data.readUInt8(1), - isOn: data.readUInt8(2) === 0x23, - RGB: { - red: data.readUInt8(6), - green: data.readUInt8(7), - blue: data.readUInt8(8), - }, - whiteValues: { - warmWhite: data.readUInt8(9), - coldWhite: data.readUInt8(11), - }, - controllerFirmwareVersion: data.readUInt8(10), - - }; - } catch (error) { - this.logs.debug('Transport getState() error:', error); - } - } -} \ No newline at end of file diff --git a/src/magichome-interface/types.ts b/src/magichome-interface/types.ts index 9e025ca..7e014e0 100644 --- a/src/magichome-interface/types.ts +++ b/src/magichome-interface/types.ts @@ -36,6 +36,6 @@ export interface MagicHomeAccessory extends PlatformAccessory { displayName: string; restartsSinceSeen: number, pendingRegistration?: boolean; - cachedController: BaseController; + cachedInformation; } } \ No newline at end of file diff --git a/src/platform.ts b/src/platform.ts index df2e888..888bac3 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -12,30 +12,27 @@ import { PlatformConfig, } from 'homebridge'; -import { ControllerGenerator } from 'magichome-platform'; -import { ICommandOptions, IDeviceAPI, IDeviceCommand, IProtoDevice } from 'magichome-platform'; +import { ICommandOptions, IDeviceAPI, IDeviceCommand, IProtoDevice, ControllerGenerator } from 'magichome-platform'; - -import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -import { MagicHomeAccessory, ControllerTypes } from './magichome-interface/types'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +import { MagicHomeAccessory } from './magichome-interface/types'; import { BaseController } from 'magichome-platform/dist/DeviceControllers/BaseController'; //const NEW_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0x81, 0x8a, 0x8b]); //const LEGACY_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0xEF, 0x01, 0x77]); +import { AccessoryGenerator } from './AccessoryGenerator'; /** */ -const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; +const controllerGenerator = new ControllerGenerator(); + +const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; let hap: HAP; -let Accessory: typeof PlatformAccessory; -export = (api: API) => { - hap = api.hap; - Accessory = api.platformAccessory; +// export = (api: API) => { - api.registerPlatform(PLATFORM_NAME, HomebridgeMagichomeDynamicPlatform); -}; +// }; /** @@ -43,29 +40,30 @@ export = (api: API) => { * This class is the main constructor for your plugin, this is where you should * parse the user config and discover/register accessories with Homebridge. */ -class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { +export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { private log; private readonly api: API; // this is used to track restored cached accessories + public count = 1; private periodicDiscovery: NodeJS.Timeout | null = null; public readonly config: PlatformConfig; + public readonly accessoriesFromDiskMap: Map = new Map(); + public readonly accessoriesActive: MagicHomeAccessory[] = []; - public readonly accessories: MagicHomeAccessory[] = []; - private readonly controllerGenerator: ControllerGenerator; constructor( hbLogger: Logging, config: PlatformConfig, api: API, ) { - - this.controllerGenerator = new ControllerGenerator(); - this.log = new Logs(hbLogger, this.config.advancedOptions.logLevel); - + hap = api.hap; + this.config = config; + // this.log = new Logs(hbLogger, this.config.advancedOptions.logLevel); +this.log = new Logs(hbLogger, config.advancedOptions.logLevel); this.api = api; //this.logs = getLogger(); @@ -79,19 +77,10 @@ class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { api.on(APIEvent.DID_FINISH_LAUNCHING, () => { this.log.debug('Homebridge Magichome Dynamic Platform didFinishLaunching'); - this.initializePlatforn(); + this.initializePlatform(); }); } - async initializePlatforn() { - - this.count = 1; - await this.discoverDevices().then(devices => { - - }); - - this.periodicDiscovery = setInterval(() => await this.discoverDevices(), 30000); - } /** * This function is invoked when homebridge restores cached accessories from disk at startup. @@ -99,440 +88,40 @@ class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { */ configureAccessory(accessory: MagicHomeAccessory) { - this.log.debug('%o - Loading accessory from cache...', this.count++, accessory.context.controller.); + this.log.debug('%o - Loading accessory from cache...', this.accessoriesActive.length, accessory.context.displayName); // set cached accessory as not recently seen // if found later to be a match with a discovered device, will change to true - accessory.context.device.restartsSinceSeen++; - accessory.context.pendingRegistration = true; - // add the restored accessory to the accessories cache so we can track if it has already been registered - this.accessories.push(accessory); + // accessory.context.scansSinceSeen++; + // accessory.context.pendingRegistration = true; + // // add the restored accessory to the accessories cache so we can track if it has already been registered + const homebridgeUUID = accessory.UUID; + this.accessoriesFromDiskMap[homebridgeUUID] = accessory; } /** - * Accessories are added by one of three Methods: - * Method One: New devices that were seen after scanning the network and are registered for the first time - * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies - * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user - */ - async discoverDevices(): Promise> { - - return new Promise>(async (resolve, reject) => { - const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; - const pendingUpdate = new Set(); - const recentlyRegisteredDevices = new Set(); - - let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - - let devicesDiscovered: Map = await this.controllerGenerator.discoverControllers(); - // let discover = new Discover(this.log, this.config); - - while (!devicesDiscovered && scans < 5) { - this.log.debug('( Scan: %o ) Discovered zero devices... rescanning...', scans + 1); - devicesDiscovered = await this.controllerGenerator.discoverControllers(); - scans++; - } - - // discover = null; - if (!devicesDiscovered) { - this.log.debug('\nDiscovered zero devices!\n'); - } else { - this.log.debug('\nDiscovered %o devices.\n', 'FIX ME'); - resolve(devicesDiscovered) - } - }); - } - - tempFunction() { - // loop over the discovered devices and register each one if it has not already been registered - devicesDiscovered.forEach(controller => { - - - let existingAccessory: MagicHomeAccessory = null; - try { - const { protoDevice: { uniqueId, ipAddress, modelNumber }, deviceState, deviceAPI } = controller.getCachedDeviceInformation(); - - existingAccessory = this.accessories.find(accessory => accessory.UUID === uniqueId); - - if (!existingAccessory) { - if (!this.createNewAccessory(controller, uniqueId)) { - continue; - } - recentlyRegisteredDevices.add(uniqueId); - registeredDevices++; - newDevices++; - - } else { - - } - - } catch (error) { - this.log.error('[discovered+cached] platform.ts discoverDevices() accessory creation has thrown the following error: %o', error); - this.log.error('[discovered+cached] The existingAccessory object is: ', existingAccessory); - this.log.error('[discovered+cached] The controller object is: ', controller); - } - }); - - //================================================= - // End Cached Devices // - - - //***************** Device Pruning Start *****************// - - //if config settings are enabled, devices that are no longer seen - //will be pruned, removing them from the cache. Usefull for removing - //unplugged or unresponsive accessories - - for (const accessory of this.accessories) { - try { - - //simple warning to notify user that their accessory hasn't been seen in n restarts - if (accessory.context.restartsSinceSeen > 0) { - //logic for removing blacklisted devices - - if (!this.isAllowed(accessory.context.device.uniqueId)) { - this.log.warn('Warning! Accessory: %o will be pruned as its Unique ID: %o is blacklisted or is not whitelisted.\n', - accessory.context.device.displayName, accessory.context.device.uniqueId); - try { - this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - } catch (err) { - this.log.debug('Accessory: %o count not be pruned. Likely it had never been registered.\n', - accessory.context.device.displayName, accessory.context.device.uniqueId); - } - continue; - } - - this.log.debug(`Warning! Continuing to register cached accessory "${accessory.context.device.uniqueId}" despite not being seen for ${accessory.context.device.restartsSinceSeen} restarts.`); - - // create the accessory handler - let lightAccessory: HomebridgeMagichomeDynamicPlatformAccessory = null; - try { - lightAccessory = new accessoryType[accessory.context.device.lightParameters.controllerLogicType](this, accessory, this.config); - } catch (error) { - this.log.error('[1] The controllerLogicType does not exist in accessoryType list. Did you migrate this? controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); - this.log.error('device object: ', accessory.context.device); - continue; - } - - // udpate the accessory to platform - this.api.updatePlatformAccessories([accessory]); - registeredDevices++; - unseenDevices++; - - } - - } catch (error) { - this.log.error('platform.ts discoverDevices() accessory pruning has thrown the following error: %o', error); - this.log.error('The context object is: ', accessory.context); - } - } - - this.log.debug('\nRegistered %o Magichome device(s). \nNew devices: %o \nCached devices that were seen this restart: %o' - + '\nCached devices that were not seen this restart: %o\n', - registeredDevices, - newDevices, - registeredDevices - newDevices - unseenDevices, - unseenDevices); - - - - // Discovery summary: - if (recentlyRegisteredDevices.size > 0) { - const found = recentlyRegisteredDevices.size; - const pending = Array.from(pendingUpdate).length; - const pendingStr = pending > 0 ? ` Pending update: ${pending} devices` : ''; - this.log.debug(`Discovery summary: Found ${found} devices.${pendingStr}`); - } - - this.count = 1; // reset the device logging counter - }//discoveredDevices - - prepareExistingAccessory() { - // This deviceDiscovered already exist in cache! - - // Check if cached device complies to the device model, - if (!isValidDeviceModel(existingAccessory.context.device, null)) { - //`Device "${uniqueId}" is online, but has outdated data model. Attempting to update it. - this.log.debug(`The known device "${uniqueId}" seen during discovery has outdated data model (pre v1.8.6). Rebuilding device. `, controller); - - - // ****** RECONSTRUCT DEVICE - patch existingAccessory with updated data ***** - // const initialState = await this.getInitialState(ipAddress, 10000); - //const deviceQueryData: IDeviceQueriedProps = await this.determineController(deviceDiscovered); - - // if (!initialState || !deviceQueryData) { - // this.log.error('Warning! Device type could not be determined for device: %o, this is usually due to an unresponsive device.\n Please restart homebridge. If the problem persists, ensure the device works in the "Magichome Pro" app.\n file an issue on github with an uploaded log\n', - // deviceDiscovered.uniqueId); - // continue; - // } - - // const oldName = existingAccessory.context.displayName || - // existingAccessory.context.device?.lightParameters?.convenientName || - // deviceQueryData.lightParameters.convenientName; - - existingAccessory.context.controller = controller; - // ****** RECONSTRUCT DEVICE ***** - - if (isValidDeviceModel(existingAccessory.context.device, this.log)) { - this.log.debug(`[discovered+cached] Device "${uniqueId}" successfully repaired!`); - } else { - this.log.error(`[discovered+cached] Device "${uniqueId}" was not repaired successfully. Ensure it can be controlled in the MagicHome app then restart homebridge to try again while it is online.`); - continue; - } - - } - - if (!this.registerExistingAccessory(controller, existingAccessory)) { - continue; - } - - // add to list of registered devices, so we can show a summary in the end - recentlyRegisteredDevices.add(uniqueId); - registeredDevices++; - } - - isAllowed(uniqueId): boolean { - - const blacklistedUniqueIDs = this.config.deviceManagement.blacklistedUniqueIDs; - let isAllowed = true; - try { - - if (blacklistedUniqueIDs !== undefined - && this.config.deviceManagement.blacklistOrWhitelist !== undefined) { - if (((blacklistedUniqueIDs).includes(uniqueId) - && (this.config.deviceManagement.blacklistOrWhitelist).includes('blacklist')) - || (!(blacklistedUniqueIDs).includes(uniqueId)) - && (this.config.deviceManagement.blacklistOrWhitelist).includes('whitelist')) { - isAllowed = false; - } - } - } catch (error) { - this.log.debug(error); - } - - return isAllowed; - } - - /** - * Accessory Generation Method One: UUID has not been seen before. Register new accessory. - * Accessories must only be registered once, previously created accessories - * must not be registered again to prevent "duplicate UUID" errors. - * @param deviceDiscovered - * @param generatedUUID + * Accessories are added by one of three Methods: + * Method One: New devices that were seen after scanning the network and are registered for the first time + * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies + * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user */ - async createNewAccessory(deviceDiscovered: IDeviceDiscoveredProps, generatedUUID): Promise { - const unsupportedModels: string[] = ['000-0000']; //AK001-ZJ210 is suported... - - const deviceQueryData: IDeviceQueriedProps = await this.determineController(deviceDiscovered); - - if (deviceQueryData == null) { - if (unsupportedModels.includes(deviceDiscovered.modelNumber)) { - this.log.warn('Warning! Discovered device did not respond to query. Device is in the unsupported device list.\nFile an issue on github requesting support. Details:', deviceDiscovered); - } else { - this.log.warn('Warning! Discovered device did not respond to query. This is usually due to an unresponsive device.\nPlease restart homebridge. If the problem persists, ensure the device works in the "Magichome Pro" app.\nFile an issue on github with an uploaded log.', deviceDiscovered); - } - return false; - } - //check if device is on blacklist or is not on whitelist - if (!this.isAllowed(deviceDiscovered.uniqueId)) { - this.log.warn('Warning! New device with Unique ID: %o is blacklisted or is not whitelisted.\n', - deviceDiscovered.uniqueId); - - return false; - } - // if user has oped, use unique name such as "Bulb AABBCCDD" - if (this.config.advancedOptions && this.config.advancedOptions.namesWithMacAddress) { - const uniqueIdName = getUniqueIdName(deviceDiscovered.uniqueId, deviceQueryData.lightParameters.controllerLogicType); - deviceQueryData.lightParameters.convenientName = uniqueIdName; - } - - const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; - - // set its restart prune counter to 0 as it has been seen this session - const deviceData: IDeviceProps = Object.assign({ UUID: generatedUUID, cachedIPAddress: deviceDiscovered.ipAddress, restartsSinceSeen: 0, displayName: deviceQueryData.lightParameters.convenientName }, deviceDiscovered, deviceQueryData); - accessory.context.device = deviceData; + async initializePlatform() { + // const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; + // const pendingUpdate = new Set(); + // const recentlyRegisteredDevices = new Set(); + // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - this.printDeviceInfo('Registering new accessory...!', accessory); - // link the accessory to your platform - this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - // create the accessory handler - let lightAccessory: HomebridgeMagichomeDynamicPlatformAccessory = null; - try { - lightAccessory = new accessoryType[accessory.context.device.lightParameters.controllerLogicType](this, accessory, this.config); - } catch (error) { - this.log.error('[2] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', accessory.context.device?.lightParameters?.controllerLogicType); - this.log.error('device object: ', accessory.context.device); - return false; - } - this.accessories.push(accessory); - - return true; + const accesssoryGenerator = new AccessoryGenerator(hap, this.api, this.log, this.config, this.accessoriesFromDiskMap, controllerGenerator); + await accesssoryGenerator.generateAccessories(); + // this.periodicDiscovery = setInterval(() => await this.discoverDevices(), 30000); } - /** - * Accessory Generation Method Two: UUID has been seen before. Load from cache. - * Test if seen accessory "is allowed" and that the IP address is identical - * @param deviceDiscovered - * @param existingAccessory - */ - registerExistingAccessory(deviceDiscovered, existingAccessory: MagicHomeAccessory): boolean { - - if (!this.isAllowed(existingAccessory.context.device.uniqueId)) { - this.log.warn('Warning! Accessory: %o will be pruned as its Unique ID: %o is blacklisted or is not whitelisted.\n', - existingAccessory.context.device.displayName, existingAccessory.context.device.uniqueId); - this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]); - return false; - } - - // set its restart prune counter to 0 as it has been seen this session - existingAccessory.context.device.restartsSinceSeen = 0; - - // test if the existing cached accessory ip address matches the discovered - // accessory ip address if not, replace it - const ipHasNotChanged = existingAccessory.context.device.cachedIPAddress === deviceDiscovered.ipAddress; - const { pendingRegistration } = existingAccessory.context; - const registrationComplete = !pendingRegistration; - if (registrationComplete && ipHasNotChanged) { - this.log.debug(`Device ${existingAccessory.context.device.uniqueId} already registered. Registration update not required`); - return false; - } - - if (!ipHasNotChanged) { - this.log.warn('Ip address discrepancy found for accessory: %o\n Expected ip address: %o\n Discovered ip address: %o', - existingAccessory.context.device.displayName, existingAccessory.context.device.cachedIPAddress, deviceDiscovered.ipAddress); - - // overwrite the ip address of the existing accessory to the newly disovered ip address - existingAccessory.context.device.cachedIPAddress = deviceDiscovered.ipAddress; - this.log.warn('Ip address successfully reassigned to: %o\n ', existingAccessory.context.device.cachedIPAddress); - } - - this.printDeviceInfo('Registering existing accessory...', existingAccessory); - - // create the accessory handler - let lightAccessory: HomebridgeMagichomeDynamicPlatformAccessory = null; - try { - if (!existingAccessory.context?.device?.lightParameters?.controllerLogicType || accessoryType[existingAccessory.context?.device?.lightParameters?.controllerLogicType] === undefined) { - this.log.error('[registerExistingAccessory] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', existingAccessory.context.device?.lightParameters?.controllerLogicType); - this.log.error('[registerExistingAccessory] device object: ', existingAccessory.context.device); - return false; - } - lightAccessory = new accessoryType[existingAccessory.context.device.lightParameters.controllerLogicType](this, existingAccessory, this.config); - } catch (error) { - this.log.error('[registerExistingAccessory] The controllerLogicType does not exist in accessoryType list. controllerLogicType=', existingAccessory.context.device?.lightParameters?.controllerLogicType); - this.log.error('[registerExistingAccessory] device object: ', existingAccessory.context.device); - this.log.error(error); - - return false; - } - - // udpate the accessory to your platform - this.api.updatePlatformAccessories([existingAccessory]); - existingAccessory.context.pendingRegistration = false; - return true; + sanitizeConfig() { + //recursive config sanitation } - printDeviceInfo(message: string, accessory: MagicHomeAccessory) { - this.log.info('%o - ' + message + - '\nDisplay Name: %o \nController Logic Type: %o \nModel: %o \nUnique ID: %o \nIP-Address: %o \nHardware Version: %o \nFirmware Version: %o \n', - this.count++, - accessory.context.device.displayName, - accessory.context.device.lightParameters?.controllerLogicType, - accessory.context.device.modelNumber, - accessory.context.device.uniqueId, - accessory.context.device.ipAddress, - accessory.context.device.controllerHardwareVersion?.toString(16), - accessory.context.device.controllerFirmwareVersion?.toString(16)); - } - - async send(transport, command: number[], useChecksum = true, _timeout = 200) { - const buffer = Buffer.from(command); - - const output = await transport.send(buffer, useChecksum, _timeout); - this.log.debug('Recived the following response', output); - - } //send - - static isValidDeviceModel(_device: IDeviceProps, logger): boolean { - const device = cloneDeep(_device); - try { - const { lightParameters } = device || {}; - - const rootProps = ['UUID', 'cachedIPAddress', 'restartsSinceSeen', 'displayName', 'ipAddress', 'uniqueId', 'modelNumber', 'lightParameters', 'controllerHardwareVersion', 'controllerFirmwareVersion']; - const lightProps = ['controllerLogicType', 'convenientName', 'simultaneousCCT', 'hasColor', 'hasBrightness']; - - const missingRootProps = rootProps.filter(k => device[k] === undefined || device[k] == null); - const missingLightProps = lightProps.filter(k => lightParameters[k] === undefined || lightParameters[k] == null); - - const missingProps = [...missingRootProps, ...missingLightProps]; - - // special case: props that can be null: 'lastKnownState' - if (device.lastKnownState === undefined) { - missingProps.push('lastKnownState'); - } - - if (!Object.values(ControllerTypes).includes(lightParameters.controllerLogicType)) { - if (logger) { - logger.error(`[isValidDeviceModel] The ContollerLogicType "${lightParameters.controllerLogicType}" is unknown.`); - } - return false; - } - - - if (missingProps.length > 0) { - if (logger) { - logger.error('[isValidDeviceModel] unable to validate device model. Missing properties: ', missingProps); - logger.debug('\nThree things are certain:\nDeath, taxes and lost data.\nGuess which has occurred.'); - } - return false; - } - - return true; - } catch (err) { - return false; - } - - } - - addAccessory(name: string) { - this.log.info("Adding new accessory with name %s", name); - - // uuid must be generated from a unique but not changing data source, name should not be used in the most cases. But works in this specific example. - const uuid = hap.uuid.generate(name); - const accessory = new Accessory(name, uuid); - - accessory.addService(hap.Service.Lightbulb, "Test Light"); - - this.configureAccessory(accessory); // abusing the configureAccessory here - - this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]); - } - - removeAccessories() { - // we don't have any special identifiers, we just remove all our accessories - - this.log.info("Removing all accessories"); - - this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, this.accessories); - this.accessories.splice(0, this.accessories.length); // clear out the array - } - - createHttpService() { - this.requestServer = http.createServer(this.handleRequest.bind(this)); - this.requestServer.listen(18081, () => this.log.info("Http server listening on 18081...")); - } - - private handleRequest(request: IncomingMessage, response: ServerResponse) { - if (request.url === "/add") { - this.addAccessory(new Date().toISOString()); - } else if (request.url === "/remove") { - this.removeAccessories(); - } - - response.writeHead(204); // 204 No content - response.end(); - } }//ZackneticMagichomePlatform class \ No newline at end of file diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index d40b212..712ec23 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -1,16 +1,13 @@ -import { CharacteristicEventTypes } from 'homebridge'; +import { API, CharacteristicEventTypes } from 'homebridge'; import type { Service, PlatformConfig, PlatformAccessory, CharacteristicValue, - CharacteristicSetCallback, CharacteristicGetCallback, + CharacteristicSetCallback, CharacteristicGetCallback, HAP, } from 'homebridge'; import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './magichome-interface/utils'; -import { HomebridgeMagichomeDynamicPlatform } from './platform'; -import { Transport } from './magichome-interface/Transport'; import { getLogs } from './logs'; -import { MagicHomeAccessory, IDeviceProps } from './magichome-interface/types'; +import { MagicHomeAccessory } from './magichome-interface/types'; +import { BaseController, ICommandOptions } from 'magichome-platform'; -const COMMAND_POWER_ON = [0x71, 0x23, 0x0f]; -const COMMAND_POWER_OFF = [0x71, 0x24, 0x0f]; const animations = { none: { name: 'none', brightnessInterrupt: true, hueSaturationInterrupt: true }, }; @@ -24,8 +21,6 @@ const INTRA_MESSAGE_TIME = 20; */ export class HomebridgeMagichomeDynamicPlatformAccessory { protected service: Service; - protected myDevice: IDeviceProps = this.accessory.context.device; - protected transport = new Transport(this.myDevice.cachedIPAddress, this.config); protected colorWhiteThreshold = this.config.whiteEffects.colorWhiteThreshold; protected colorWhiteThresholdSimultaniousDevices = this.config.whiteEffects.colorWhiteThresholdSimultaniousDevices; protected colorOffThresholdSimultaniousDevices = this.config.whiteEffects.colorOffThresholdSimultaniousDevices; @@ -58,41 +53,50 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { CCT: 0, } + + //================================================= // Start Constructor // constructor( - protected readonly platform: HomebridgeMagichomeDynamicPlatform, + protected readonly hap: HAP, + protected readonly api: API, protected readonly accessory: MagicHomeAccessory, public readonly config: PlatformConfig, + private readonly controller: BaseController, ) { - + this.hap = hap; + this.api = api; + const { + protoDevice: { uniqueId, ipAddress, modelNumber }, + deviceState: {controllerFirmwareVersion, controllerHardwareVersion}, deviceAPI: { description }, + } = controller.getCachedDeviceInformation(); // set accessory information - this.accessory.getService(this.platform.Service.AccessoryInformation)! - .setCharacteristic(this.platform.Characteristic.Manufacturer, 'MagicHome') - .setCharacteristic(this.platform.Characteristic.SerialNumber, this.myDevice.uniqueId) - .setCharacteristic(this.platform.Characteristic.Model, this.myDevice.modelNumber) - .setCharacteristic(this.platform.Characteristic.HardwareRevision, this.myDevice.controllerHardwareVersion) - .setCharacteristic(this.platform.Characteristic.FirmwareRevision, this.myDevice.controllerFirmwareVersion) //? - .getCharacteristic(this.platform.Characteristic.Identify) + this.accessory.getService(hap.Service.AccessoryInformation)! + .setCharacteristic(hap.Characteristic.Manufacturer, 'MagicHome') + .setCharacteristic(hap.Characteristic.SerialNumber, uniqueId) + .setCharacteristic(hap.Characteristic.Model, modelNumber) + .setCharacteristic(hap.Characteristic.HardwareRevision, controllerHardwareVersion.toString(16)) + .setCharacteristic(hap.Characteristic.FirmwareRevision, controllerFirmwareVersion.toString(16)) //? + .getCharacteristic(hap.Characteristic.Identify) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) .on(CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below - this.accessory.getService(this.platform.Service.AccessoryInformation)! - .addOptionalCharacteristic(this.platform.Characteristic.ConfiguredName); + this.accessory.getService(hap.Service.AccessoryInformation)! + .addOptionalCharacteristic(hap.Characteristic.ConfiguredName); // get the LightBulb service if it exists, otherwise create a new LightBulb service // you can create multiple services for each accessory - if(this.myDevice.lightParameters.hasBrightness || this.myDevice.lightParameters.hasBrightness == undefined){ + //if(this.myDevice.lightParameters.hasBrightness || this.myDevice.lightParameters.hasBrightness == undefined){ - if (this.accessory.getService(this.platform.Service.Switch)) { - this.accessory.removeService(this.accessory.getService(this.platform.Service.Switch)); + if (this.accessory.getService(hap.Service.Switch)) { + this.accessory.removeService(this.accessory.getService(hap.Service.Switch)); } - this.service = this.accessory.getService(this.platform.Service.Lightbulb) ?? this.accessory.addService(this.platform.Service.Lightbulb); - this.myDevice.lightParameters.hasBrightness = true; + this.service = this.accessory.getService(hap.Service.Lightbulb) ?? this.accessory.addService(hap.Service.Lightbulb); + //this.myDevice.lightParameters.hasBrightness = true; - this.service.getCharacteristic(this.platform.Characteristic.ConfiguredName) + this.service.getCharacteristic(hap.Characteristic.ConfiguredName) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); @@ -102,17 +106,17 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // register handlers for the Brightness Characteristic - this.service.getCharacteristic(this.platform.Characteristic.Brightness) + this.service.getCharacteristic(hap.Characteristic.Brightness) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) .on(CharacteristicEventTypes.SET, this.setBrightness.bind(this)) // SET - bind to the 'setBrightness` method below .on(CharacteristicEventTypes.GET, this.getBrightness.bind(this)); // GET - bind to the 'getBrightness` method below - if( this.myDevice.lightParameters.hasColor){ + // if( this..lightParameters.hasColor){ // register handlers for the Hue Characteristic this.logs.trace('Adding Hue characteristic to device.'); - this.service.getCharacteristic(this.platform.Characteristic.Hue) + this.service.getCharacteristic(hap.Characteristic.Hue) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) .on(CharacteristicEventTypes.SET, this.setHue.bind(this)) // SET - bind to the 'setHue` method below @@ -120,46 +124,46 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // register handlers for the Saturation Characteristic this.logs.trace('Adding Saturation characteristic to device.'); - this.service.getCharacteristic(this.platform.Characteristic.Saturation) + this.service.getCharacteristic(hap.Characteristic.Saturation) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) .on(CharacteristicEventTypes.SET, this.setSaturation.bind(this)); // SET - bind to the 'setSaturation` method below //.on(CharacteristicEventTypes.GET, this.getSaturation.bind(this)); // GET - bind to the 'getSaturation` method below // register handlers for the On/Off Characteristic - } + // } - if(this.myDevice.lightParameters.hasCCT){ - // register handlers for the Saturation Characteristic - this.logs.trace('Adding ColorTemperature characteristic to device.'); - this.service.getCharacteristic(this.platform.Characteristic.ColorTemperature) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setColorTemperature.bind(this)) // SET - bind to the 'setSaturation` method below - .on(CharacteristicEventTypes.GET, this.getColorTemperature.bind(this)); // GET - bind to the 'getSaturation` method below - } - } else { - //device is switch, register it as such - this.logs.trace('Adding Switch service to device.'); - this.service = this.accessory.getService(this.platform.Service.Switch) ?? this.accessory.addService(this.platform.Service.Switch); - this.service.getCharacteristic(this.platform.Characteristic.ConfiguredName) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); - - } + // if(this.myDevice.lightParameters.hasCCT){ + // // register handlers for the Saturation Characteristic + // this.logs.trace('Adding ColorTemperature characteristic to device.'); + // this.service.getCharacteristic(hap.Characteristic.ColorTemperature) + // .removeAllListeners(CharacteristicEventTypes.SET) + // .removeAllListeners(CharacteristicEventTypes.GET) + // .on(CharacteristicEventTypes.SET, this.setColorTemperature.bind(this)) // SET - bind to the 'setSaturation` method below + // .on(CharacteristicEventTypes.GET, this.getColorTemperature.bind(this)); // GET - bind to the 'getSaturation` method below + // } + // } else { + // //device is switch, register it as such + // this.logs.trace('Adding Switch service to device.'); + // this.service = this.accessory.getService(hap.Service.Switch) ?? this.accessory.addService(hap.Service.Switch); + // this.service.getCharacteristic(hap.Characteristic.ConfiguredName) + // .removeAllListeners(CharacteristicEventTypes.SET) + // .removeAllListeners(CharacteristicEventTypes.GET) + // .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); + + // } // register handlers for the On/Off Characteristic this.logs.trace('Adding On characteristic to device.'); - this.service.getCharacteristic(this.platform.Characteristic.On) + this.service.getCharacteristic(hap.Characteristic.On) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) .on(CharacteristicEventTypes.SET, this.setOn.bind(this)) // SET - bind to the `setOn` method below .on(CharacteristicEventTypes.GET, this.getOn.bind(this)); // GET - bind to the `getOn` method below - this.updateLocalState(); + //this.updateLocalState(); // set the service name, this is what is displayed as the default name on the Home app // in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method. - this.service.setCharacteristic(this.platform.Characteristic.Name, this.myDevice.displayName); + //this.service.setCharacteristic(hap.Characteristic.Name, this.myDevice.displayName); // this.logListeners(); @@ -174,20 +178,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setConfiguredName(value: CharacteristicValue, callback: CharacteristicSetCallback) { const name: string = value.toString(); this.logs.debug('Renaming device to %o', name); - this.myDevice.displayName = name; - this.platform.api.updatePlatformAccessories([this.accessory]); + this.accessory.displayName = name; + this.api.updatePlatformAccessories([this.accessory]); callback(null); } identifyLight() { - this.logs.info('Identifying accessory: %o!', this.myDevice.displayName); + //this.logs.info('Identifying accessory: %o!', this.myDevice.displayName); this.flashEffect(); } setHue(value: CharacteristicValue, callback: CharacteristicSetCallback) { - this.logs.debug('Setting accessory %o\'s Hue value: %o', this.myDevice.displayName, value); + //this.logs.debug('Setting accessory %o\'s Hue value: %o', this.myDevice.displayName, value); this.setColortemp = false; this.lightState.HSL.hue = value as number; this.colorCommand = true; @@ -196,7 +200,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setSaturation(value: CharacteristicValue, callback: CharacteristicSetCallback) { - this.logs.debug('Setting accessory %o\'s Saturation value: %o', this.myDevice.displayName, value); + //this.logs.debug('Setting accessory %o\'s Saturation value: %o', this.myDevice.displayName, value); this.setColortemp = false; this.lightState.HSL.saturation = value as number; this.colorCommand = true; @@ -205,7 +209,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setBrightness(value: CharacteristicValue, callback: CharacteristicSetCallback) { - this.logs.debug('Setting accessory %o\'s Brightness value: %o', this.myDevice.displayName, value); + //this.logs.debug('Setting accessory %o\'s Brightness value: %o', this.myDevice.displayName, value); this.lightState.brightness = value as number; this.colorCommand = true; this.processRequest(); @@ -213,11 +217,11 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setColorTemperature(value: CharacteristicValue, callback: CharacteristicSetCallback) { - this.logs.debug('Setting accessory %o\'s Color Temperature value: %o', this.myDevice.displayName, value); + // this.logs.debug('Setting accessory %o\'s Color Temperature value: %o', this.myDevice.displayName, value); this.setColortemp = true; this.lightState.CCT = value as number; this.colorCommand = true; - this.processRequest(); + // this.processRequest(); callback(null); } @@ -229,12 +233,11 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { }*/ setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) { - this.logs.debug('Setting accessory %o\'s On value: %o', this.myDevice.displayName, value); + // this.logs.debug('Setting accessory %o\'s On value: %o', this.myDevice.displayName, value); + callback(null); this.lightState.isOn = value as boolean; this.processRequest(); - callback(null); } - //================================================= // End Setters // @@ -244,8 +247,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getHue(callback: CharacteristicGetCallback) { const hue = this.lightState.HSL.hue; if(!this.setColortemp){ //if we are not in Color Temperature mode, allow HB to update HK with Hue values - this.logs.debug('Returning accessory %o\'s cached Hue value: %o', this.myDevice.displayName, hue); - this.updateLocalState(); //update state with actual values asynchronously + //this.logs.debug('Returning accessory %o\'s cached Hue value: %o', this.myDevice.displayName, hue); + // this.updateLocalState(); //update state with actual values asynchronously } callback(null, hue); } @@ -253,16 +256,16 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getColorTemperature(callback: CharacteristicGetCallback) { const CCT = this.lightState.CCT; if(this.setColortemp){ //if we are in Color Temperature mode, allow HB to update HK with CCT values - this.logs.debug('Returning accessory %o\'s cached Color Temperature value: %o', this.myDevice.displayName, CCT); - this.updateLocalState(); //update state with actual values asynchronously + //this.logs.debug('Returning accessory %o\'s cached Color Temperature value: %o', this.myDevice.displayName, CCT); + // this.updateLocalState(); //update state with actual values asynchronously } callback(null, CCT); //immediately return cached state to prevent laggy HomeKit UI } getBrightness(callback: CharacteristicGetCallback) { const brightness = this.lightState.brightness; - this.logs.debug('Returning accessory %o\'s cached Brightness value: %o', this.myDevice.displayName, brightness); - this.updateLocalState(); //update state with actual values asynchronously + //this.logs.debug('Returning accessory %o\'s cached Brightness value: %o', this.myDevice.displayName, brightness); + // this.updateLocalState(); //update state with actual values asynchronously callback(null, brightness); //immediately return cached state to prevent laggy HomeKit UI } @@ -274,8 +277,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getOn(callback: CharacteristicGetCallback) { const isOn = this.lightState.isOn; - this.logs.debug('Returning accessory %o\'s cached Power value: %o', this.myDevice.displayName, isOn); - this.updateLocalState(); //update state with actual values asynchronously + //this.logs.debug('Returning accessory %o\'s cached Power value: %o', this.myDevice.displayName, isOn); + // this.updateLocalState(); //update state with actual values asynchronously callback(null, isOn); //immediately return cached state to prevent laggy HomeKit UI } @@ -283,199 +286,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // End Getters // //================================================= - // Start State Get/Set // - - /** - ** @updateLocalState - * retrieve light's state object from transport class - * once values are available, update homekit with actual values - */ - async updateLocalState() { - - if( this.deviceWriteInProgress || this.deviceUpdateInProgress || this.deviceReadInProgress){ - this.logs.trace('Accessory %o already has write/update/read in progress. Skipping updateLocalState.', this.myDevice.displayName); - return; - } - - this.deviceReadInProgress = true; - - try { - let state; - let scans = 0; - while(state == null && scans <= 5){ - this.logs.debug('Retrieving accessory %o\'s current state...', this.myDevice.displayName); - state = await this.transport.getState(1000); //retrieve a state object from transport class showing light's current r,g,b,ww,cw, etc - scans++; - } - if(state == null){ - const { ipAddress, uniqueId, displayName } = this.myDevice; - this.logs.debug(`No response from device '${displayName}' (${uniqueId}) ${ipAddress}`); - this.deviceReadInProgress = false; - return; - } - this.myDevice.lastKnownState = state; - this.updateLocalRGB(state.RGB); - this.updateLocalHSL(convertRGBtoHSL(this.lightState.RGB)); - this.updateLocalWhiteValues(state.whiteValues); - this.updateLocalIsOn(state.isOn); - this.updateHomekitState(); - - } catch (error) { - this.logs.error('getState() error: ', error); - } - this.deviceReadInProgress = false; - } - - /** - ** @updateHomekitState - * send state to homekit - */ - async updateHomekitState() { - - this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - this.updateLocalBrightness(this.lightState.HSL.luminance * 2); - } - this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); - } - - updateLocalHSL(_hsl){ - this.lightState.HSL = _hsl; - } - - updateLocalRGB(_rgb){ - this.lightState.RGB = _rgb; - } - - updateLocalWhiteValues(_whiteValues){ - this.lightState.whiteValues = _whiteValues; - } - - updateLocalIsOn(_isOn){ - this.lightState.isOn = _isOn; - } - - updateLocalBrightness(_brightness){ - this.lightState.brightness = _brightness; - } - - - /** - ** @updateDeviceState - * determine RGB and warmWhite/coldWhite values from homekit's HSL - * perform different logic based on light's capabilities, detimined by "this.myDevice.lightVersion" - * - */ - async updateDeviceState(_timeout = 200) { - - //**** local variables ****\\ - const hsl = this.lightState.HSL; - const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - const brightness = this.lightState.brightness; - /* - this.logs.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - this.logs.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - */ - const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - //we default the mask to turn on color. Other values can still be set, they just wont turn on - - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - - await this.send([0x31, r, g, b, 0x00, mask, 0x0F], true, _timeout); //8th byte checksum calculated later in send() - - }//updateDeviceState - - //================================================= - // End State Get/Set // - - //================================================= - // Start Misc Tools // - - - /** - ** @calculateWhiteColor - * determine warmWhite/coldWhite values from hue - * the closer to 0/360 the weaker coldWhite brightness becomes - * the closer to 180 the weaker warmWhite brightness becomes - * the closer to 90/270 the stronger both warmWhite and coldWhite become simultaniously - */ - hueToWhiteTemperature() { - const hue = this.lightState.HSL.hue; - let multiplier = 0; - const whiteTemperature = { warmWhite: 0, coldWhite: 0 }; - - if (hue <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue - whiteTemperature.warmWhite = 255; - multiplier = ((hue / 90)); - whiteTemperature.coldWhite = Math.round((255 * multiplier)); - } else if (hue > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue - whiteTemperature.warmWhite = 255; - multiplier = (1 - (hue - 270) / 90); - whiteTemperature.coldWhite = Math.round((255 * multiplier)); - } else if (hue > 180 && hue <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue - whiteTemperature.coldWhite = 255; - multiplier = ((hue - 180) / 90); - whiteTemperature.warmWhite = Math.round((255 * multiplier)); - } else if (hue > 90 && hue <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue - whiteTemperature.coldWhite = 255; - multiplier = (1 - (hue - 90) / 90); - whiteTemperature.warmWhite = Math.round((255 * multiplier)); - } - this.lightState.whiteValues = whiteTemperature; - this.logs.trace('Calculated accessory %o\'s white values: %o from hue: %o', this.myDevice.displayName, whiteTemperature, hue); - - return whiteTemperature; - } //hueToWhiteTemperature - - cctToWhiteTemperature() { - const CCT = this.lightState.CCT - 140; - let multiplier = 0; - const whiteTemperature = { warmWhite: 0, coldWhite: 0 }; - - const threshold = 110; - if (CCT >= threshold) { - whiteTemperature.warmWhite = 127; - multiplier = (1-((CCT-threshold) / (360 - threshold))); - whiteTemperature.coldWhite = Math.round((127 * multiplier)); - } else { - whiteTemperature.coldWhite = 127; - multiplier = (CCT / threshold); - whiteTemperature.warmWhite = Math.round((127 * multiplier)); - } - this.lightState.whiteValues = whiteTemperature; - this.logs.trace('Calculated accessory %o\'s white values: %o from CCT: %o', this.myDevice.displayName, whiteTemperature, CCT); - - - return whiteTemperature; - } - - async send(command: number[], useChecksum = true, _timeout = 200) { - this.logs.trace('Sending the following command to accessory %o: %o', this.myDevice.displayName, command); - const buffer = Buffer.from(command); - const output = await this.transport.send(buffer, useChecksum, _timeout); - this.logs.trace('Received the following resonse from accessory %o: %o', this.myDevice.displayName, output); - - } //send - - cacheCurrentLightState(){ - this.logs.trace('Caching accessory %o\'s current state', this.myDevice.displayName); - this.lightStateTemporary = this.lightState; - } - - async restoreCachedLightState(){ - this.logs.trace('Restoring accessory %o\'s cached state', this.myDevice.displayName); - this.lightState = this.lightStateTemporary; - this.updateDeviceState(); - } //================================================= // End Misc Tools // @@ -501,14 +314,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { change = !change; count++; - this.updateDeviceState(); + // this.updateDeviceState(); if (count >= 20) { this.lightState.HSL.hue = 0; this.lightState.HSL.saturation = 5; this.lightState.brightness = 100; - this.updateDeviceState(); + //this.updateDeviceState(); clearInterval(interval); return; } @@ -517,7 +330,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { async stopAnimation(){ this.activeAnimation = animations.none; - // this.service2.updateCharacteristic(this.platform.Characteristic.On, false); + // this.service2.updateCharacteristic(hap.Characteristic.On, false); //clearInterval(this.interval); } @@ -532,47 +345,51 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { - processRequest(){ - if(!this.deviceUpdateInProgress){ - this.deviceUpdateInProgress = true; - setTimeout( async () => { - if (( !this.colorCommand) || !this.lightState.isOn){ //if no color command or a command to turn the light off - await this.send(this.lightState.isOn ? COMMAND_POWER_ON : COMMAND_POWER_OFF); // set the power - } else { - if((this.myDevice.controllerFirmwareVersion <= 5 && this.myDevice.controllerFirmwareVersion > 1) - || this.myDevice.controllerFirmwareVersion == 8 - || (this.myDevice.controllerFirmwareVersion == 1 && this.myDevice.modelNumber.includes('HF-LPB100-ZJ200'))){ - await this.send( COMMAND_POWER_ON ); // set the power - } - setTimeout( async () => { - await this.updateDeviceState(); // set color - }, 100); - } - this.colorCommand = false; - this.deviceUpdateInProgress = false; - }, INTRA_MESSAGE_TIME); - } - return; + async processRequest(){ + this.logs.warn(this.lightState.isOn); + + await this.controller.setOn(this.lightState.isOn); + + // if(!this.deviceUpdateInProgress){ + // this.deviceUpdateInProgress = true; + // setTimeout( async () => { + // if (( !this.colorCommand) || !this.lightState.isOn){ //if no color command or a command to turn the light off + // await this.send(this.lightState.isOn ? COMMAND_POWER_ON : COMMAND_POWER_OFF); // set the power + // } else { + // if((this.myDevice.controllerFirmwareVersion <= 5 && this.myDevice.controllerFirmwareVersion > 1) + // || this.myDevice.controllerFirmwareVersion == 8 + // || (this.myDevice.controllerFirmwareVersion == 1 && this.myDevice.modelNumber.includes('HF-LPB100-ZJ200'))){ + // await this.send( COMMAND_POWER_ON ); // set the power + // } + // setTimeout( async () => { + // await this.updateDeviceState(); // set color + // }, 100); + // } + // this.colorCommand = false; + // this.deviceUpdateInProgress = false; + // }, INTRA_MESSAGE_TIME); + // } + // return; } - /** - * This is a debug function to show the number of listeners for each .on event. - */ - logListeners() { - this.logs.warn('On set Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.On).listenerCount('set')); - this.logs.warn('Identify set Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.Identify).listenerCount('set')); - this.logs.warn('Name set Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.ConfiguredName).listenerCount('set')); - this.logs.warn('Brightness set Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.Brightness).listenerCount('set')); - this.logs.warn('Hue set Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.Hue).listenerCount('set')); - this.logs.warn('Sat set Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.Saturation).listenerCount('set')); - this.logs.warn('Manufacturer set: Listener count: ', this.service.setCharacteristic(this.platform.Characteristic.Manufacturer, null).listenerCount('set') ); - - this.logs.warn('On get Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.On).listenerCount('get')); - this.logs.warn('Identify get Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.Identify).listenerCount('get')); - this.logs.warn('Name get Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.ConfiguredName).listenerCount('get')); - this.logs.warn('Brightness get Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.Brightness).listenerCount('get')); - this.logs.warn('Hue get Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.Hue).listenerCount('get')); - this.logs.warn('Sat get Listener count: ', this.service.getCharacteristic(this.platform.Characteristic.Saturation).listenerCount('get')); - this.logs.warn('Manufacturer get: Listener count: ', this.service.setCharacteristic(this.platform.Characteristic.Manufacturer, null).listenerCount('get') ); - } + // /** + // * This is a debug function to show the number of listeners for each .on event. + // */ + // logListeners() { + // this.logs.warn('On set Listener count: ', this.service.getCharacteristic(hap.Characteristic.On).listenerCount('set')); + // this.logs.warn('Identify set Listener count: ', this.service.getCharacteristic(hap.Characteristic.Identify).listenerCount('set')); + // this.logs.warn('Name set Listener count: ', this.service.getCharacteristic(hap.Characteristic.ConfiguredName).listenerCount('set')); + // this.logs.warn('Brightness set Listener count: ', this.service.getCharacteristic(hap.Characteristic.Brightness).listenerCount('set')); + // this.logs.warn('Hue set Listener count: ', this.service.getCharacteristic(hap.Characteristic.Hue).listenerCount('set')); + // this.logs.warn('Sat set Listener count: ', this.service.getCharacteristic(hap.Characteristic.Saturation).listenerCount('set')); + // this.logs.warn('Manufacturer set: Listener count: ', this.service.setCharacteristic(hap.Characteristic.Manufacturer, null).listenerCount('set') ); + + // this.logs.warn('On get Listener count: ', this.service.getCharacteristic(hap.Characteristic.On).listenerCount('get')); + // this.logs.warn('Identify get Listener count: ', this.service.getCharacteristic(hap.Characteristic.Identify).listenerCount('get')); + // this.logs.warn('Name get Listener count: ', this.service.getCharacteristic(hap.Characteristic.ConfiguredName).listenerCount('get')); + // this.logs.warn('Brightness get Listener count: ', this.service.getCharacteristic(hap.Characteristic.Brightness).listenerCount('get')); + // this.logs.warn('Hue get Listener count: ', this.service.getCharacteristic(hap.Characteristic.Hue).listenerCount('get')); + // this.logs.warn('Sat get Listener count: ', this.service.getCharacteristic(hap.Characteristic.Saturation).listenerCount('get')); + // this.logs.warn('Manufacturer get: Listener count: ', this.service.setCharacteristic(hap.Characteristic.Manufacturer, null).listenerCount('get') ); + //} } // ZackneticMagichomePlatformAccessory class From b747ae004e9cd4ff33f50a5022de2ab7c61d90fe Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Fri, 1 Oct 2021 01:45:43 -0400 Subject: [PATCH 08/42] changes to accessory state --- package-lock.json | 11 +- package.json | 5 +- src/AccessoryGenerator.ts | 24 +-- src/magichome-interface/types.ts | 10 +- src/platformAccessory.ts | 267 +++++++++++++++---------------- 5 files changed, 167 insertions(+), 150 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e127ef..c69e2ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1703,9 +1703,9 @@ } }, "magichome-platform": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.4.tgz", - "integrity": "sha512-xmUul6J1ABCuIofh9+cVN2ZR3WSz2IcSP6Pg47G9RElnAcuQFsqVg7OJxoUvjOlO6esjGQ5Rdvd0fi/6t4jXqw==", + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.7.tgz", + "integrity": "sha512-PjULUcljCAAgHgWk8vvP+mb6D1LUY1whfZchKqfwZ1Wdf4z6PAMf8joLsfrP+kFvf/CWW0o/gnR9/cK++ZBAfQ==", "requires": { "dgram": "^1.0.1", "lodash": "^4.17.21", @@ -2082,6 +2082,11 @@ "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", "dev": true }, + "queue-promise": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/queue-promise/-/queue-promise-2.2.1.tgz", + "integrity": "sha512-C3eyRwLF9m6dPV4MtqMVFX+Xmc7keZ9Ievm3jJ/wWM5t3uVbFnGsJXwpYzZ4LaIEcX9bss/mdaKzyrO6xheRuA==" + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", diff --git a/package.json b/package.json index f8e1e2a..9bc6ba4 100644 --- a/package.json +++ b/package.json @@ -64,8 +64,9 @@ "color-convert": "^2.0.1", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", - "magichome-platform": "0.0.4", - "promise-queue": "^2.2.5" + "magichome-platform": "0.0.7", + "promise-queue": "^2.2.5", + "queue-promise": "^2.2.1" }, "devDependencies": { "@types/node": "^14.17.19", diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index c30670c..a513b77 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -1,5 +1,5 @@ import { BaseController, ControllerGenerator } from 'magichome-platform'; -import { MagicHomeAccessory } from './magichome-interface/types'; +import { IAccessoryState, MagicHomeAccessory } from './magichome-interface/types'; import { API, HAP, @@ -8,6 +8,7 @@ import { import { homekitInterface } from './magichome-interface/types'; import { config } from 'process'; +import { convertRGBtoHSL } from './magichome-interface/utils'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; @@ -76,7 +77,7 @@ export class AccessoryGenerator { const existingAccessoriesList: MagicHomeAccessory[] = []; for (const [uniqueId, controller] of Object.entries(controllers)) { - this.log.warn(controller); + // this.log.warn(controller); const homebridgeUUID = this.hap.uuid.generate(uniqueId); @@ -108,19 +109,24 @@ export class AccessoryGenerator { createNewAccessory(controller: BaseController, homebridgeUUID: string): MagicHomeAccessory { - const cachedInformation = controller.getCachedDeviceInformation(); const { - protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState, deviceAPI: { description }, - } = cachedInformation; - + protoDevice: { uniqueId }, + deviceAPI: { description }, + deviceState: {LED: { RGB, CCT, isOn}}, + } = controller.getCachedDeviceInformation(); if (!this.isAllowed(uniqueId)) { return; } + // //convert RGB to HSL + // //convert CCT to colorTemperature + // const HSL = convertRGBtoHSL(RGB) + // const + // const accessoryState: IAccessoryState = {isOn, } JUST KIDDING, DO IT AFTER INITIALIZING DEVICE + const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; - newAccessory.context = { displayName: description as string, restartsSinceSeen: 0, cachedInformation }; + newAccessory.context = { displayName: description as string, restartsSinceSeen: 0 }; try { new homekitInterface[description](this.hap, this.api, newAccessory, this.config, controller); @@ -142,7 +148,7 @@ export class AccessoryGenerator { return; } - existingAccessory.context.cachedInformation = cachedInformation; + //existingAccessory.context.cachedInformation = cachedInformation; SAME HERE try { new homekitInterface[description](this.hap, this.api, existingAccessory, this.config, controller); } catch (error) { diff --git a/src/magichome-interface/types.ts b/src/magichome-interface/types.ts index 7e014e0..af6aff9 100644 --- a/src/magichome-interface/types.ts +++ b/src/magichome-interface/types.ts @@ -10,6 +10,7 @@ import { RGBWWBulb } from '../accessories/RGBWWBulb'; import { RGBWStrip } from '../accessories/RGBWStrip'; import { RGBWWStrip } from '../accessories/RGBWWStrip'; import { CCTStrip } from '../accessories/CCTStrip'; +import { IDeviceState, IDeviceCommand, IColorCCT } from 'magichome-platform/dist/types'; export const homekitInterface = { @@ -36,6 +37,13 @@ export interface MagicHomeAccessory extends PlatformAccessory { displayName: string; restartsSinceSeen: number, pendingRegistration?: boolean; - cachedInformation; + cachedAccessoryState?: IAccessoryState; } +} + +export interface IAccessoryState extends IDeviceCommand { + isOn: boolean, + HSL: IColorHSL, + colorTemperature: number, + brightness: number, } \ No newline at end of file diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 712ec23..5e560cc 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -1,19 +1,16 @@ import { API, CharacteristicEventTypes } from 'homebridge'; import type { - Service, PlatformConfig, PlatformAccessory, CharacteristicValue, + Service, PlatformConfig, CharacteristicValue, CharacteristicSetCallback, CharacteristicGetCallback, HAP, } from 'homebridge'; import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './magichome-interface/utils'; import { getLogs } from './logs'; -import { MagicHomeAccessory } from './magichome-interface/types'; +import { IAccessoryState, MagicHomeAccessory } from './magichome-interface/types'; import { BaseController, ICommandOptions } from 'magichome-platform'; -const animations = { - none: { name: 'none', brightnessInterrupt: true, hueSaturationInterrupt: true }, -}; +import Queue from 'queue-promise'; +import { IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; - -const INTRA_MESSAGE_TIME = 20; /** * Platform Accessory * An instance of this class is created for each accessory your platform registers @@ -27,33 +24,17 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected simultaniousDevicesColorWhite = this.config.whiteEffects.simultaniousDevicesColorWhite; //protected interval; - public activeAnimation = animations.none; protected setColortemp = false; protected colorCommand = false; - protected deviceWriteInProgress = false; - protected deviceWriteRetry: any = null; - protected deviceUpdateInProgress = false; - protected deviceReadInProgress = false; + logs = getLogs(); - public lightStateTemporary= { - HSL: { hue: 255, saturation: 100, luminance: 50 }, - RGB: { red: 0, green: 0, blue: 0 }, - whiteValues: {warmWhite: 0, coldWhite: 0}, - isOn: true, - brightness: 100, - CCT: 0, - }; - - protected lightState = { - HSL: { hue: 255, saturation: 100, luminance: 50 }, - RGB: { red: 0, green: 0, blue: 0 }, - whiteValues: {warmWhite: 0, coldWhite: 0}, - isOn: true, - brightness: 100, - CCT: 0, - } + protected accessoryState: IAccessoryState; + protected accessoryStateTemporary: IAccessoryState; + + protected latestDeviceCommand: IDeviceCommand; + protected queue; //================================================= // Start Constructor // @@ -64,19 +45,51 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { public readonly config: PlatformConfig, private readonly controller: BaseController, ) { + + this.accessoryState = this.accessory.context.cachedAccessoryState; + + this.queue = new Queue({ + concurrent: 1, + interval: 1, + }); + + let tempData: IDeviceState; + + + let timeout; + this.queue.on('start', () => { + clearTimeout(timeout); + }); + + this.queue.on('end', async () => { + + timeout = setTimeout(async () => { + const options: ICommandOptions = { verifyRetries: 10, bufferMS: 0, timeoutMS: 500 }; + + this.accessoryState = await this.controller.setOn(this.accessoryState.LED.isOn, options); + }, 500); + }); + + this.queue.on('resolve', data => { + if (this.queue.size < 1) { + tempData = data; + + } + }); + this.queue.on('reject', error => {/** */ }); this.hap = hap; this.api = api; - const { - protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState: {controllerFirmwareVersion, controllerHardwareVersion}, deviceAPI: { description }, - } = controller.getCachedDeviceInformation(); + const { + protoDevice: { uniqueId, ipAddress, modelNumber }, + deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, deviceAPI: { description }, + } = controller.getCachedDeviceInformation(); // set accessory information this.accessory.getService(hap.Service.AccessoryInformation)! .setCharacteristic(hap.Characteristic.Manufacturer, 'MagicHome') .setCharacteristic(hap.Characteristic.SerialNumber, uniqueId) .setCharacteristic(hap.Characteristic.Model, modelNumber) .setCharacteristic(hap.Characteristic.HardwareRevision, controllerHardwareVersion.toString(16)) - .setCharacteristic(hap.Characteristic.FirmwareRevision, controllerFirmwareVersion.toString(16)) //? + .setCharacteristic(hap.Characteristic.FirmwareRevision, controllerFirmwareVersion.toString(16)) .getCharacteristic(hap.Characteristic.Identify) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) @@ -89,59 +102,59 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // get the LightBulb service if it exists, otherwise create a new LightBulb service // you can create multiple services for each accessory //if(this.myDevice.lightParameters.hasBrightness || this.myDevice.lightParameters.hasBrightness == undefined){ - - if (this.accessory.getService(hap.Service.Switch)) { - this.accessory.removeService(this.accessory.getService(hap.Service.Switch)); - } - this.service = this.accessory.getService(hap.Service.Lightbulb) ?? this.accessory.addService(hap.Service.Lightbulb); - //this.myDevice.lightParameters.hasBrightness = true; - this.service.getCharacteristic(hap.Characteristic.ConfiguredName) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); - - // each service must implement at-minimum the "required characteristics" for the given service type - // see https://developers.homebridge.io/#/service/Lightbulb + if (this.accessory.getService(hap.Service.Switch)) { + this.accessory.removeService(this.accessory.getService(hap.Service.Switch)); + } + this.service = this.accessory.getService(hap.Service.Lightbulb) ?? this.accessory.addService(hap.Service.Lightbulb); + //this.myDevice.lightParameters.hasBrightness = true; - // register handlers for the Brightness Characteristic - - this.service.getCharacteristic(hap.Characteristic.Brightness) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setBrightness.bind(this)) // SET - bind to the 'setBrightness` method below - .on(CharacteristicEventTypes.GET, this.getBrightness.bind(this)); // GET - bind to the 'getBrightness` method below + this.service.getCharacteristic(hap.Characteristic.ConfiguredName) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); - - // if( this..lightParameters.hasColor){ - // register handlers for the Hue Characteristic - this.logs.trace('Adding Hue characteristic to device.'); - this.service.getCharacteristic(hap.Characteristic.Hue) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setHue.bind(this)) // SET - bind to the 'setHue` method below - .on(CharacteristicEventTypes.GET, this.getHue.bind(this)); // GET - bind to the 'getHue` method below - - // register handlers for the Saturation Characteristic - this.logs.trace('Adding Saturation characteristic to device.'); - this.service.getCharacteristic(hap.Characteristic.Saturation) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setSaturation.bind(this)); // SET - bind to the 'setSaturation` method below - //.on(CharacteristicEventTypes.GET, this.getSaturation.bind(this)); // GET - bind to the 'getSaturation` method below - // register handlers for the On/Off Characteristic - - // } - - // if(this.myDevice.lightParameters.hasCCT){ - // // register handlers for the Saturation Characteristic - // this.logs.trace('Adding ColorTemperature characteristic to device.'); - // this.service.getCharacteristic(hap.Characteristic.ColorTemperature) - // .removeAllListeners(CharacteristicEventTypes.SET) - // .removeAllListeners(CharacteristicEventTypes.GET) - // .on(CharacteristicEventTypes.SET, this.setColorTemperature.bind(this)) // SET - bind to the 'setSaturation` method below - // .on(CharacteristicEventTypes.GET, this.getColorTemperature.bind(this)); // GET - bind to the 'getSaturation` method below - // } + // each service must implement at-minimum the "required characteristics" for the given service type + // see https://developers.homebridge.io/#/service/Lightbulb + + // register handlers for the Brightness Characteristic + + this.service.getCharacteristic(hap.Characteristic.Brightness) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setBrightness.bind(this)) // SET - bind to the 'setBrightness` method below + .on(CharacteristicEventTypes.GET, this.getBrightness.bind(this)); // GET - bind to the 'getBrightness` method below + + + // if( this..lightParameters.hasColor){ + // register handlers for the Hue Characteristic + this.logs.trace('Adding Hue characteristic to device.'); + this.service.getCharacteristic(hap.Characteristic.Hue) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setHue.bind(this)) // SET - bind to the 'setHue` method below + .on(CharacteristicEventTypes.GET, this.getHue.bind(this)); // GET - bind to the 'getHue` method below + + // register handlers for the Saturation Characteristic + this.logs.trace('Adding Saturation characteristic to device.'); + this.service.getCharacteristic(hap.Characteristic.Saturation) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setSaturation.bind(this)); // SET - bind to the 'setSaturation` method below + //.on(CharacteristicEventTypes.GET, this.getSaturation.bind(this)); // GET - bind to the 'getSaturation` method below + // register handlers for the On/Off Characteristic + + // } + + // if(this.myDevice.lightParameters.hasCCT){ + // // register handlers for the Saturation Characteristic + // this.logs.trace('Adding ColorTemperature characteristic to device.'); + // this.service.getCharacteristic(hap.Characteristic.ColorTemperature) + // .removeAllListeners(CharacteristicEventTypes.SET) + // .removeAllListeners(CharacteristicEventTypes.GET) + // .on(CharacteristicEventTypes.SET, this.setColorTemperature.bind(this)) // SET - bind to the 'setSaturation` method below + // .on(CharacteristicEventTypes.GET, this.getColorTemperature.bind(this)); // GET - bind to the 'getSaturation` method below + // } // } else { // //device is switch, register it as such // this.logs.trace('Adding Switch service to device.'); @@ -164,7 +177,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // set the service name, this is what is displayed as the default name on the Home app // in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method. //this.service.setCharacteristic(hap.Characteristic.Name, this.myDevice.displayName); - + // this.logListeners(); } @@ -193,33 +206,33 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setHue(value: CharacteristicValue, callback: CharacteristicSetCallback) { //this.logs.debug('Setting accessory %o\'s Hue value: %o', this.myDevice.displayName, value); this.setColortemp = false; - this.lightState.HSL.hue = value as number; + this.accessoryState.HSL.hue = value as number; this.colorCommand = true; - this.processRequest(); + // this.processRequest(); callback(null); } setSaturation(value: CharacteristicValue, callback: CharacteristicSetCallback) { //this.logs.debug('Setting accessory %o\'s Saturation value: %o', this.myDevice.displayName, value); this.setColortemp = false; - this.lightState.HSL.saturation = value as number; + this.lightState.HSL.saturation = value as number; this.colorCommand = true; - this.processRequest(); + //this.processRequest(); callback(null); } setBrightness(value: CharacteristicValue, callback: CharacteristicSetCallback) { //this.logs.debug('Setting accessory %o\'s Brightness value: %o', this.myDevice.displayName, value); - this.lightState.brightness = value as number; + this.lightState.brightness = value as number; this.colorCommand = true; - this.processRequest(); + // this.processRequest(); callback(null); } setColorTemperature(value: CharacteristicValue, callback: CharacteristicSetCallback) { // this.logs.debug('Setting accessory %o\'s Color Temperature value: %o', this.myDevice.displayName, value); this.setColortemp = true; - this.lightState.CCT = value as number; + this.lightState.CCT = value as number; this.colorCommand = true; // this.processRequest(); callback(null); @@ -232,11 +245,11 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { callback(null); }*/ - setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) { + async setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) { // this.logs.debug('Setting accessory %o\'s On value: %o', this.myDevice.displayName, value); callback(null); - this.lightState.isOn = value as boolean; - this.processRequest(); + //this.lightState.isOn = value as boolean; + await this.processRequest(value as boolean); } //================================================= // End Setters // @@ -245,8 +258,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start Getters // getHue(callback: CharacteristicGetCallback) { - const hue = this.lightState.HSL.hue; - if(!this.setColortemp){ //if we are not in Color Temperature mode, allow HB to update HK with Hue values + const hue = this.lightState.HSL.hue; + if (!this.setColortemp) { //if we are not in Color Temperature mode, allow HB to update HK with Hue values //this.logs.debug('Returning accessory %o\'s cached Hue value: %o', this.myDevice.displayName, hue); // this.updateLocalState(); //update state with actual values asynchronously } @@ -255,7 +268,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getColorTemperature(callback: CharacteristicGetCallback) { const CCT = this.lightState.CCT; - if(this.setColortemp){ //if we are in Color Temperature mode, allow HB to update HK with CCT values + if (this.setColortemp) { //if we are in Color Temperature mode, allow HB to update HK with CCT values //this.logs.debug('Returning accessory %o\'s cached Color Temperature value: %o', this.myDevice.displayName, CCT); // this.updateLocalState(); //update state with actual values asynchronously } @@ -287,7 +300,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= - + //================================================= // End Misc Tools // @@ -314,7 +327,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { change = !change; count++; - // this.updateDeviceState(); + // this.updateDeviceState(); if (count >= 20) { @@ -327,8 +340,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } }, 300); } //flashEffect - - async stopAnimation(){ + + async stopAnimation() { this.activeAnimation = animations.none; // this.service2.updateCharacteristic(hap.Characteristic.On, false); //clearInterval(this.interval); @@ -337,39 +350,15 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // End LightEffects // - protected myTimer = null - protected timestamps = [] - - protected timeOfLastRead = null; - protected timeOfLastWrite = null; - - - - async processRequest(){ - this.logs.warn(this.lightState.isOn); - - await this.controller.setOn(this.lightState.isOn); - - // if(!this.deviceUpdateInProgress){ - // this.deviceUpdateInProgress = true; - // setTimeout( async () => { - // if (( !this.colorCommand) || !this.lightState.isOn){ //if no color command or a command to turn the light off - // await this.send(this.lightState.isOn ? COMMAND_POWER_ON : COMMAND_POWER_OFF); // set the power - // } else { - // if((this.myDevice.controllerFirmwareVersion <= 5 && this.myDevice.controllerFirmwareVersion > 1) - // || this.myDevice.controllerFirmwareVersion == 8 - // || (this.myDevice.controllerFirmwareVersion == 1 && this.myDevice.modelNumber.includes('HF-LPB100-ZJ200'))){ - // await this.send( COMMAND_POWER_ON ); // set the power - // } - // setTimeout( async () => { - // await this.updateDeviceState(); // set color - // }, 100); - // } - // this.colorCommand = false; - // this.deviceUpdateInProgress = false; - // }, INTRA_MESSAGE_TIME); - // } - // return; + + async processRequest(value: boolean) { + this.queue.enqueue(() => { + const options: ICommandOptions = { verifyRetries: 0, bufferMS: 10, timeoutMS: 0 }; + this.logs.warn(this.queue.size); + + return this.controller.setOn(value, options); + }); + } // /** @@ -393,3 +382,11 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // this.logs.warn('Manufacturer get: Listener count: ', this.service.setCharacteristic(hap.Characteristic.Manufacturer, null).listenerCount('get') ); //} } // ZackneticMagichomePlatformAccessory class + +function deviceStateToAccessoryState(deviceState: IDeviceState):IAccessoryState{ + // +} + +function accessoryStateToDeviceCommand(accessoryState: IAccessoryState): IDeviceCommand{ + // +} From 603d4afb30ce117beedd077ec1bc8804b6943203 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Fri, 1 Oct 2021 13:05:12 -0400 Subject: [PATCH 09/42] somewhat working RGB --- package-lock.json | 6 +- package.json | 2 +- src/accessories/CCTStrip.ts | 8 +- src/accessories/DimmerStrip.ts | 32 ++--- src/accessories/GRBStrip.ts | 48 +++---- src/accessories/RGBStrip.ts | 48 +++---- src/accessories/RGBWBulb.ts | 96 ++++++------- src/accessories/RGBWStrip.ts | 118 ++++++++-------- src/magichome-interface/types.ts | 37 +++-- src/magichome-interface/utils.ts | 23 ++-- src/platformAccessory.ts | 228 +++++++++++++++++++------------ 11 files changed, 365 insertions(+), 281 deletions(-) diff --git a/package-lock.json b/package-lock.json index c69e2ef..337cbff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1703,9 +1703,9 @@ } }, "magichome-platform": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.7.tgz", - "integrity": "sha512-PjULUcljCAAgHgWk8vvP+mb6D1LUY1whfZchKqfwZ1Wdf4z6PAMf8joLsfrP+kFvf/CWW0o/gnR9/cK++ZBAfQ==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.8.tgz", + "integrity": "sha512-dMhkKxiKw0J1nDrzKG3v7pKLm/6FMzYNV4ZVUIrRuBqqVD1/DqGQ5g91VGou0FWXYew2ErCxWfTowAq5Mbi5Og==", "requires": { "dgram": "^1.0.1", "lodash": "^4.17.21", diff --git a/package.json b/package.json index 9bc6ba4..9f575be 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "color-convert": "^2.0.1", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", - "magichome-platform": "0.0.7", + "magichome-platform": "0.0.8", "promise-queue": "^2.2.5", "queue-promise": "^2.2.1" }, diff --git a/src/accessories/CCTStrip.ts b/src/accessories/CCTStrip.ts index 0376313..b3779c1 100644 --- a/src/accessories/CCTStrip.ts +++ b/src/accessories/CCTStrip.ts @@ -5,8 +5,8 @@ export class CCTStrip extends HomebridgeMagichomeDynamicPlatformAccessory { async updateDeviceState(_timeout = 200) { - //**** local variables ****\\ - const CCT = this.lightState.CCT; + // //**** local variables ****\\ + // const CCT = this.lightState.CCT; //we default the mask to turn on color. Other values can still be set, they just wont turn on @@ -27,11 +27,11 @@ export class CCTStrip extends HomebridgeMagichomeDynamicPlatformAccessory { // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); //this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - if (this.lightState.isOn){ + // if (this.lightState.isOn){ // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(( // (this.lightState.whiteValues.coldWhite/1.27) // + (this.lightState.whiteValues.warmWhite/1.27)), 0, 100)); - } + // } //this.cacheCurrentLightState(); } diff --git a/src/accessories/DimmerStrip.ts b/src/accessories/DimmerStrip.ts index 3ba3f42..81e32bb 100644 --- a/src/accessories/DimmerStrip.ts +++ b/src/accessories/DimmerStrip.ts @@ -2,30 +2,30 @@ import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessor export class DimmerStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - /** - ** @updateHomekitState - * send state to homekit - */ - async updateHomekitState() { + // /** + // ** @updateHomekitState + // * send state to homekit + // */ + // async updateHomekitState() { - this.lightState.brightness = this.lightState.RGB.red / 2.5; //create local constant for brightness - //this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + // this.lightState.brightness = this.lightState.RGB.red / 2.5; //create local constant for brightness + // //this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - if( this.lightState.isOn ){ - //this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); - } + // if( this.lightState.isOn ){ + // //this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); + // } - } + // } - async setColor() { + // async setColor() { - //**** local variables ****\\ - const brightness = Math.round((2.5 * this.lightState.brightness)); + // //**** local variables ****\\ + // const brightness = Math.round((2.5 * this.lightState.brightness)); - //await this.send([0x31, brightness, 0x00, 0x00, 0x03, 0x01, 0x0F]); //8th byte checksum calculated later in send() + // //await this.send([0x31, brightness, 0x00, 0x00, 0x03, 0x01, 0x0F]); //8th byte checksum calculated later in send() - }//setColor + // }//setColor } \ No newline at end of file diff --git a/src/accessories/GRBStrip.ts b/src/accessories/GRBStrip.ts index 52abc2c..4e611fc 100644 --- a/src/accessories/GRBStrip.ts +++ b/src/accessories/GRBStrip.ts @@ -2,38 +2,38 @@ import { clamp, convertHSLtoRGB } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - public eightByteProtocol = 2; - async updateDeviceState() { + // public eightByteProtocol = 2; + // async updateDeviceState() { - //**** local variables ****\\ - const hsl = this.lightState.HSL; - const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - const brightness = this.lightState.brightness; + // //**** local variables ****\\ + // const hsl = this.lightState.HSL; + // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB + // const brightness = this.lightState.brightness; - //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - //we default the mask to turn on color. Other values can still be set, they just wont turn on + // const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) + // //we default the mask to turn on color. Other values can still be set, they just wont turn on - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); + // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + // const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); + // const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); + // const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - if(this.eightByteProtocol == 0){ - // await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() - } else if(this.eightByteProtocol == 1){ - //await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); - } else if (this.eightByteProtocol == 2){ - //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - // await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() - } + // if(this.eightByteProtocol == 0){ + // // await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() + // } else if(this.eightByteProtocol == 1){ + // //await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); + // } else if (this.eightByteProtocol == 2){ + // //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; + // // await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() + // } - }//setColor + // }//setColor } \ No newline at end of file diff --git a/src/accessories/RGBStrip.ts b/src/accessories/RGBStrip.ts index c03ba19..b09973c 100644 --- a/src/accessories/RGBStrip.ts +++ b/src/accessories/RGBStrip.ts @@ -2,33 +2,33 @@ import { clamp, convertHSLtoRGB } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - public eightByteProtocol = 2; - async updateDeviceState() { + // public eightByteProtocol = 2; + // async updateDeviceState() { - //**** local variables ****\\ - const hsl = this.lightState.HSL; - const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - const brightness = this.lightState.brightness; + // //**** local variables ****\\ + // const hsl = this.lightState.HSL; + // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB + // const brightness = this.lightState.brightness; - //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - //we default the mask to turn on color. Other values can still be set, they just wont turn on + // const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) + // //we default the mask to turn on color. Other values can still be set, they just wont turn on - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); + // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + // const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); + // const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); + // const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - if(this.eightByteProtocol == 0){ - //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() - } else if(this.eightByteProtocol == 1){ - // await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); - } else if (this.eightByteProtocol == 2){ - //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() - } - }//setColor + // if(this.eightByteProtocol == 0){ + // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() + // } else if(this.eightByteProtocol == 1){ + // // await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); + // } else if (this.eightByteProtocol == 2){ + // //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; + // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() + // } + // }//setColor } \ No newline at end of file diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index deb5d42..d254173 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -2,65 +2,65 @@ import { clamp, convertHSLtoRGB } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - public eightByteProtocol = 2; - async updateDeviceState() { + // public eightByteProtocol = 2; + // async updateDeviceState() { - //**** local variables ****\\ - const hsl = this.lightState.HSL; - const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - const brightness = this.lightState.brightness; + // //**** local variables ****\\ + // const hsl = this.lightState.HSL; + // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB + // const brightness = this.lightState.brightness; - //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - let mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - //we default the mask to turn on color. Other values can still be set, they just wont turn on + // let mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) + // //we default the mask to turn on color. Other values can still be set, they just wont turn on - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - let ww = 0; + // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + // let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); + // let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); + // let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); + // let ww = 0; - //if saturation is below config set threshold or if user asks for warm white / cold white - //set all other values besides warmWhite to 0 and set the mask to white (0x0F) + // //if saturation is below config set threshold or if user asks for warm white / cold white + // //set all other values besides warmWhite to 0 and set the mask to white (0x0F) - if ((hsl.saturation < this.colorWhiteThreshold) - || (hsl.hue == 31 && hsl.saturation == 33) - || (hsl.hue == 208 && hsl.saturation == 17) - || (hsl.hue == 0 && hsl.saturation == 0)) { + // if ((hsl.saturation < this.colorWhiteThreshold) + // || (hsl.hue == 31 && hsl.saturation == 33) + // || (hsl.hue == 208 && hsl.saturation == 17) + // || (hsl.hue == 0 && hsl.saturation == 0)) { - r = 0; - g = 0; - b = 0; - ww = Math.round((255 / 100) * brightness); - mask = 0x0F; - // this.platform.log.debug('Setting warmWhite only without colors: ww:%o', ww); + // r = 0; + // g = 0; + // b = 0; + // ww = Math.round((255 / 100) * brightness); + // mask = 0x0F; + // // this.platform.log.debug('Setting warmWhite only without colors: ww:%o', ww); - } + // } - if(this.eightByteProtocol == 0){ - //await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - } else if(this.eightByteProtocol == 1){ - // await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); - } else if (this.eightByteProtocol == 2){ - //this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - //await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - } + // if(this.eightByteProtocol == 0){ + // //await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() + // } else if(this.eightByteProtocol == 1){ + // // await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); + // } else if (this.eightByteProtocol == 2){ + // //this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; + // //await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() + // } } - async updateHomekitState(){ - // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - // } else if (this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); - // } - } +// async updateHomekitState(){ +// // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); +// // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); +// // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); +// // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ +// // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); +// // } else if (this.lightState.isOn){ +// // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); +// // } +// // } -} \ No newline at end of file +// } \ No newline at end of file diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 15d0678..5d15844 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -3,78 +3,78 @@ import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessor export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - public eightByteProtocol = 2; - async updateDeviceState() { + // public eightByteProtocol = 2; + // async updateDeviceState() { - //**** local variables ****\\ - const hsl = this.lightState.HSL; - let [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - const brightness = this.lightState.brightness; - // this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + // //**** local variables ****\\ + // const hsl = this.lightState.HSL; + // let [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB + // const brightness = this.lightState.brightness; + // // this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - const mask = 0xFF; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - //we default the mask to turn on color. Other values can still be set, they just wont turn on + // const mask = 0xFF; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) + // //we default the mask to turn on color. Other values can still be set, they just wont turn on - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - let ww = 0; + // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + // let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); + // let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); + // let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); + // let ww = 0; - //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). - if ((hsl.hue == 31 && hsl.saturation == 33) || (hsl.hue == 208 && hsl.saturation == 17) || (hsl.hue == 0 && hsl.saturation == 0) || (hsl.saturation < this.colorOffThresholdSimultaniousDevices) ) { - r = 0; - g = 0; - b = 0; - ww = Math.round((255 / 100) * brightness); + // //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). + // if ((hsl.hue == 31 && hsl.saturation == 33) || (hsl.hue == 208 && hsl.saturation == 17) || (hsl.hue == 0 && hsl.saturation == 0) || (hsl.saturation < this.colorOffThresholdSimultaniousDevices) ) { + // r = 0; + // g = 0; + // b = 0; + // ww = Math.round((255 / 100) * brightness); - // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); + // // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); - //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" - //set RGB to 100% saturation and 100% brightness - //this allows brightness to only affect the white colors, creating beautiful white+color balance - //we've set the color saturation to 100% because the higher the white level the more washed out the colors become - //the white brightness effectively acts as the saturation value - } else if (hsl.saturation < this.colorWhiteThresholdSimultaniousDevices && this.simultaniousDevicesColorWhite) { + // //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" + // //set RGB to 100% saturation and 100% brightness + // //this allows brightness to only affect the white colors, creating beautiful white+color balance + // //we've set the color saturation to 100% because the higher the white level the more washed out the colors become + // //the white brightness effectively acts as the saturation value + // } else if (hsl.saturation < this.colorWhiteThresholdSimultaniousDevices && this.simultaniousDevicesColorWhite) { - [red, green, blue] = convertHSLtoRGB({hue: hsl.hue, saturation: 100, luminance: hsl.luminance}); //re-generate rgb with full saturation - r = red; - g = green; - b = blue; - ww = Math.round((255 / 100) * brightness); + // [red, green, blue] = convertHSLtoRGB({hue: hsl.hue, saturation: 100, luminance: hsl.luminance}); //re-generate rgb with full saturation + // r = red; + // g = green; + // b = blue; + // ww = Math.round((255 / 100) * brightness); - // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o', r, g, b, ww); + // // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o', r, g, b, ww); - //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs - } else { - ww = 0; - // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); - } + // //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs + // } else { + // ww = 0; + // // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); + // } - // if(this.eightByteProtocol == 0){ - // await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - // } else if(this.eightByteProtocol == 1){ - // await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); - // } else if (this.eightByteProtocol == 2){ - // this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - // await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - // } + // // if(this.eightByteProtocol == 0){ + // // await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() + // // } else if(this.eightByteProtocol == 1){ + // // await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); + // // } else if (this.eightByteProtocol == 2){ + // // this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; + // // await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() + // // } - }//setColor + // }//setColor - async updateHomekitState(){ - // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - // } else if (this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); - // } - } + // async updateHomekitState(){ + // // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + // // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); + // // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); + // // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ + // // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); + // // } else if (this.lightState.isOn){ + // // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); + // // } + // } } \ No newline at end of file diff --git a/src/magichome-interface/types.ts b/src/magichome-interface/types.ts index af6aff9..1f6c0ae 100644 --- a/src/magichome-interface/types.ts +++ b/src/magichome-interface/types.ts @@ -25,13 +25,6 @@ export const homekitInterface = { 'CCT Strip': CCTStrip, }; -export interface IColorHSL { - hue: number; - saturation: number; - luminance: number; -} - - export interface MagicHomeAccessory extends PlatformAccessory { context: { displayName: string; @@ -41,9 +34,35 @@ export interface MagicHomeAccessory extends PlatformAccessory { } } -export interface IAccessoryState extends IDeviceCommand { +export interface IAccessoryState { isOn: boolean, HSL: IColorHSL, colorTemperature: number, brightness: number, -} \ No newline at end of file +} + +export interface IAccessoryCommand { + isOn?: boolean, + HSL?: IColorHSL, + colorTemperature?: number, + brightness?: number, +} + +export interface IColorHSL { + hue?: number; + saturation?: number; + luminance?: number; +} + +/*----------------------[Constants]----------------------*/ + +export const DefaultAccessoryCommand = { + isOn: true, + HSL: { + hue: 0, + saturation: 100, + luminance: 0, + }, + colorTemperature: 0, + brightness: 100, +}; \ No newline at end of file diff --git a/src/magichome-interface/utils.ts b/src/magichome-interface/utils.ts index 2471453..a931605 100644 --- a/src/magichome-interface/utils.ts +++ b/src/magichome-interface/utils.ts @@ -1,4 +1,6 @@ import { existsSync, readFileSync } from 'fs'; +import { IColorCCT, IColorRGB } from 'magichome-platform/dist/types'; +import { IColorHSL } from './types'; export function clamp(value: number, min: number, max: number) { return Math.min(max, Math.max(min, value)); @@ -22,7 +24,7 @@ export function checksum(buffer: Uint8Array) { //================================================= // Start Convert RGBtoHSL // -export function convertRGBtoHSL({red, green, blue}) { +export function convertRGBtoHSL({ red, green, blue }) { const r = red / 255; const g = green / 255; const b = blue / 255; @@ -57,9 +59,9 @@ export function convertRGBtoHSL({red, green, blue}) { } else { s = delta / (2 - max - min); } - const HSL = {hue: h, saturation: s * 100, luminance: l * 100}; + const HSL = { hue: h, saturation: s * 100, luminance: l * 100 }; return HSL; -} +} export function hue2rgb(p: number, q: number, t: number) { if (t < 0) { @@ -70,7 +72,7 @@ export function hue2rgb(p: number, q: number, t: number) { } if (t < 1 / 6) { return p + (q - p) * 6 * t; - } + } if (t < 1 / 2) { return q; } @@ -84,10 +86,13 @@ export function hue2rgb(p: number, q: number, t: number) { //================================================= // End Convert RGBtoHSL // - + //================================================= // Start Convert HSLtoRGB // -export function convertHSLtoRGB ({hue, saturation, luminance}) { +export function convertHSLtoRGB(HSL: IColorHSL): IColorRGB { + + let RGB: IColorRGB; + const { hue, saturation, luminance } = HSL; const h = hue / 360; const s = saturation / 100; const l = 50 / 100; @@ -97,7 +102,7 @@ export function convertHSLtoRGB ({hue, saturation, luminance}) { if (s === 0) { val = l * 255; - return [val, val, val]; + RGB = {red: val, green: val, blue: val}; } if (l < 0.5) { @@ -131,8 +136,8 @@ export function convertHSLtoRGB ({hue, saturation, luminance}) { rgb[i] = val * 255; } - - return rgb; + RGB = {red: rgb[0], green: rgb[1], blue: rgb[2]}; + return RGB; } //================================================= // End Convert HSLtoRGB // diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 5e560cc..33261ba 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -5,12 +5,14 @@ import type { } from 'homebridge'; import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './magichome-interface/utils'; import { getLogs } from './logs'; -import { IAccessoryState, MagicHomeAccessory } from './magichome-interface/types'; +import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, MagicHomeAccessory } from './magichome-interface/types'; import { BaseController, ICommandOptions } from 'magichome-platform'; import Queue from 'queue-promise'; -import { IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { DefaultCommand, IDeviceCommand, IDeviceState, DeviceWriteStatus } from 'magichome-platform/dist/types'; +const { ready, pending, busy } = DeviceWriteStatus; +const BUFFER_MS = 20; /** * Platform Accessory * An instance of this class is created for each accessory your platform registers @@ -23,19 +25,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected colorOffThresholdSimultaniousDevices = this.config.whiteEffects.colorOffThresholdSimultaniousDevices; protected simultaniousDevicesColorWhite = this.config.whiteEffects.simultaniousDevicesColorWhite; - //protected interval; + + protected newAccessoryCommand: IAccessoryCommand; + protected latestDeviceCommand: IDeviceCommand; + protected setColortemp = false; - protected colorCommand = false; - - logs = getLogs(); - protected accessoryState: IAccessoryState; + protected logs = getLogs(); + + protected accessoryState: IAccessoryState = DefaultAccessoryCommand; protected accessoryStateTemporary: IAccessoryState; - - protected latestDeviceCommand: IDeviceCommand; - protected queue; + protected deviceWriteStatus = ready; + protected queue; //================================================= // Start Constructor // constructor( @@ -46,17 +49,19 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { private readonly controller: BaseController, ) { - this.accessoryState = this.accessory.context.cachedAccessoryState; - + this.accessoryState = this.accessory.context.cachedAccessoryState || DefaultAccessoryCommand; + // this.accessoryState.HSL = Object.assign( DefaultAccessoryCommand.HSL); + this.logs.warn(this.accessoryState); + //get acessory state from device + + this.queue = new Queue({ concurrent: 1, - interval: 1, + interval: 50, }); - let tempData: IDeviceState; - - let timeout; + this.queue.on('start', () => { clearTimeout(timeout); }); @@ -64,18 +69,15 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.queue.on('end', async () => { timeout = setTimeout(async () => { - const options: ICommandOptions = { verifyRetries: 10, bufferMS: 0, timeoutMS: 500 }; - - this.accessoryState = await this.controller.setOn(this.accessoryState.LED.isOn, options); + this.logs.warn('FINAL STATE', this.latestDeviceCommand); + const options: ICommandOptions = { verifyRetries: 10, bufferMS: 0, timeoutMS: 200 }; + const deviceState = await this.controller.setAllValues(this.latestDeviceCommand, options); + this.accessory.context.cachedAccessoryState = this.accessoryState; + //this.accessoryState = deviceStateToAccessoryState(deviceState); }, 500); }); - this.queue.on('resolve', data => { - if (this.queue.size < 1) { - tempData = data; - - } - }); + this.queue.on('resolve', data => {/** */ }); this.queue.on('reject', error => {/** */ }); this.hap = hap; this.api = api; @@ -205,37 +207,42 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setHue(value: CharacteristicValue, callback: CharacteristicSetCallback) { //this.logs.debug('Setting accessory %o\'s Hue value: %o', this.myDevice.displayName, value); - this.setColortemp = false; - this.accessoryState.HSL.hue = value as number; - this.colorCommand = true; - // this.processRequest(); + callback(null); + this.setColortemp = false; + + const accessoryCommand: IAccessoryCommand = {isOn: true, HSL: { hue: value as number } }; + this.processAccessoryCommand(accessoryCommand); } setSaturation(value: CharacteristicValue, callback: CharacteristicSetCallback) { //this.logs.debug('Setting accessory %o\'s Saturation value: %o', this.myDevice.displayName, value); - this.setColortemp = false; - this.lightState.HSL.saturation = value as number; - this.colorCommand = true; - //this.processRequest(); + callback(null); + this.setColortemp = false; + + + const accessoryCommand: IAccessoryCommand = {isOn: true, HSL: { saturation: value as number } }; + this.processAccessoryCommand(accessoryCommand); } setBrightness(value: CharacteristicValue, callback: CharacteristicSetCallback) { //this.logs.debug('Setting accessory %o\'s Brightness value: %o', this.myDevice.displayName, value); - this.lightState.brightness = value as number; - this.colorCommand = true; - // this.processRequest(); + callback(null); + + const accessoryCommand: IAccessoryCommand = {isOn: true, brightness: value as number }; + this.processAccessoryCommand(accessoryCommand); } setColorTemperature(value: CharacteristicValue, callback: CharacteristicSetCallback) { // this.logs.debug('Setting accessory %o\'s Color Temperature value: %o', this.myDevice.displayName, value); this.setColortemp = true; - this.lightState.CCT = value as number; - this.colorCommand = true; - // this.processRequest(); + callback(null); + + const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; + this.processAccessoryCommand(accessoryCommand); } /* @@ -248,8 +255,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { async setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) { // this.logs.debug('Setting accessory %o\'s On value: %o', this.myDevice.displayName, value); callback(null); - //this.lightState.isOn = value as boolean; - await this.processRequest(value as boolean); + + const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; + this.processAccessoryCommand(accessoryCommand); } //================================================= // End Setters // @@ -258,7 +266,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start Getters // getHue(callback: CharacteristicGetCallback) { - const hue = this.lightState.HSL.hue; + const hue = this.accessoryState.HSL.hue; if (!this.setColortemp) { //if we are not in Color Temperature mode, allow HB to update HK with Hue values //this.logs.debug('Returning accessory %o\'s cached Hue value: %o', this.myDevice.displayName, hue); // this.updateLocalState(); //update state with actual values asynchronously @@ -267,16 +275,16 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } getColorTemperature(callback: CharacteristicGetCallback) { - const CCT = this.lightState.CCT; + const colorTemperature = this.accessoryState.colorTemperature; if (this.setColortemp) { //if we are in Color Temperature mode, allow HB to update HK with CCT values //this.logs.debug('Returning accessory %o\'s cached Color Temperature value: %o', this.myDevice.displayName, CCT); // this.updateLocalState(); //update state with actual values asynchronously } - callback(null, CCT); //immediately return cached state to prevent laggy HomeKit UI + callback(null, colorTemperature); //immediately return cached state to prevent laggy HomeKit UI } getBrightness(callback: CharacteristicGetCallback) { - const brightness = this.lightState.brightness; + const brightness = this.accessoryState.brightness; //this.logs.debug('Returning accessory %o\'s cached Brightness value: %o', this.myDevice.displayName, brightness); // this.updateLocalState(); //update state with actual values asynchronously callback(null, brightness); //immediately return cached state to prevent laggy HomeKit UI @@ -289,7 +297,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { */ getOn(callback: CharacteristicGetCallback) { - const isOn = this.lightState.isOn; + const isOn = this.accessoryState.isOn; //this.logs.debug('Returning accessory %o\'s cached Power value: %o', this.myDevice.displayName, isOn); // this.updateLocalState(); //update state with actual values asynchronously callback(null, isOn); //immediately return cached state to prevent laggy HomeKit UI @@ -310,53 +318,93 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start LightEffects // flashEffect() { - this.lightState.HSL.hue = 100 as number; - this.lightState.HSL.saturation = 100 as number; + // this.lightState.HSL.hue = 100 as number; + // this.lightState.HSL.saturation = 100 as number; - let change = true; - let count = 0; + // let change = true; + // let count = 0; - const interval = setInterval(() => { + // const interval = setInterval(() => { - if (change) { - this.lightState.brightness = 0; + // if (change) { + // this.lightState.brightness = 0; - } else { - this.lightState.brightness = 100; - } + // } else { + // this.lightState.brightness = 100; + // } - change = !change; - count++; - // this.updateDeviceState(); + // change = !change; + // count++; + // // this.updateDeviceState(); - if (count >= 20) { + // if (count >= 20) { - this.lightState.HSL.hue = 0; - this.lightState.HSL.saturation = 5; - this.lightState.brightness = 100; - //this.updateDeviceState(); - clearInterval(interval); - return; - } - }, 300); + // this.lightState.HSL.hue = 0; + // this.lightState.HSL.saturation = 5; + // this.lightState.brightness = 100; + // //this.updateDeviceState(); + // clearInterval(interval); + // return; + // } + // }, 300); } //flashEffect - async stopAnimation() { - this.activeAnimation = animations.none; - // this.service2.updateCharacteristic(hap.Characteristic.On, false); - //clearInterval(this.interval); - } - //================================================= // End LightEffects // - async processRequest(value: boolean) { - this.queue.enqueue(() => { - const options: ICommandOptions = { verifyRetries: 0, bufferMS: 10, timeoutMS: 0 }; - this.logs.warn(this.queue.size); + async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { + const deviceWriteStatus = this.deviceWriteStatus; + switch (deviceWriteStatus) { + case ready: + + this.deviceWriteStatus = pending; + await this.writeStateToDevice(accessoryCommand).then((msg) => { + //error logging + }).finally(() => { + this.newAccessoryCommand = DefaultCommand; + this.deviceWriteStatus = ready; + }); + break; + + case pending: + + //this.newAccessoryCommand = Object.assign({}, this.newAccessoryCommand, accessoryCommand); + this.newAccessoryCommand.HSL = Object.assign({}, this.newAccessoryCommand.HSL, accessoryCommand.HSL); + this.logs.warn('PENDING', this.newAccessoryCommand); + break; + } + } + + private async writeStateToDevice(accessoryCommand: IAccessoryCommand): Promise { + this.newAccessoryCommand = accessoryCommand; + return new Promise((resolve, reject) => { - return this.controller.setOn(value, options); + return setTimeout(() => { + + const sanitizedAcessoryCommand = Object.assign({}, this.accessoryState, this.newAccessoryCommand); + sanitizedAcessoryCommand.HSL = Object.assign({}, this.accessoryState.HSL, this.newAccessoryCommand.HSL); + + this.logs.warn(sanitizedAcessoryCommand); + this.deviceWriteStatus = ready; + //console.log('everything is probably fine', this.deviceAPI.description, this.protoDevice.uniqueId, this.deviceState.controllerHardwareVersion.toString(16), this.deviceAPI.needsPowerCommand, this.deviceState.controllerFirmwareVersion) + + return this.prepareCommand(sanitizedAcessoryCommand).then(state => { + //set current state to state + }); + }, BUFFER_MS); + }); + } + + async prepareCommand(accessoryCommand: IAccessoryCommand) { + const deviceCommand = accessoryCommandToDeviceCommand(accessoryCommand); + this.latestDeviceCommand = deviceCommand; + + this.queue.enqueue(() => { + const options: ICommandOptions = { verifyRetries: 0, bufferMS: 0, timeoutMS: 20 }; + this.accessoryState = Object.assign(accessoryCommand); + this.logs.warn(deviceCommand); + return this.controller.setAllValues(deviceCommand, options); }); } @@ -383,10 +431,22 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //} } // ZackneticMagichomePlatformAccessory class -function deviceStateToAccessoryState(deviceState: IDeviceState):IAccessoryState{ - // -} +// function deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// // +// } + +// function accessoryStateToDeviceCommand(accessoryState: IAccessoryState): IDeviceCommand { +// // +// } + +function accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + const {isOn, HSL, colorTemperature, brightness } = accessoryCommand; + const RGB = convertHSLtoRGB(HSL); + RGB.red = Math.round((RGB.red / 100) * brightness); + RGB.green = Math.round((RGB.green / 100) * brightness); + RGB.blue = Math.round((RGB.blue / 100) * brightness); -function accessoryStateToDeviceCommand(accessoryState: IAccessoryState): IDeviceCommand{ - // + const deviceCommand: IDeviceCommand = {isOn, RGB}; + return deviceCommand; } From 723e36f34350629177b320e4ee89c69fed94391a Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Fri, 1 Oct 2021 13:39:00 -0400 Subject: [PATCH 10/42] working with on/off --- src/platformAccessory.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 33261ba..d45e712 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -69,9 +69,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.queue.on('end', async () => { timeout = setTimeout(async () => { - this.logs.warn('FINAL STATE', this.latestDeviceCommand); + this.logs.warn(this.accessory.displayName,': FINAL STATE', this.latestDeviceCommand); const options: ICommandOptions = { verifyRetries: 10, bufferMS: 0, timeoutMS: 200 }; - const deviceState = await this.controller.setAllValues(this.latestDeviceCommand, options); + let deviceState: IDeviceState; + if(this.latestDeviceCommand.isOn){ + deviceState = await this.controller.setAllValues(this.latestDeviceCommand, options); + } else { + deviceState = await this.controller.setOn(false, options); + } this.accessory.context.cachedAccessoryState = this.accessoryState; //this.accessoryState = deviceStateToAccessoryState(deviceState); }, 500); @@ -404,7 +409,11 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { const options: ICommandOptions = { verifyRetries: 0, bufferMS: 0, timeoutMS: 20 }; this.accessoryState = Object.assign(accessoryCommand); this.logs.warn(deviceCommand); - return this.controller.setAllValues(deviceCommand, options); + if(deviceCommand.isOn){ + return this.controller.setAllValues(deviceCommand, options); + } else { + return this.controller.setOn(false, options); + } }); } From cb8351640c17e7b3768f3a3498ee987b2d4a8dea Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 2 Oct 2021 00:45:04 -0400 Subject: [PATCH 11/42] function send commands --- package-lock.json | 6 +- package.json | 2 +- src/AccessoryGenerator.ts | 2 + src/accessories/RGBWBulb.ts | 88 +++++++++--------- src/accessories/RGBWStrip.ts | 134 ++++++++++++---------------- src/accessories/RGBWWBulb.ts | 142 +++++++++++++++-------------- src/accessories/RGBWWStrip.ts | 148 +++++++++++++++---------------- src/magichome-interface/utils.ts | 37 +++++++- src/platformAccessory.ts | 80 +++++++++-------- 9 files changed, 338 insertions(+), 301 deletions(-) diff --git a/package-lock.json b/package-lock.json index 337cbff..fb4ae8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1703,9 +1703,9 @@ } }, "magichome-platform": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.8.tgz", - "integrity": "sha512-dMhkKxiKw0J1nDrzKG3v7pKLm/6FMzYNV4ZVUIrRuBqqVD1/DqGQ5g91VGou0FWXYew2ErCxWfTowAq5Mbi5Og==", + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.9.tgz", + "integrity": "sha512-zbbRhPXiGMdso98i7Ifsk9RbnWH/BOQ91RmLqPLZF7RoALOTiQo+xMH6TIvLFwe9GMFpR65758DQso8Deu+66Q==", "requires": { "dgram": "^1.0.1", "lodash": "^4.17.21", diff --git a/package.json b/package.json index 9f575be..f1cd8ed 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "color-convert": "^2.0.1", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", - "magichome-platform": "0.0.8", + "magichome-platform": "0.0.9", "promise-queue": "^2.2.5", "queue-promise": "^2.2.1" }, diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index a513b77..1e496b7 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -148,6 +148,8 @@ export class AccessoryGenerator { return; } + this.log.info(existingAccessory.context.displayName); + //existingAccessory.context.cachedInformation = cachedInformation; SAME HERE try { new homekitInterface[description](this.hap, this.api, existingAccessory, this.config, controller); diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index d254173..5858172 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -1,56 +1,56 @@ -import { clamp, convertHSLtoRGB } from '../magichome-interface/utils'; +import { IColorRGB, IDeviceCommand } from 'magichome-platform/dist/types'; +import { IAccessoryCommand } from '../magichome-interface/types'; +import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - // public eightByteProtocol = 2; - // async updateDeviceState() { + + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + + const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + const {hue, saturation} = HSL; + const RGB:IColorRGB = convertHSLtoRGB(HSL); + + let {red, green, blue} = RGB, warmWhite; + + //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + + let colorMask = 0xF0; - // //**** local variables ****\\ - // const hsl = this.lightState.HSL; - // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - // const brightness = this.lightState.brightness; - - // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - - // let mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - // //we default the mask to turn on color. Other values can still be set, they just wont turn on - - // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - // let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - // let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - // let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - // let ww = 0; - // //if saturation is below config set threshold or if user asks for warm white / cold white - // //set all other values besides warmWhite to 0 and set the mask to white (0x0F) + //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + red = Math.round((red / 100) * brightness); + green = Math.round((green / 100) * brightness); + blue = Math.round((blue / 100) * brightness); + warmWhite = Math.round(2.5 * brightness); - // if ((hsl.saturation < this.colorWhiteThreshold) - // || (hsl.hue == 31 && hsl.saturation == 33) - // || (hsl.hue == 208 && hsl.saturation == 17) - // || (hsl.hue == 0 && hsl.saturation == 0)) { + if (hue == 31 && saturation == 33) { - // r = 0; - // g = 0; - // b = 0; - // ww = Math.round((255 / 100) * brightness); - // mask = 0x0F; - // // this.platform.log.debug('Setting warmWhite only without colors: ww:%o', ww); + red = 0; + green = 0; + blue = 0; + colorMask = 0x0F; + // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); + } else if (saturation < 20) { + // this.platform.log.debug('Turning off color'); + red = 0; + green = 0; + blue = 0; - // } - - // if(this.eightByteProtocol == 0){ - // //await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - // } else if(this.eightByteProtocol == 1){ - // // await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); - // } else if (this.eightByteProtocol == 2){ - // //this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - // //await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - // } + colorMask = 0x0F; + // this.platform.log.debug('Setting warmWhite and coldWhite without colors: ww:%o cw:%o', ww, cw); + } else { + warmWhite = 0; + // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); + } - } + const deviceCommand: IDeviceCommand = { isOn, RGB:{red, green, blue}, CCT: {warmWhite}, colorMask}; + return deviceCommand; + + }//setColor // async updateHomekitState(){ // // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); @@ -63,4 +63,4 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { // // } // // } -// } \ No newline at end of file +} \ No newline at end of file diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 5d15844..ebe550a 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -1,80 +1,64 @@ -import { clamp, convertHSLtoRGB, convertRGBtoHSL } from '../magichome-interface/utils'; +import { IColorRGB, IDeviceCommand } from 'magichome-platform/dist/types'; +import { IAccessoryCommand } from '../magichome-interface/types'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - // public eightByteProtocol = 2; - // async updateDeviceState() { - - // //**** local variables ****\\ - // const hsl = this.lightState.HSL; - // let [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - // const brightness = this.lightState.brightness; - // // this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - - // const mask = 0xFF; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - // //we default the mask to turn on color. Other values can still be set, they just wont turn on - - // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - // let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - // let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - // let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - // let ww = 0; - - - - - // //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). - // if ((hsl.hue == 31 && hsl.saturation == 33) || (hsl.hue == 208 && hsl.saturation == 17) || (hsl.hue == 0 && hsl.saturation == 0) || (hsl.saturation < this.colorOffThresholdSimultaniousDevices) ) { - // r = 0; - // g = 0; - // b = 0; - // ww = Math.round((255 / 100) * brightness); - - // // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); - - // //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" - // //set RGB to 100% saturation and 100% brightness - // //this allows brightness to only affect the white colors, creating beautiful white+color balance - // //we've set the color saturation to 100% because the higher the white level the more washed out the colors become - // //the white brightness effectively acts as the saturation value - // } else if (hsl.saturation < this.colorWhiteThresholdSimultaniousDevices && this.simultaniousDevicesColorWhite) { - - // [red, green, blue] = convertHSLtoRGB({hue: hsl.hue, saturation: 100, luminance: hsl.luminance}); //re-generate rgb with full saturation - // r = red; - // g = green; - // b = blue; - // ww = Math.round((255 / 100) * brightness); - - // // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o', r, g, b, ww); - - // //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs - // } else { - // ww = 0; - // // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); - // } - - // // if(this.eightByteProtocol == 0){ - // // await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - // // } else if(this.eightByteProtocol == 1){ - // // await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F]); - // // } else if (this.eightByteProtocol == 2){ - // // this.eightByteProtocol = (await this.send([0x31, r, g, b, ww, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - // // await this.send([0x31, r, g, b, ww, mask, 0x0F]); //8th byte checksum calculated later in send() - // // } - - // }//setColor - - // async updateHomekitState(){ - // // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - // // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - // // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - // // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - // // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - // // } else if (this.lightState.isOn){ - // // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); - // // } - // } + + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + + const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + const { hue, saturation } = HSL; + let RGB: IColorRGB = convertHSLtoRGB(HSL); + + let { red, green, blue } = RGB, warmWhite; + + //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + + let colorMask = 0xFF; + + //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + red = Math.round((red / 100) * brightness); + green = Math.round((green / 100) * brightness); + blue = Math.round((blue / 100) * brightness); + warmWhite = Math.round(2.5 * brightness); + + if (hue == 31 && saturation == 33) { + + red = 0; + green = 0; + blue = 0; + colorMask = 0x0F; + // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); + + } else if (saturation < 20) { + // this.platform.log.debug('Turning off color'); + red = 0; + green = 0; + blue = 0; + // this.platform.log.debug('Setting only white: ww:%o cw:%o', ww, cw); + + //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" + //set RGB to 100% saturation and 100% brightness + //this allows brightness to only affect the white colors, creating beautiful white+color balance + //we've set the color saturation to 100% because the higher the white level the more washed out the colors become + //the white brightness effectively acts as the saturation value + } else if (saturation < 50) { + + RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation + + // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); + + //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs + } else { + warmWhite = 0; + // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); + } + + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite }, colorMask }; + return deviceCommand; + } } \ No newline at end of file diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index 75df6e7..adaadf3 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -1,86 +1,98 @@ -import { clamp, convertHSLtoRGB, convertRGBtoHSL } from '../magichome-interface/utils'; +import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; +import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - async updateDeviceState(_timeout = 200) { + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + + const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + const {hue, saturation} = HSL; + const RGB:IColorRGB = convertHSLtoRGB(HSL); + const CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" + + let {red, green, blue} = RGB, {warmWhite, coldWhite} = CCT; + + //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + + let colorMask = 0xF0; - // //**** local variables ****\\ - // const hsl = this.lightState.HSL; - // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - // // const whites = this.hueToWhiteTemperature(); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - // const brightness = this.lightState.brightness; - - // // this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - - // let mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - // //we default the mask to turn on color. Other values can still be set, they just wont turn on - - // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - // let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - // let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - // let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - // let ww = Math.round(((clamp(whites.warmWhite, 0, 255) / 100) * brightness)); - // let cw = Math.round(((clamp(whites.coldWhite, 0, 255) / 100) * brightness)); - // if (hsl.hue == 31 && (hsl.saturation == 33)) { - // r = 0; - // g = 0; - // b = 0; - // ww = Math.round((255 / 100) * brightness); - // cw = 0; - // mask = 0x0F; - // //this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); - // } else if ((hsl.hue == 208 && (hsl.saturation == 17))) { - // r = 0; - // g = 0; - // b = 0; - // ww = 0; - // cw = Math.round((255 / 100) * brightness); - // mask = 0x0F; - // // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); - - // //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). - // //White colors were already calculated above - // } else if ((hsl.saturation < this.colorWhiteThreshold)) { - // r = 0; - // g = 0; - // b = 0; - // mask = 0x0F; - // // this.platform.log.debug('Setting warmWhite and coldWhite without colors: ww:%o cw:%o', ww, cw); - // } else { //else set warmWhite and coldWhite to zero. Color mask already set at top - - // ww = 0; - // cw = 0; - // //this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); + //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + red = Math.round((red / 100) * brightness); + green = Math.round((green / 100) * brightness); + blue = Math.round((blue / 100) * brightness); + warmWhite = Math.round((warmWhite / 100) * brightness); + coldWhite = Math.round((coldWhite / 100) * brightness); - // } - // await this.send([0x31, r, g, b, ww, cw, mask, 0x0F], true, _timeout); //9th byte checksum calculated later in send() + if (hue == 31 && saturation == 33) { + + red = 0; + green = 0; + blue = 0; + coldWhite = 0; + colorMask = 0x0F; + // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); + } else if (hue == 208 && saturation == 17) { + red = 0; + green = 0; + blue = 0; + warmWhite = 0; + colorMask = 0x0F; + // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); + + //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). + //White colors were already calculated above + } else if (saturation < 20) { + // this.platform.log.debug('Turning off color'); + red = 0; + green = 0; + blue = 0; + + colorMask = 0x0F; + // this.platform.log.debug('Setting warmWhite and coldWhite without colors: ww:%o cw:%o', ww, cw); + } else { + warmWhite = 0; + coldWhite = 0; + // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); + } + + const deviceCommand: IDeviceCommand = { isOn, RGB:{red, green, blue}, CCT: {warmWhite, coldWhite}, colorMask}; + return deviceCommand; }//setColor - async updateHomekitState() { - // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); + // deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + // // const accessoryState: IAccessoryState = {}; + + // // const {LED:{RGB, CCT, isOn }} = deviceState; + + // // return accessoryState; + // } + + updateDeviceState(){ + + // this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessory.isOn); + // this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.lightState.HSL.hue); + // this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.lightState.HSL.saturation); // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); + // this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.lightState.HSL.luminance * 2); // } else if (this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(((this.lightState.whiteValues.coldWhite/2.55) + (this.lightState.whiteValues.warmWhite/2.55)), 0, 100)); - // if(this.lightState.whiteValues.warmWhite>this.lightState.whiteValues.coldWhite){ - // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.coldWhite/255))); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, 0); + // this.service.updateCharacteristic(this.hap.Characteristic.Brightness,clamp(((this.lightState.whiteValues.coldWhite/2.55) + (this.lightState.whiteValues.warmWhite/2.55)), 0, 100)); + // if(this.accessoryState.colorTemperature.warmWhite>this.lightState.whiteValues.coldWhite){ + // this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.coldWhite/255))); + // this.service.updateCharacteristic(this.hap.Characteristic.Hue, 0); // } else { - // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.warmWhite/255))); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, 180); + // this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.warmWhite/255))); + // this.service.updateCharacteristic(this.hap.Characteristic.Hue, 180); // } // } - // this.cacheCurrentLightState(); } } \ No newline at end of file diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index f6ae850..79d3538 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -1,82 +1,80 @@ -import { clamp, convertHSLtoRGB, convertRGBtoHSL } from '../magichome-interface/utils'; +import { IColorRGB, IDeviceCommand } from 'magichome-platform/dist/types'; +import { IAccessoryCommand } from '../magichome-interface/types'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - - async updateDeviceState() { - - // //**** local variables ****\\ - // const hsl = this.lightState.HSL; - // let [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - // const whites = this.hueToWhiteTemperature(); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - // const brightness = this.lightState.brightness; - - // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - - // let mask = 0xFF; - - // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - // let r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - // let g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - // let b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - // let ww = Math.round(((clamp(whites.warmWhite, 0, 255) / 100) * brightness)); - // let cw = Math.round(((clamp(whites.coldWhite, 0, 255) / 100) * brightness)); - - - // if (hsl.hue == 31 && hsl.saturation == 33) { - - // r = 0; - // g = 0; - // b = 0; - // ww = Math.round((255 / 100) * brightness); - // cw = 0; - // mask = 0x0F; - // // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); - - // } else if (hsl.hue == 208 && hsl.saturation == 17) { - // r = 0; - // g = 0; - // b = 0; - // ww = 0; - // cw = Math.round((255 / 100) * brightness); - // mask = 0x0F; - // // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); - - // //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). - // //White colors were already calculated above - // } else if (hsl.saturation < this.colorOffThresholdSimultaniousDevices) { - // // this.platform.log.debug('Turning off color'); - // r = 0; - // g = 0; - // b = 0; - // // this.platform.log.debug('Setting only white: ww:%o cw:%o', ww, cw); - - // //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" - // //set RGB to 100% saturation and 100% brightness - // //this allows brightness to only affect the white colors, creating beautiful white+color balance - // //we've set the color saturation to 100% because the higher the white level the more washed out the colors become - // //the white brightness effectively acts as the saturation value - // } else if (hsl.saturation < this.colorWhiteThresholdSimultaniousDevices && this.simultaniousDevicesColorWhite) { - - // [red, green, blue] = convertHSLtoRGB({ hue: hsl.hue, saturation: 100, luminance: hsl.luminance}); //re-generate rgb with full saturation - // r = red; - // g = green; - // b = blue; - // // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); - - // //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs - // } else { - // ww = 0; - // cw = 0; - // // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); - // } - // await this.send([0x31, r, g, b, ww, cw, mask, 0x0F]); //9th byte checksum calculated later in send() - + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + + const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + const {hue, saturation} = HSL; + let RGB:IColorRGB = convertHSLtoRGB(HSL); + const CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" + + let {red, green, blue} = RGB, {warmWhite, coldWhite} = CCT; + + //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); + // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + + let colorMask = 0xFF; + + //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + red = Math.round((red / 100) * brightness); + green = Math.round((green / 100) * brightness); + blue = Math.round((blue / 100) * brightness); + warmWhite = Math.round((warmWhite / 100) * brightness); + coldWhite = Math.round((coldWhite / 100) * brightness); + + if (hue == 31 && saturation == 33) { + + red = 0; + green = 0; + blue = 0; + coldWhite = 0; + colorMask = 0x0F; + // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); + + } else if (hue == 208 && saturation == 17) { + red = 0; + green = 0; + blue = 0; + warmWhite = 0; + colorMask = 0x0F; + // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); + + //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). + //White colors were already calculated above + } else if (saturation < 20) { + // this.platform.log.debug('Turning off color'); + red = 0; + green = 0; + blue = 0; + // this.platform.log.debug('Setting only white: ww:%o cw:%o', ww, cw); + + //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" + //set RGB to 100% saturation and 100% brightness + //this allows brightness to only affect the white colors, creating beautiful white+color balance + //we've set the color saturation to 100% because the higher the white level the more washed out the colors become + //the white brightness effectively acts as the saturation value + } else if (saturation < 50) { + + RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation + + // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); + + //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs + } else { + warmWhite = 0; + coldWhite = 0; + // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); + } + + const deviceCommand: IDeviceCommand = { isOn, RGB:{red, green, blue}, CCT: {warmWhite, coldWhite}, colorMask}; + return deviceCommand; }//setColor - + async updateHomekitState() { // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); @@ -94,5 +92,5 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { // } // } } - + } \ No newline at end of file diff --git a/src/magichome-interface/utils.ts b/src/magichome-interface/utils.ts index a931605..368805f 100644 --- a/src/magichome-interface/utils.ts +++ b/src/magichome-interface/utils.ts @@ -102,7 +102,7 @@ export function convertHSLtoRGB(HSL: IColorHSL): IColorRGB { if (s === 0) { val = l * 255; - RGB = {red: val, green: val, blue: val}; + RGB = { red: val, green: val, blue: val }; } if (l < 0.5) { @@ -136,7 +136,7 @@ export function convertHSLtoRGB(HSL: IColorHSL): IColorRGB { rgb[i] = val * 255; } - RGB = {red: rgb[0], green: rgb[1], blue: rgb[2]}; + RGB = { red: rgb[0], green: rgb[1], blue: rgb[2] }; return RGB; } //================================================= @@ -157,6 +157,39 @@ export function loadJson(file: string, replacement: T): T { return parseJson(readFileSync(file).toString(), replacement); } +/** + ** @calculateWhiteColor + * determine warmWhite/coldWhite values from hue + * the closer to 0/360 the weaker coldWhite brightness becomes + * the closer to 180 the weaker warmWhite brightness becomes + * the closer to 90/270 the stronger both warmWhite and coldWhite become simultaniously + */ +export function convertHueToColorCCT(hue: number): IColorCCT { + let multiplier = 0; + const colorCCT = { warmWhite: 0, coldWhite: 0 }; + + + if (hue <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue + colorCCT.warmWhite = 255; + multiplier = ((hue / 90)); + colorCCT.coldWhite = Math.round((255 * multiplier)); + } else if (hue > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue + colorCCT.warmWhite = 255; + multiplier = (1 - (hue - 270) / 90); + colorCCT.coldWhite = Math.round((255 * multiplier)); + } else if (hue > 180 && hue <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue + colorCCT.coldWhite = 255; + multiplier = ((hue - 180) / 90); + colorCCT.warmWhite = Math.round((255 * multiplier)); + } else if (hue > 90 && hue <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue + colorCCT.coldWhite = 255; + multiplier = (1 - (hue - 90) / 90); + colorCCT.warmWhite = Math.round((255 * multiplier)); + } + + return colorCCT; +} //hueToWhiteTemperature + //Unused /* diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index d45e712..d9383d3 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -7,12 +7,12 @@ import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './magichome-interface/u import { getLogs } from './logs'; import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, MagicHomeAccessory } from './magichome-interface/types'; import { BaseController, ICommandOptions } from 'magichome-platform'; - +import { _ } from 'lodash'; import Queue from 'queue-promise'; import { DefaultCommand, IDeviceCommand, IDeviceState, DeviceWriteStatus } from 'magichome-platform/dist/types'; const { ready, pending, busy } = DeviceWriteStatus; -const BUFFER_MS = 20; +const BUFFER_MS = 50; /** * Platform Accessory * An instance of this class is created for each accessory your platform registers @@ -57,7 +57,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.queue = new Queue({ concurrent: 1, - interval: 50, + interval: 20, }); let timeout; @@ -69,10 +69,10 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.queue.on('end', async () => { timeout = setTimeout(async () => { - this.logs.warn(this.accessory.displayName,': FINAL STATE', this.latestDeviceCommand); + this.logs.warn(this.accessory.displayName, ': FINAL STATE', this.latestDeviceCommand); const options: ICommandOptions = { verifyRetries: 10, bufferMS: 0, timeoutMS: 200 }; let deviceState: IDeviceState; - if(this.latestDeviceCommand.isOn){ + if (this.latestDeviceCommand.isOn) { deviceState = await this.controller.setAllValues(this.latestDeviceCommand, options); } else { deviceState = await this.controller.setOn(false, options); @@ -183,7 +183,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //this.updateLocalState(); // set the service name, this is what is displayed as the default name on the Home app // in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method. - //this.service.setCharacteristic(hap.Characteristic.Name, this.myDevice.displayName); // this.logListeners(); @@ -196,9 +195,12 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start Setters // setConfiguredName(value: CharacteristicValue, callback: CharacteristicSetCallback) { + const name: string = value.toString(); this.logs.debug('Renaming device to %o', name); - this.accessory.displayName = name; + this.accessory.context.displayName = name; + // this.service.setCharacteristic(this.hap.Characteristic.Name, value); + this.api.updatePlatformAccessories([this.accessory]); callback(null); @@ -211,32 +213,33 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setHue(value: CharacteristicValue, callback: CharacteristicSetCallback) { - //this.logs.debug('Setting accessory %o\'s Hue value: %o', this.myDevice.displayName, value); + this.logs.warn('Setting accessory %o\'s Hue value: %o', this.accessory.context.displayName, value); callback(null); this.setColortemp = false; - const accessoryCommand: IAccessoryCommand = {isOn: true, HSL: { hue: value as number } }; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; this.processAccessoryCommand(accessoryCommand); } setSaturation(value: CharacteristicValue, callback: CharacteristicSetCallback) { - //this.logs.debug('Setting accessory %o\'s Saturation value: %o', this.myDevice.displayName, value); + this.logs.warn('Setting accessory %o\'s Saturation value: %o', this.accessory.displayName, value); callback(null); this.setColortemp = false; - const accessoryCommand: IAccessoryCommand = {isOn: true, HSL: { saturation: value as number } }; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { saturation: value as number } }; this.processAccessoryCommand(accessoryCommand); } - setBrightness(value: CharacteristicValue, callback: CharacteristicSetCallback) { - //this.logs.debug('Setting accessory %o\'s Brightness value: %o', this.myDevice.displayName, value); + async setBrightness(value: CharacteristicValue, callback: CharacteristicSetCallback) { + this.logs.warn('Setting accessory %o\'s Brightness value: %o', this.accessory.context.displayName, value); callback(null); - const accessoryCommand: IAccessoryCommand = {isOn: true, brightness: value as number }; + const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; + this.logs.error(accessoryCommand); this.processAccessoryCommand(accessoryCommand); } @@ -360,6 +363,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { const deviceWriteStatus = this.deviceWriteStatus; + this.logs.info(this.deviceWriteStatus); switch (deviceWriteStatus) { case ready: @@ -367,16 +371,16 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { await this.writeStateToDevice(accessoryCommand).then((msg) => { //error logging }).finally(() => { - this.newAccessoryCommand = DefaultCommand; + //this.newAccessoryCommand = DefaultCommand; this.deviceWriteStatus = ready; }); break; case pending: - - //this.newAccessoryCommand = Object.assign({}, this.newAccessoryCommand, accessoryCommand); - this.newAccessoryCommand.HSL = Object.assign({}, this.newAccessoryCommand.HSL, accessoryCommand.HSL); - this.logs.warn('PENDING', this.newAccessoryCommand); + _.merge(this.newAccessoryCommand, accessoryCommand); + // Object.assign(this.newAccessoryCommand, accessoryCommand); + // Object.assign(this.newAccessoryCommand.HSL, accessoryCommand.HSL); + //this.logs.warn('PENDING', this.newAccessoryCommand); break; } } @@ -386,11 +390,13 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { return new Promise((resolve, reject) => { return setTimeout(() => { + this.logs.warn(this.accessory.context.displayName, '\nthis.accessoryState: ', this.accessoryState, '\n this.newAccessoryCommand: ', this.newAccessoryCommand); + const sanitizedAcessoryCommand = _.merge({}, this.accessoryState, this.newAccessoryCommand); + // const sanitizedAcessoryCommand = Object.assign({}, this.accessoryState, this.newAccessoryCommand); + // sanitizedAcessoryCommand.HSL = Object.assign({}, this.accessoryState.HSL, this.newAccessoryCommand.HSL); + this.logs.warn('\nSanatizedCommand: ', sanitizedAcessoryCommand); - const sanitizedAcessoryCommand = Object.assign({}, this.accessoryState, this.newAccessoryCommand); - sanitizedAcessoryCommand.HSL = Object.assign({}, this.accessoryState.HSL, this.newAccessoryCommand.HSL); - - this.logs.warn(sanitizedAcessoryCommand); + //this.logs.warn(sanitizedAcessoryCommand); this.deviceWriteStatus = ready; //console.log('everything is probably fine', this.deviceAPI.description, this.protoDevice.uniqueId, this.deviceState.controllerHardwareVersion.toString(16), this.deviceAPI.needsPowerCommand, this.deviceState.controllerFirmwareVersion) @@ -402,14 +408,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } async prepareCommand(accessoryCommand: IAccessoryCommand) { - const deviceCommand = accessoryCommandToDeviceCommand(accessoryCommand); + const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); this.latestDeviceCommand = deviceCommand; this.queue.enqueue(() => { - const options: ICommandOptions = { verifyRetries: 0, bufferMS: 0, timeoutMS: 20 }; + const options: ICommandOptions = { verifyRetries: 0, bufferMS: 0, timeoutMS: 100 }; this.accessoryState = Object.assign(accessoryCommand); - this.logs.warn(deviceCommand); - if(deviceCommand.isOn){ + //this.logs.warn(deviceCommand); + if (deviceCommand.isOn) { return this.controller.setAllValues(deviceCommand, options); } else { return this.controller.setOn(false, options); @@ -418,6 +424,17 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + const RGB = convertHSLtoRGB(HSL); + RGB.red = Math.round((RGB.red / 100) * brightness); + RGB.green = Math.round((RGB.green / 100) * brightness); + RGB.blue = Math.round((RGB.blue / 100) * brightness); + + const deviceCommand: IDeviceCommand = { isOn, RGB }; + return deviceCommand; + } + // /** // * This is a debug function to show the number of listeners for each .on event. // */ @@ -449,13 +466,4 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // // // } -function accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const {isOn, HSL, colorTemperature, brightness } = accessoryCommand; - const RGB = convertHSLtoRGB(HSL); - RGB.red = Math.round((RGB.red / 100) * brightness); - RGB.green = Math.round((RGB.green / 100) * brightness); - RGB.blue = Math.round((RGB.blue / 100) * brightness); - const deviceCommand: IDeviceCommand = {isOn, RGB}; - return deviceCommand; -} From 0efbc253fc9ff340f66baaf4ea7f171909df2349 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Mon, 4 Oct 2021 10:25:32 -0400 Subject: [PATCH 12/42] update to some device state fetching --- .homebridge-dev/config.json | 2 +- package-lock.json | 117 ++++------- package.json | 3 +- src/AccessoryGenerator.ts | 24 ++- src/accessories/RGBWBulb.ts | 43 +++-- src/accessories/RGBWStrip.ts | 36 +++- src/accessories/RGBWWBulb.ts | 80 ++++---- src/accessories/RGBWWStrip.ts | 70 ++++--- src/accessories/Switch.ts | 14 +- src/index.ts | 22 --- src/magichome-interface/types.ts | 7 +- src/magichome-interface/utils.ts | 203 ++++++++++++++++--- src/platform.ts | 28 +-- src/platformAccessory.ts | 321 +++++++++++++++---------------- 14 files changed, 552 insertions(+), 418 deletions(-) diff --git a/.homebridge-dev/config.json b/.homebridge-dev/config.json index a656d42..283ce78 100644 --- a/.homebridge-dev/config.json +++ b/.homebridge-dev/config.json @@ -17,7 +17,7 @@ "platforms": [ { "platform": "homebridge-magichome-dynamic-platform", - "name": "magicHome", + "name": "MagicHome Dynamic Platform", "pruning": { "pruneMissingCachedAccessories": false, "restartsBeforeMissingAccessoriesPruned": 3, diff --git a/package-lock.json b/package-lock.json index fb4ae8c..261898b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -106,8 +106,7 @@ "@leichtgewicht/ip-codec": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", - "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==", - "dev": true + "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==" }, "@sindresorhus/is": { "version": "0.14.0", @@ -364,8 +363,7 @@ "array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, "astral-regex": { "version": "2.0.0", @@ -382,8 +380,7 @@ "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, "balanced-match": { "version": "1.0.0", @@ -401,7 +398,6 @@ "version": "3.6.3", "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.3.tgz", "integrity": "sha512-qyLU96ICCYbpOFiMCjA3aNYH5Jc83XH1YX6+EXWukyyiNXzXH2LZv8AVmGW33FceF3gfUM4jYoKX2xChtNDUnA==", - "dev": true, "requires": { "array-flatten": "^2.1.2", "deep-equal": "^2.0.5", @@ -487,7 +483,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -509,7 +504,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -519,7 +513,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -527,14 +520,12 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -656,7 +647,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "es-get-iterator": "^1.1.1", @@ -697,7 +687,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -717,7 +706,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.0.tgz", "integrity": "sha512-Nce7YLu6YCgWRvOmDBsJMo9M5/jV3lEZ5vUWnWXYmwURvPylHvq7nkDWhNmk1ZQoZZOP7oQh/S0lSxbisKOfHg==", - "dev": true, "requires": { "@leichtgewicht/ip-codec": "^2.0.1" } @@ -779,7 +767,6 @@ "version": "1.18.6", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", "integrity": "sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ==", - "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -805,7 +792,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.0", @@ -821,7 +807,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -1045,8 +1030,7 @@ "foreach": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" }, "fs-extra": { "version": "9.1.0", @@ -1076,8 +1060,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -1095,7 +1078,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -1115,7 +1097,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -1217,7 +1198,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -1225,8 +1205,7 @@ "has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" }, "has-flag": { "version": "3.0.0", @@ -1237,14 +1216,12 @@ "has-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, "has-tostringtag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -1270,6 +1247,16 @@ "source-map-support": "^0.5.19" } }, + "homebridge-lib": { + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.1.14.tgz", + "integrity": "sha512-ZtGssTd9uoKv169ChDoiMmCLdzHGtHtlAJ7zM8JM9u8Sxgm/X8LtoV+OB78m9TuHEuvmv5wdJqguYYSFycclgw==", + "requires": { + "bonjour-hap": "^3.6.3", + "chalk": "^4.1.2", + "semver": "^7.3.5" + } + }, "http-cache-semantics": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", @@ -1336,7 +1323,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, "requires": { "get-intrinsic": "^1.1.0", "has": "^1.0.3", @@ -1346,14 +1332,12 @@ "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, "is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -1363,7 +1347,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "requires": { "has-bigints": "^1.0.1" } @@ -1381,7 +1364,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -1390,8 +1372,7 @@ "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, "is-ci": { "version": "2.0.0", @@ -1406,7 +1387,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -1445,14 +1425,12 @@ "is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" }, "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", - "dev": true + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" }, "is-npm": { "version": "5.0.0", @@ -1470,7 +1448,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -1491,7 +1468,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -1500,14 +1476,12 @@ "is-set": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" }, "is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -1516,7 +1490,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -1525,7 +1498,6 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", - "dev": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -1543,14 +1515,12 @@ "is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" }, "is-weakset": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", - "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==", - "dev": true + "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==" }, "is-yarn-global": { "version": "0.3.0", @@ -1561,8 +1531,7 @@ "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, "isexe": { "version": "2.0.0", @@ -1685,7 +1654,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -1703,9 +1671,9 @@ } }, "magichome-platform": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.9.tgz", - "integrity": "sha512-zbbRhPXiGMdso98i7Ifsk9RbnWH/BOQ91RmLqPLZF7RoALOTiQo+xMH6TIvLFwe9GMFpR65758DQso8Deu+66Q==", + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.11.tgz", + "integrity": "sha512-xC7cNbXxCQnUS8K6N3UnXwthRBkGgcS1dTUFo750ClmzpQ36TkJRplE6QNeWOSb9iBBA5G2mEO9uxBWM3W3g0g==", "requires": { "dgram": "^1.0.1", "lodash": "^4.17.21", @@ -1781,7 +1749,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.3.tgz", "integrity": "sha512-TzxgGSLRLB7tqAlzjgd2x2ZE0cDsGFq4rs9W4yE5xp+7hlRXeUQGtXZsTGfGw2FwWB45rfe8DtXMYBpZGMLUng==", - "dev": true, "requires": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -1790,8 +1757,7 @@ "multicast-dns-service-types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, "natural-compare": { "version": "1.4.0", @@ -1868,14 +1834,12 @@ "object-inspect": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" }, "object-is": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -1884,14 +1848,12 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", @@ -2126,7 +2088,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -2195,7 +2156,6 @@ "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -2236,7 +2196,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -2313,7 +2272,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -2323,7 +2281,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -2396,8 +2353,7 @@ "thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, "to-readable-stream": { "version": "1.0.0", @@ -2491,7 +2447,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has-bigints": "^1.0.1", @@ -2604,7 +2559,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -2617,7 +2571,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, "requires": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -2629,7 +2582,6 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", - "dev": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -2703,8 +2655,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yn": { "version": "3.1.1", diff --git a/package.json b/package.json index f1cd8ed..3aaacf8 100644 --- a/package.json +++ b/package.json @@ -62,9 +62,10 @@ ], "dependencies": { "color-convert": "^2.0.1", + "homebridge-lib": "^5.1.14", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", - "magichome-platform": "0.0.9", + "magichome-platform": "0.0.11", "promise-queue": "^2.2.5", "queue-promise": "^2.2.1" }, diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 1e496b7..ae43a1e 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -7,8 +7,6 @@ import { } from 'homebridge'; import { homekitInterface } from './magichome-interface/types'; -import { config } from 'process'; -import { convertRGBtoHSL } from './magichome-interface/utils'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; @@ -35,11 +33,13 @@ export class AccessoryGenerator { public async generateAccessories() { this.log.warn('started to generate accessories'); return await this.controllerGenerator.discoverControllers().then(async controllers => { - return this.discoverAccessories(controllers); + const accessories = this.discoverAccessories(controllers); + return accessories; }).catch(error => { this.log.error(error); }); + } /** @@ -81,12 +81,12 @@ export class AccessoryGenerator { const homebridgeUUID = this.hap.uuid.generate(uniqueId); - if (this.accessoriesFromDiskMap[homebridgeUUID]) { + if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { - const existingAccessory = this.accessoriesFromDiskMap[homebridgeUUID]; + const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); const processedAccessory = this.processExistingAccessory(controller, existingAccessory); - this.accessoriesFromDiskMap.delete[homebridgeUUID]; + this.log.warn(this.accessoriesFromDiskMap.delete(homebridgeUUID)); existingAccessoriesList.push(processedAccessory); this.log.warn('registering existing accessory'); @@ -101,8 +101,18 @@ export class AccessoryGenerator { } + + } + // this.accessoriesFromDiskMap.forEach((accessory, homebridgeUUID) => { + // const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); + // const processedAccessory = this.processExistingAccessory(controller, existingAccessory); + + // existingAccessoriesList.push(processedAccessory); + // this.log.warn('registering accessory that has been unseen'); + // }); + this.registerNewAccessories(newAccessoriesList); //register new accessories from scan this.registerExistingAccessories(existingAccessoriesList); } @@ -112,7 +122,7 @@ export class AccessoryGenerator { const { protoDevice: { uniqueId }, deviceAPI: { description }, - deviceState: {LED: { RGB, CCT, isOn}}, + deviceState: { LED: { RGB, CCT, isOn } }, } = controller.getCachedDeviceInformation(); if (!this.isAllowed(uniqueId)) { diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index 5858172..54d4bce 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -1,5 +1,5 @@ -import { IColorRGB, IDeviceCommand } from 'magichome-platform/dist/types'; -import { IAccessoryCommand } from '../magichome-interface/types'; +import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -52,15 +52,34 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { }//setColor -// async updateHomekitState(){ -// // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); -// // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); -// // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); -// // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ -// // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); -// // } else if (this.lightState.isOn){ -// // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp((this.lightState.whiteValues.warmWhite/2.55), 0, 100)); -// // } -// // } + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + // eslint-disable-next-line prefer-const + let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let brightness = 0; + + if (luminance > 0 && isOn) { + brightness = luminance; + } else if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + if (warmWhite > coldWhite) { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); + } else { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + } + } + + const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; + return accessoryState; + } + + updateHomekiState() { + this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); + } + } \ No newline at end of file diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index ebe550a..9cb622d 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -1,6 +1,6 @@ -import { IColorRGB, IDeviceCommand } from 'magichome-platform/dist/types'; -import { IAccessoryCommand } from '../magichome-interface/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; +import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -61,4 +61,34 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite }, colorMask }; return deviceCommand; } + + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + // eslint-disable-next-line prefer-const + let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let brightness = 0; + + if (luminance > 0 && isOn) { + brightness = luminance; + } else if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + if (warmWhite > coldWhite) { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); + } else { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + } + } + + const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; + return accessoryState; + } + + updateHomekitState() { + this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); + } + } \ No newline at end of file diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index adaadf3..e5d4c39 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -1,25 +1,29 @@ -import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; +import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - const {hue, saturation} = HSL; - const RGB:IColorRGB = convertHSLtoRGB(HSL); - const CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - - let {red, green, blue} = RGB, {warmWhite, coldWhite} = CCT; + const { hue, saturation } = HSL; + const RGB: IColorRGB = convertHSLtoRGB(HSL); + let CCT: IColorCCT; + if (this.ColorCommandMode == 'CCT') { + CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" + } else { + CCT = cctToWhiteTemperature(accessoryCommand.colorTemperature); + } + let { red, green, blue } = RGB, { warmWhite, coldWhite } = CCT; //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); let colorMask = 0xF0; - + //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) @@ -39,6 +43,7 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { colorMask = 0x0F; // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); } else if (hue == 208 && saturation == 17) { + red = 0; green = 0; blue = 0; @@ -62,37 +67,38 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); } - const deviceCommand: IDeviceCommand = { isOn, RGB:{red, green, blue}, CCT: {warmWhite, coldWhite}, colorMask}; + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; return deviceCommand; - + }//setColor + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + // eslint-disable-next-line prefer-const + let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let brightness = 0; + + if (luminance > 0 && isOn) { + brightness = luminance; + } else if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + if (warmWhite > coldWhite) { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); + } else { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + } + } - // deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - // // const accessoryState: IAccessoryState = {}; - - // // const {LED:{RGB, CCT, isOn }} = deviceState; - - // // return accessoryState; - // } - - updateDeviceState(){ - - // this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessory.isOn); - // this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.lightState.HSL.hue); - // this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.lightState.HSL.saturation); - // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - // this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - // } else if (this.lightState.isOn){ - // this.service.updateCharacteristic(this.hap.Characteristic.Brightness,clamp(((this.lightState.whiteValues.coldWhite/2.55) + (this.lightState.whiteValues.warmWhite/2.55)), 0, 100)); - // if(this.accessoryState.colorTemperature.warmWhite>this.lightState.whiteValues.coldWhite){ - // this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.coldWhite/255))); - // this.service.updateCharacteristic(this.hap.Characteristic.Hue, 0); - // } else { - // this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.warmWhite/255))); - // this.service.updateCharacteristic(this.hap.Characteristic.Hue, 180); - // } - // } + const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; + return accessoryState; } - + + updateHomekitState() { + this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); + } + } \ No newline at end of file diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index 79d3538..ff1b1b8 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -1,6 +1,6 @@ -import { IColorRGB, IDeviceCommand } from 'magichome-platform/dist/types'; -import { IAccessoryCommand } from '../magichome-interface/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp } from '../magichome-interface/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { @@ -8,11 +8,15 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - const {hue, saturation} = HSL; - let RGB:IColorRGB = convertHSLtoRGB(HSL); - const CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - - let {red, green, blue} = RGB, {warmWhite, coldWhite} = CCT; + const { hue, saturation } = HSL; + let RGB: IColorRGB = convertHSLtoRGB(HSL); + let CCT: IColorCCT; + if (this.ColorCommandMode == 'CCT') { + CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" + } else { + CCT = cctToWhiteTemperature(accessoryCommand.colorTemperature); + } + let { red, green, blue } = RGB, { warmWhite, coldWhite } = CCT; //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); @@ -24,6 +28,7 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { red = Math.round((red / 100) * brightness); green = Math.round((green / 100) * brightness); blue = Math.round((blue / 100) * brightness); + warmWhite = Math.round((warmWhite / 100) * brightness); coldWhite = Math.round((coldWhite / 100) * brightness); @@ -60,8 +65,8 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { //the white brightness effectively acts as the saturation value } else if (saturation < 50) { - RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation - + RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation + // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs @@ -71,26 +76,37 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); } - const deviceCommand: IDeviceCommand = { isOn, RGB:{red, green, blue}, CCT: {warmWhite, coldWhite}, colorMask}; + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; return deviceCommand; }//setColor - async updateHomekitState() { - // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - // if(this.lightState.HSL.luminance > 0 && this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.HSL.luminance * 2); - // } else if (this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(((this.lightState.whiteValues.coldWhite/2.55) + (this.lightState.whiteValues.warmWhite/2.55)), 0, 100)); - // if(this.lightState.whiteValues.warmWhite>this.lightState.whiteValues.coldWhite){ - // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.coldWhite/255))); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, 0); - // } else { - // this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.colorWhiteThreshold - (this.colorWhiteThreshold * (this.lightState.whiteValues.warmWhite/255))); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, 180); - // } - // } + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + // eslint-disable-next-line prefer-const + let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let brightness = 0; + + if (luminance > 0 && isOn) { + brightness = luminance; + } else if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + if (warmWhite > coldWhite) { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); + } else { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + } + } + + const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; + return accessoryState; + } + + updateHomekitState() { + this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); } } \ No newline at end of file diff --git a/src/accessories/Switch.ts b/src/accessories/Switch.ts index 3aca931..ec2188b 100644 --- a/src/accessories/Switch.ts +++ b/src/accessories/Switch.ts @@ -2,15 +2,15 @@ import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessor export class Switch extends HomebridgeMagichomeDynamicPlatformAccessory { - /** - ** @updateHomekitState - * send state to homekit - */ - async updateHomekitState() { + // /** + // ** @updateHomekitState + // * send state to homekit + // */ + // async updateHomekitState() { - // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + // // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - } + // } diff --git a/src/index.ts b/src/index.ts index 6e03296..c7ed50e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,32 +1,10 @@ -import { join } from 'path'; -import { loadJson } from './magichome-interface/utils'; -import { cloneDeep } from 'lodash'; -import { Logs } from './logs'; import { API, - APIEvent, - DynamicPlatformPlugin, HAP, - Logging, PlatformAccessory, - PlatformConfig, } from 'homebridge'; -import { ICommandOptions, IDeviceAPI, IDeviceCommand, IProtoDevice, ControllerGenerator } from 'magichome-platform'; - -// import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -import { MagicHomeAccessory } from './magichome-interface/types'; -import { BaseController } from 'magichome-platform/dist/DeviceControllers/BaseController'; -//const NEW_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0x81, 0x8a, 0x8b]); -//const LEGACY_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0xEF, 0x01, 0x77]); -import { AccessoryGenerator } from './AccessoryGenerator'; - -/** - */ - -const controllerGenerator = new ControllerGenerator(); - let hap: HAP; import { PLATFORM_NAME } from './settings'; import { HomebridgeMagichomeDynamicPlatform } from './platform'; diff --git a/src/magichome-interface/types.ts b/src/magichome-interface/types.ts index 1f6c0ae..d194578 100644 --- a/src/magichome-interface/types.ts +++ b/src/magichome-interface/types.ts @@ -56,6 +56,11 @@ export interface IColorHSL { /*----------------------[Constants]----------------------*/ +export const ColorCommandModes = { + CCT: 'CCT', + HSL: 'HSL', +}; + export const DefaultAccessoryCommand = { isOn: true, HSL: { @@ -63,6 +68,6 @@ export const DefaultAccessoryCommand = { saturation: 100, luminance: 0, }, - colorTemperature: 0, + colorTemperature: 140, brightness: 100, }; \ No newline at end of file diff --git a/src/magichome-interface/utils.ts b/src/magichome-interface/utils.ts index 368805f..1ef2b82 100644 --- a/src/magichome-interface/utils.ts +++ b/src/magichome-interface/utils.ts @@ -1,6 +1,6 @@ import { existsSync, readFileSync } from 'fs'; -import { IColorCCT, IColorRGB } from 'magichome-platform/dist/types'; -import { IColorHSL } from './types'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IAccessoryCommand, IAccessoryState, IColorHSL } from './types'; export function clamp(value: number, min: number, max: number) { return Math.min(max, Math.max(min, value)); @@ -10,8 +10,15 @@ export function clamp(value: number, min: number, max: number) { //================================================= // Start checksum // -//a checksum is needed at the end of the byte array otherwise the message is rejected by the light -//add all bytes and chop off the beginning by & with 0xFF + + +/** + * @checksum + * a checksum is needed at the end of the byte array otherwise the message is rejected by the device + * add all bytes and chop off the beginning by & with 0xFF + * @param buffer + * @returns checksum number + */ export function checksum(buffer: Uint8Array) { let chk = 0; @@ -24,7 +31,8 @@ export function checksum(buffer: Uint8Array) { //================================================= // Start Convert RGBtoHSL // -export function convertRGBtoHSL({ red, green, blue }) { +export function convertRGBtoHSL(RGB: IColorRGB) { + const { red, green, blue } = RGB; const r = red / 255; const g = green / 255; const b = blue / 255; @@ -50,7 +58,7 @@ export function convertRGBtoHSL({ red, green, blue }) { h += 360; } - const l = (min + max) / 2; + const l = max; if (max === min) { s = 0; @@ -59,30 +67,10 @@ export function convertRGBtoHSL({ red, green, blue }) { } else { s = delta / (2 - max - min); } - const HSL = { hue: h, saturation: s * 100, luminance: l * 100 }; + const HSL: IColorHSL = { hue: h, saturation: s * 100, luminance: l * 100 }; return HSL; } -export function hue2rgb(p: number, q: number, t: number) { - if (t < 0) { - t += 1; - } - if (t > 1) { - t -= 1; - } - if (t < 1 / 6) { - return p + (q - p) * 6 * t; - } - if (t < 1 / 2) { - return q; - } - if (t < 2 / 3) { - return p + (q - p) * (2 / 3 - t) * 6; - } - return p; - -} - //================================================= // End Convert RGBtoHSL // @@ -186,11 +174,29 @@ export function convertHueToColorCCT(hue: number): IColorCCT { multiplier = (1 - (hue - 90) / 90); colorCCT.warmWhite = Math.round((255 * multiplier)); } - + return colorCCT; } //hueToWhiteTemperature -//Unused +export function cctToWhiteTemperature(CCT: number, multiplier = 0): {warmWhite: number, coldWhite: number} { + CCT -= 140; + let warmWhite, coldWhite; + + const threshold = 110; + if (CCT >= threshold) { + warmWhite = 127; + multiplier = (1-((CCT-threshold) / (360 - threshold))); + coldWhite = Math.round((127 * multiplier)); + } else { + coldWhite = 127; + multiplier = (CCT / threshold); + warmWhite = Math.round((127 * multiplier)); + } + + // this.logs.trace('Calculated accessory %o\'s white values: %o from CCT: %o', this.accessory.context.displayName, {warmWhite, coldWhite}, CCT); + + return {warmWhite, coldWhite}; +} /* export function delayToSpeed(delay: never) { @@ -204,3 +210,142 @@ export function speedToDelay(speed: never) { return 30 - (clamped / 100) * 30 + 1; } */ +export function convertMiredColorTemperatureToHueSat(temperature: number): [number, number] { + const xy = convertMiredColorTemperatureToXY(temperature); + return convertXyToHueSat(xy[0], xy[1]); +} + +export function convertXyToHueSat(x: number, y: number): [number, number] { + // Based on: https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/ + const z: number = 1.0 - x - y; + const Y = 1.0; + const X: number = (Y / y) * x; + const Z: number = (Y / y) * z; + + // sRGB D65 conversion + let r: number = (X * 1.656492) - (Y * 0.354851) - (Z * 0.255038); + let g: number = (-X * 0.707196) + (Y * 1.655397) + (Z * 0.036152); + let b: number = (X * 0.051713) - (Y * 0.121364) + (Z * 1.011530); + + // Remove negative values + const m = Math.min(r, g, b); + if (m < 0.0) { + r -= m; + g -= m; + b -= m; + } + + // Normalize + if (r > b && r > g && r > 1.0) { + // red is too big + g = g / r; + b = b / r; + r = 1.0; + } else if (g > b && g > r && g > 1.0) { + // green is too big + r = r / g; + b = b / g; + g = 1.0; + } else if (b > r && b > g && b > 1.0) { + // blue is too big + r = r / b; + g = g / b; + b = 1.0; + } + + // Gamma correction + r = reverseGammaCorrection(r); + g = reverseGammaCorrection(g); + b = reverseGammaCorrection(b); + + // Maximize + const max = Math.max(r, g, b); + r = (r === max) ? 255 : (255 * (r / max)); + g = (g === max) ? 255 : (255 * (g / max)); + b = (b === max) ? 255 : (255 * (b / max)); + + const RGB:IColorRGB = { red: r, green: g, blue: b }; + const HSL = convertRGBtoHSL(RGB); + + const hsv = [HSL.hue, HSL.saturation]; + + return [hsv[0], hsv[1]]; +} + +function convertMiredColorTemperatureToXY(temperature: number): [number, number] { + // Based on MiredColorTemperatureToXY from: + // https://github.com/dresden-elektronik/deconz-rest-plugin/blob/78939ac4ee4b0646fbf542a0f6e83ee995f1a875/colorspace.cpp + const TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD = 4000; + + const TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD = 2222; + const TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD = 4000; + + const TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION = 17440695910400; + const TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION = 15358885888; + const TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION = 57520658; + const TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION = 11790; + + const TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION = 198301902438400; + const TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION = 138086835814; + const TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION = 14590587; + const TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION = 15754; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION = 18126; + const TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION = 22087; + const TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION = 35808; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION = 3312; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION = 15645; + const TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION = 22514; + const TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION = 34265; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION = 2744; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION = 50491; + const TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION = 96229; + const TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION = 61458; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION = 6062; + + let localX = 0; + let localY = 0; + const temp = 1000000 / temperature; + + if (TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD > temp) { + localX = TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION / temp + + TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION - + TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION / temp / temp - + TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION / temp / temp / temp; + } else { + localX = TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION / temp / temp + + TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION / temp + + TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION - + TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION / temp / temp / temp; + } + + if (TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD > temp) { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION * localX / 65536 - + TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION; + } else if (TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD > temp) { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION * localX / 65536 - + TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION; + } else { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION * localX / 65536 + + TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION; + } + + localY *= 4; + + localX /= 0xFFFF; + localY /= 0xFFFF; + + return [Math.round(localX * 10000) / 10000, Math.round(localY * 10000) / 10000]; +} + +function reverseGammaCorrection(v: number): number { + return (v <= 0.0031308) ? 12.92 * v : (1.0 + 0.055) * Math.pow(v, (1.0 / 2.4)) - 0.055; +} \ No newline at end of file diff --git a/src/platform.ts b/src/platform.ts index 888bac3..6e32e26 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -20,21 +20,14 @@ import { BaseController } from 'magichome-platform/dist/DeviceControllers/BaseCo //const NEW_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0x81, 0x8a, 0x8b]); //const LEGACY_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0xEF, 0x01, 0x77]); import { AccessoryGenerator } from './AccessoryGenerator'; +import { UUID } from 'hap-nodejs'; /** */ const controllerGenerator = new ControllerGenerator(); - -const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; -const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; let hap: HAP; -// export = (api: API) => { - -// }; - - /** * HomebridgePlatform * This class is the main constructor for your plugin, this is where you should @@ -52,8 +45,6 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin public readonly config: PlatformConfig; public readonly accessoriesFromDiskMap: Map = new Map(); - public readonly accessoriesActive: MagicHomeAccessory[] = []; - constructor( hbLogger: Logging, @@ -63,7 +54,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin hap = api.hap; this.config = config; // this.log = new Logs(hbLogger, this.config.advancedOptions.logLevel); -this.log = new Logs(hbLogger, config.advancedOptions.logLevel); + this.log = new Logs(hbLogger, config.advancedOptions.logLevel); this.api = api; //this.logs = getLogger(); @@ -87,8 +78,6 @@ this.log = new Logs(hbLogger, config.advancedOptions.logLevel); * It should be used to setup event handlers for characteristics and update respective values. */ configureAccessory(accessory: MagicHomeAccessory) { - - this.log.debug('%o - Loading accessory from cache...', this.accessoriesActive.length, accessory.context.displayName); // set cached accessory as not recently seen // if found later to be a match with a discovered device, will change to true // accessory.context.scansSinceSeen++; @@ -96,7 +85,9 @@ this.log = new Logs(hbLogger, config.advancedOptions.logLevel); // // add the restored accessory to the accessories cache so we can track if it has already been registered const homebridgeUUID = accessory.UUID; - this.accessoriesFromDiskMap[homebridgeUUID] = accessory; + this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); + this.log.debug('%o - Loading accessory from cache...', this.accessoriesFromDiskMap.keys.length, accessory.context.displayName); + } /** @@ -115,13 +106,14 @@ this.log = new Logs(hbLogger, config.advancedOptions.logLevel); const accesssoryGenerator = new AccessoryGenerator(hap, this.api, this.log, this.config, this.accessoriesFromDiskMap, controllerGenerator); await accesssoryGenerator.generateAccessories(); - // this.periodicDiscovery = setInterval(() => await this.discoverDevices(), 30000); - } - sanitizeConfig() { - //recursive config sanitation } + // sanitizeConfig() { + // //recursive config sanitation + // } + + }//ZackneticMagichomePlatform class \ No newline at end of file diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index d9383d3..f981e26 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -3,15 +3,19 @@ import type { Service, PlatformConfig, CharacteristicValue, CharacteristicSetCallback, CharacteristicGetCallback, HAP, } from 'homebridge'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './magichome-interface/utils'; +import { clamp, convertHSLtoRGB, convertMiredColorTemperatureToHueSat, convertRGBtoHSL } from './magichome-interface/utils'; import { getLogs } from './logs'; import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, MagicHomeAccessory } from './magichome-interface/types'; -import { BaseController, ICommandOptions } from 'magichome-platform'; +import * as types from './magichome-interface/types'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus, IDeviceAPI, IProtoDevice } from 'magichome-platform'; import { _ } from 'lodash'; import Queue from 'queue-promise'; -import { DefaultCommand, IDeviceCommand, IDeviceState, DeviceWriteStatus } from 'magichome-platform/dist/types'; +import { Hue } from 'hap-nodejs/dist/lib/definitions'; const { ready, pending, busy } = DeviceWriteStatus; +const CCT = 'CCT'; +const HSL = 'HSL'; + const BUFFER_MS = 50; /** * Platform Accessory @@ -25,20 +29,24 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected colorOffThresholdSimultaniousDevices = this.config.whiteEffects.colorOffThresholdSimultaniousDevices; protected simultaniousDevicesColorWhite = this.config.whiteEffects.simultaniousDevicesColorWhite; + protected alController; protected newAccessoryCommand: IAccessoryCommand; protected latestDeviceCommand: IDeviceCommand; - protected setColortemp = false; + protected ColorCommandMode = HSL; protected logs = getLogs(); protected accessoryState: IAccessoryState = DefaultAccessoryCommand; protected accessoryStateTemporary: IAccessoryState; - protected deviceWriteStatus = ready; - + // protected deviceAPI: IDeviceAPI; + protected protoDevice: IProtoDevice; protected queue; + protected deviceAPI: { hasBrightness, hasCCT }; + saturationCharacteristic: any; + //================================================= // Start Constructor // constructor( @@ -50,6 +58,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { ) { this.accessoryState = this.accessory.context.cachedAccessoryState || DefaultAccessoryCommand; + // this.accessoryState.HSL = Object.assign( DefaultAccessoryCommand.HSL); this.logs.warn(this.accessoryState); //get acessory state from device @@ -77,8 +86,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } else { deviceState = await this.controller.setOn(false, options); } - this.accessory.context.cachedAccessoryState = this.accessoryState; //this.accessoryState = deviceStateToAccessoryState(deviceState); + this.accessory.context.cachedAccessoryState = this.accessoryState; + }, 500); }); @@ -88,7 +98,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.api = api; const { protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, deviceAPI: { description }, + deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, + deviceAPI: { description, hasBrightness, hasCCT, hasColor }, } = controller.getCachedDeviceInformation(); // set accessory information this.accessory.getService(hap.Service.AccessoryInformation)! @@ -108,70 +119,72 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // get the LightBulb service if it exists, otherwise create a new LightBulb service // you can create multiple services for each accessory - //if(this.myDevice.lightParameters.hasBrightness || this.myDevice.lightParameters.hasBrightness == undefined){ - - if (this.accessory.getService(hap.Service.Switch)) { - this.accessory.removeService(this.accessory.getService(hap.Service.Switch)); - } - this.service = this.accessory.getService(hap.Service.Lightbulb) ?? this.accessory.addService(hap.Service.Lightbulb); - //this.myDevice.lightParameters.hasBrightness = true; - - this.service.getCharacteristic(hap.Characteristic.ConfiguredName) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); + if (hasBrightness) { - // each service must implement at-minimum the "required characteristics" for the given service type - // see https://developers.homebridge.io/#/service/Lightbulb - - // register handlers for the Brightness Characteristic - - this.service.getCharacteristic(hap.Characteristic.Brightness) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setBrightness.bind(this)) // SET - bind to the 'setBrightness` method below - .on(CharacteristicEventTypes.GET, this.getBrightness.bind(this)); // GET - bind to the 'getBrightness` method below + if (this.accessory.getService(hap.Service.Switch)) { + this.accessory.removeService(this.accessory.getService(hap.Service.Switch)); + } + this.service = this.accessory.getService(hap.Service.Lightbulb) ?? this.accessory.addService(hap.Service.Lightbulb); + + this.service.getCharacteristic(hap.Characteristic.ConfiguredName) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); + + // register handlers for the Brightness Characteristic + this.service.getCharacteristic(hap.Characteristic.Brightness) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setBrightness.bind(this)) // SET - bind to the 'setBrightness` method below + .on(CharacteristicEventTypes.GET, this.getBrightness.bind(this)); // GET - bind to the 'getBrightness` method below + + if (hasColor) { + + // register handlers for the Hue Characteristic + this.logs.trace('Adding Hue characteristic to device.'); + this.service.getCharacteristic(hap.Characteristic.Hue) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setHue.bind(this)) // SET - bind to the 'setHue` method below + .on(CharacteristicEventTypes.GET, this.getHue.bind(this)); // GET - bind to the 'getHue` method below + + // register handlers for the Saturation Characteristic + this.logs.trace('Adding Saturation characteristic to device.'); + this.saturationCharacteristic = this.service.getCharacteristic(hap.Characteristic.Saturation) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setSaturation.bind(this)); // SET - bind to the 'setSaturation` method below + //.on(CharacteristicEventTypes.GET, this.getSaturation.bind(this)); // GET - bind to the 'getSaturation` method below + // register handlers for the On/Off Characteristic - // if( this..lightParameters.hasColor){ - // register handlers for the Hue Characteristic - this.logs.trace('Adding Hue characteristic to device.'); - this.service.getCharacteristic(hap.Characteristic.Hue) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setHue.bind(this)) // SET - bind to the 'setHue` method below - .on(CharacteristicEventTypes.GET, this.getHue.bind(this)); // GET - bind to the 'getHue` method below + } - // register handlers for the Saturation Characteristic - this.logs.trace('Adding Saturation characteristic to device.'); - this.service.getCharacteristic(hap.Characteristic.Saturation) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setSaturation.bind(this)); // SET - bind to the 'setSaturation` method below - //.on(CharacteristicEventTypes.GET, this.getSaturation.bind(this)); // GET - bind to the 'getSaturation` method below - // register handlers for the On/Off Characteristic + if (hasCCT) { + // register handlers for the Saturation Characteristic + this.logs.trace('Adding ColorTemperature characteristic to device.'); + this.service.getCharacteristic(hap.Characteristic.ColorTemperature) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setColorTemperature.bind(this)) // SET - bind to the 'setSaturation` method below + .on(CharacteristicEventTypes.GET, this.getColorTemperature.bind(this)); // GET - bind to the 'getSaturation` method below + + if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { + this.logs.trace('Adding the adaptive lighting controller to the accessory...'); + this.alController = new this.api.hap.AdaptiveLightingController(this.service); + this.accessory.configureController(this.alController); + } + } + } else { + //device is switch, register it as such + this.logs.trace('Adding Switch service to device.'); + this.service = this.accessory.getService(hap.Service.Switch) ?? this.accessory.addService(hap.Service.Switch); + this.service.getCharacteristic(hap.Characteristic.ConfiguredName) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); - // } - - // if(this.myDevice.lightParameters.hasCCT){ - // // register handlers for the Saturation Characteristic - // this.logs.trace('Adding ColorTemperature characteristic to device.'); - // this.service.getCharacteristic(hap.Characteristic.ColorTemperature) - // .removeAllListeners(CharacteristicEventTypes.SET) - // .removeAllListeners(CharacteristicEventTypes.GET) - // .on(CharacteristicEventTypes.SET, this.setColorTemperature.bind(this)) // SET - bind to the 'setSaturation` method below - // .on(CharacteristicEventTypes.GET, this.getColorTemperature.bind(this)); // GET - bind to the 'getSaturation` method below - // } - // } else { - // //device is switch, register it as such - // this.logs.trace('Adding Switch service to device.'); - // this.service = this.accessory.getService(hap.Service.Switch) ?? this.accessory.addService(hap.Service.Switch); - // this.service.getCharacteristic(hap.Characteristic.ConfiguredName) - // .removeAllListeners(CharacteristicEventTypes.SET) - // .removeAllListeners(CharacteristicEventTypes.GET) - // .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); - - // } + } // register handlers for the On/Off Characteristic this.logs.trace('Adding On characteristic to device.'); this.service.getCharacteristic(hap.Characteristic.On) @@ -180,7 +193,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { .on(CharacteristicEventTypes.SET, this.setOn.bind(this)) // SET - bind to the `setOn` method below .on(CharacteristicEventTypes.GET, this.getOn.bind(this)); // GET - bind to the `getOn` method below - //this.updateLocalState(); + this.updateLocalState(); // set the service name, this is what is displayed as the default name on the Home app // in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method. @@ -194,47 +207,33 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // Start Setters // - setConfiguredName(value: CharacteristicValue, callback: CharacteristicSetCallback) { - - const name: string = value.toString(); - this.logs.debug('Renaming device to %o', name); - this.accessory.context.displayName = name; - // this.service.setCharacteristic(this.hap.Characteristic.Name, value); - - this.api.updatePlatformAccessories([this.accessory]); - + async setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) { callback(null); - } - - identifyLight() { - //this.logs.info('Identifying accessory: %o!', this.myDevice.displayName); - this.flashEffect(); + const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; + this.processAccessoryCommand(accessoryCommand); } setHue(value: CharacteristicValue, callback: CharacteristicSetCallback) { - this.logs.warn('Setting accessory %o\'s Hue value: %o', this.accessory.context.displayName, value); - callback(null); - this.setColortemp = false; + + this.ColorCommandMode = HSL; const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; this.processAccessoryCommand(accessoryCommand); } setSaturation(value: CharacteristicValue, callback: CharacteristicSetCallback) { - this.logs.warn('Setting accessory %o\'s Saturation value: %o', this.accessory.displayName, value); callback(null); - this.setColortemp = false; + this.ColorCommandMode = HSL; const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { saturation: value as number } }; this.processAccessoryCommand(accessoryCommand); } async setBrightness(value: CharacteristicValue, callback: CharacteristicSetCallback) { - this.logs.warn('Setting accessory %o\'s Brightness value: %o', this.accessory.context.displayName, value); callback(null); @@ -244,29 +243,28 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setColorTemperature(value: CharacteristicValue, callback: CharacteristicSetCallback) { - // this.logs.debug('Setting accessory %o\'s Color Temperature value: %o', this.myDevice.displayName, value); - this.setColortemp = true; + this.ColorCommandMode = CCT; callback(null); - const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; this.processAccessoryCommand(accessoryCommand); } - /* - async setColorTemperature(value: CharacteristicValue, callback: CharacteristicSetCallback){ - this.lightState.operatingMode = opMode.temperatureMode; - this.processRequest({msg: `cct=${value}`} ); - callback(null); - }*/ + setConfiguredName(value: CharacteristicValue, callback: CharacteristicSetCallback) { + + const name: string = value.toString(); + this.logs.debug('Renaming device to %o', name); + this.accessory.context.displayName = name; + this.api.updatePlatformAccessories([this.accessory]); - async setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) { - // this.logs.debug('Setting accessory %o\'s On value: %o', this.myDevice.displayName, value); callback(null); + } - const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; - this.processAccessoryCommand(accessoryCommand); + identifyLight() { + + this.flashEffect(); } + //================================================= // End Setters // @@ -274,28 +272,26 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start Getters // getHue(callback: CharacteristicGetCallback) { + const hue = this.accessoryState.HSL.hue; - if (!this.setColortemp) { //if we are not in Color Temperature mode, allow HB to update HK with Hue values - //this.logs.debug('Returning accessory %o\'s cached Hue value: %o', this.myDevice.displayName, hue); - // this.updateLocalState(); //update state with actual values asynchronously - } callback(null, hue); + + this.updateLocalState(); } getColorTemperature(callback: CharacteristicGetCallback) { + const colorTemperature = this.accessoryState.colorTemperature; - if (this.setColortemp) { //if we are in Color Temperature mode, allow HB to update HK with CCT values - //this.logs.debug('Returning accessory %o\'s cached Color Temperature value: %o', this.myDevice.displayName, CCT); - // this.updateLocalState(); //update state with actual values asynchronously - } callback(null, colorTemperature); //immediately return cached state to prevent laggy HomeKit UI + + this.updateLocalState(); } getBrightness(callback: CharacteristicGetCallback) { + const brightness = this.accessoryState.brightness; - //this.logs.debug('Returning accessory %o\'s cached Brightness value: %o', this.myDevice.displayName, brightness); - // this.updateLocalState(); //update state with actual values asynchronously callback(null, brightness); //immediately return cached state to prevent laggy HomeKit UI + this.updateLocalState(); } /** @@ -306,62 +302,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getOn(callback: CharacteristicGetCallback) { const isOn = this.accessoryState.isOn; - //this.logs.debug('Returning accessory %o\'s cached Power value: %o', this.myDevice.displayName, isOn); - // this.updateLocalState(); //update state with actual values asynchronously callback(null, isOn); //immediately return cached state to prevent laggy HomeKit UI - } - - //================================================= - // End Getters // - - //================================================= - - - //================================================= - // End Misc Tools // - - - //================================================= - // Start LightEffects // + this.updateLocalState(); + } flashEffect() { - // this.lightState.HSL.hue = 100 as number; - // this.lightState.HSL.saturation = 100 as number; - - // let change = true; - // let count = 0; - - // const interval = setInterval(() => { - - // if (change) { - // this.lightState.brightness = 0; - - // } else { - // this.lightState.brightness = 100; - // } - - // change = !change; - // count++; - // // this.updateDeviceState(); - - // if (count >= 20) { - - // this.lightState.HSL.hue = 0; - // this.lightState.HSL.saturation = 5; - // this.lightState.brightness = 100; - // //this.updateDeviceState(); - // clearInterval(interval); - // return; - // } - // }, 300); + // } //flashEffect //================================================= // End LightEffects // - async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { + protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { const deviceWriteStatus = this.deviceWriteStatus; this.logs.info(this.deviceWriteStatus); switch (deviceWriteStatus) { @@ -385,10 +339,10 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } } - private async writeStateToDevice(accessoryCommand: IAccessoryCommand): Promise { + protected async writeStateToDevice(accessoryCommand: IAccessoryCommand): Promise { this.newAccessoryCommand = accessoryCommand; return new Promise((resolve, reject) => { - + this.logs.info(this.ColorCommandMode); return setTimeout(() => { this.logs.warn(this.accessory.context.displayName, '\nthis.accessoryState: ', this.accessoryState, '\n this.newAccessoryCommand: ', this.newAccessoryCommand); const sanitizedAcessoryCommand = _.merge({}, this.accessoryState, this.newAccessoryCommand); @@ -407,7 +361,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { }); } - async prepareCommand(accessoryCommand: IAccessoryCommand) { + protected async prepareCommand(accessoryCommand: IAccessoryCommand) { const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); this.latestDeviceCommand = deviceCommand; @@ -426,6 +380,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + const RGB = convertHSLtoRGB(HSL); RGB.red = Math.round((RGB.red / 100) * brightness); RGB.green = Math.round((RGB.green / 100) * brightness); @@ -435,6 +390,42 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { return deviceCommand; } + protected async updateLocalState() { + const deviceState = await this.controller.fetchState(); + const accessoryState = this.deviceStateToAccessoryState(deviceState); + _.merge(this.accessoryState, accessoryState); + this.updateHomekitState(); + } + + updateHomekitState() { + this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); + } + + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + // eslint-disable-next-line prefer-const + let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let brightness = 0; + + if (luminance > 0 && isOn) { + brightness = luminance * 2; + } else if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + if (warmWhite > coldWhite) { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); + } else { + saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + } + } + + const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; + return accessoryState; + } + // /** // * This is a debug function to show the number of listeners for each .on event. // */ @@ -457,13 +448,3 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //} } // ZackneticMagichomePlatformAccessory class -// function deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - -// // -// } - -// function accessoryStateToDeviceCommand(accessoryState: IAccessoryState): IDeviceCommand { -// // -// } - - From 0478ebf2a1e3bbc61471d765eb8ff7007ec3682b Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Mon, 11 Oct 2021 21:04:49 -0400 Subject: [PATCH 13/42] major change to device state --- src/misc/serviceCharacteristics.ts | 87 +++++++ src/misc/types.ts | 73 ++++++ src/misc/utils.ts | 351 +++++++++++++++++++++++++++++ 3 files changed, 511 insertions(+) create mode 100644 src/misc/serviceCharacteristics.ts create mode 100644 src/misc/types.ts create mode 100644 src/misc/utils.ts diff --git a/src/misc/serviceCharacteristics.ts b/src/misc/serviceCharacteristics.ts new file mode 100644 index 0000000..3af810e --- /dev/null +++ b/src/misc/serviceCharacteristics.ts @@ -0,0 +1,87 @@ +import { CharacteristicEventTypes } from 'homebridge'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +/*-------------------------- Characteristics -------------------------------------*/ + +export function addOnCharacteristic(_this) { + _this.logs.trace('Adding On characteristic to service.'); + _this.service.getCharacteristic(_this.hap.Characteristic.On) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, _this.setOn.bind(_this)) // SET - bind to the `setOn` method below + .on(CharacteristicEventTypes.GET, _this.getOn.bind(_this)); // GET - bind to the `getOn` method below +} + +export function addBrightnessCharacteristic(_this) { + _this.logs.trace('Adding Hue characteristic to service.'); + _this.service.getCharacteristic(_this.hap.Characteristic.Brightness) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, _this.setBrightness.bind(_this)) // SET - bind to the 'setBrightness` method below + .on(CharacteristicEventTypes.GET, _this.getBrightness.bind(_this)); // GET - bind to the 'getBrightness` method below +} + +export function addHueCharacteristic(_this) { + _this.logs.trace('Adding Hue characteristic to service.'); + _this.service.getCharacteristic(_this.hap.Characteristic.Hue) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, _this.setHue.bind(_this)) // SET - bind to the 'setHue` method below + .on(CharacteristicEventTypes.GET, _this.getHue.bind(_this)); // GET - bind to the 'getHue` method below +} + +export function addSaturationCharacteristic(_this) { + _this.logs.trace('Adding Saturation characteristic to service.'); + _this.saturationCharacteristic = _this.service.getCharacteristic(_this.hap.Characteristic.Saturation) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, _this.setSaturation.bind(_this)); // SET - bind to the 'setSaturation` method below + //.on(CharacteristicEventTypes.GET, _this.getSaturation.bind(_this)); // GET - bind to the 'getSaturation` method below + +} + +export function addColorTemperatureCharacteristic(_this) { + _this.logs.trace('Adding ColorTemperature characteristic to service.'); + _this.service.getCharacteristic(_this.hap.Characteristic.ColorTemperature) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, _this.setColorTemperature.bind(_this)) // SET - bind to the 'setSaturation` method below + .on(CharacteristicEventTypes.GET, _this.getColorTemperature.bind(_this)); // GET - bind to the 'getSaturation` method below + + if (_this.api.versionGreaterOrEqual && _this.api.versionGreaterOrEqual('1.3.0-beta.46')) { + _this.logs.trace('Adding the adaptive lighting service to the accessory...'); + _this.adaptiveLightingService = new _this.api.hap.AdaptiveLightingController(_this.service); + _this.accessory.configureController(_this.adaptiveLightingService); + } +} + +export function addAccessoryInformationCharacteristic(_this) { + + const { + protoDevice: { uniqueId, modelNumber }, + deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, + } = _this.controller.getCachedDeviceInformation(); + + // set accessory information + _this.accessory.getService(_this.hap.Service.AccessoryInformation)! + .setCharacteristic(_this.hap.Characteristic.Manufacturer, 'MagicHome') + .setCharacteristic(_this.hap.Characteristic.SerialNumber, uniqueId) + .setCharacteristic(_this.hap.Characteristic.Model, modelNumber) + .setCharacteristic(_this.hap.Characteristic.HardwareRevision, controllerHardwareVersion.toString(16)) + .setCharacteristic(_this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion.toString(16)) + .getCharacteristic(_this.hap.Characteristic.Identify) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, _this.identifyLight.bind(_this)); // SET - bind to the 'Identify` method below + + + _this.accessory.getService(_this.hap.Service.AccessoryInformation)! + .addOptionalCharacteristic(_this.hap.Characteristic.ConfiguredName); +} + +export function addConfiguredNameCharacteristic(_this) { + _this.service.getCharacteristic(_this.hap.Characteristic.ConfiguredName) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, _this.setConfiguredName.bind(_this)); +} \ No newline at end of file diff --git a/src/misc/types.ts b/src/misc/types.ts new file mode 100644 index 0000000..d194578 --- /dev/null +++ b/src/misc/types.ts @@ -0,0 +1,73 @@ +import type { PlatformAccessory } from 'homebridge'; +import { BaseController } from 'magichome-platform'; + +import { Switch } from '../accessories/Switch'; +import { DimmerStrip } from '../accessories/DimmerStrip'; +import { RGBStrip } from '../accessories/RGBStrip'; +import { GRBStrip } from '../accessories/GRBStrip'; +import { RGBWBulb } from '../accessories/RGBWBulb'; +import { RGBWWBulb } from '../accessories/RGBWWBulb'; +import { RGBWStrip } from '../accessories/RGBWStrip'; +import { RGBWWStrip } from '../accessories/RGBWWStrip'; +import { CCTStrip } from '../accessories/CCTStrip'; +import { IDeviceState, IDeviceCommand, IColorCCT } from 'magichome-platform/dist/types'; + + +export const homekitInterface = { + 'Power Socket': Switch, + 'Dimmer': DimmerStrip, + 'GRB Strip': GRBStrip, + 'RGB Strip': RGBStrip, + 'RGBW Non-Simultaneous': RGBWBulb, + 'RGBWW Non-Simultaneous': RGBWWBulb, + 'RGBW Simultaneous': RGBWStrip, + 'RGBWW Simultaneous': RGBWWStrip, + 'CCT Strip': CCTStrip, +}; + +export interface MagicHomeAccessory extends PlatformAccessory { + context: { + displayName: string; + restartsSinceSeen: number, + pendingRegistration?: boolean; + cachedAccessoryState?: IAccessoryState; + } +} + +export interface IAccessoryState { + isOn: boolean, + HSL: IColorHSL, + colorTemperature: number, + brightness: number, +} + +export interface IAccessoryCommand { + isOn?: boolean, + HSL?: IColorHSL, + colorTemperature?: number, + brightness?: number, +} + +export interface IColorHSL { + hue?: number; + saturation?: number; + luminance?: number; +} + +/*----------------------[Constants]----------------------*/ + +export const ColorCommandModes = { + CCT: 'CCT', + HSL: 'HSL', +}; + +export const DefaultAccessoryCommand = { + isOn: true, + HSL: { + hue: 0, + saturation: 100, + luminance: 0, + }, + colorTemperature: 140, + brightness: 100, +}; \ No newline at end of file diff --git a/src/misc/utils.ts b/src/misc/utils.ts new file mode 100644 index 0000000..1ef2b82 --- /dev/null +++ b/src/misc/utils.ts @@ -0,0 +1,351 @@ +import { existsSync, readFileSync } from 'fs'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IAccessoryCommand, IAccessoryState, IColorHSL } from './types'; + +export function clamp(value: number, min: number, max: number) { + return Math.min(max, Math.max(min, value)); +} + + +//================================================= +// Start checksum // + + + +/** + * @checksum + * a checksum is needed at the end of the byte array otherwise the message is rejected by the device + * add all bytes and chop off the beginning by & with 0xFF + * @param buffer + * @returns checksum number + */ +export function checksum(buffer: Uint8Array) { + let chk = 0; + + for (const byte of buffer) { + chk += byte; + } + + return chk & 0xff; +} + +//================================================= +// Start Convert RGBtoHSL // +export function convertRGBtoHSL(RGB: IColorRGB) { + const { red, green, blue } = RGB; + const r = red / 255; + const g = green / 255; + const b = blue / 255; + const min = Math.min(r, g, b); + const max = Math.max(r, g, b); + const delta = max - min; + let h = 0; + let s = 0; + + if (max === min) { + h = 0; + } else if (r === max) { + h = (g - b) / delta; + } else if (g === max) { + h = 2 + (b - r) / delta; + } else if (b === max) { + h = 4 + (r - g) / delta; + } + + h = Math.min(h * 60, 360); + + if (h < 0) { + h += 360; + } + + const l = max; + + if (max === min) { + s = 0; + } else if (l <= 0.5) { + s = delta / (max + min); + } else { + s = delta / (2 - max - min); + } + const HSL: IColorHSL = { hue: h, saturation: s * 100, luminance: l * 100 }; + return HSL; +} + +//================================================= +// End Convert RGBtoHSL // + + +//================================================= +// Start Convert HSLtoRGB // +export function convertHSLtoRGB(HSL: IColorHSL): IColorRGB { + + let RGB: IColorRGB; + const { hue, saturation, luminance } = HSL; + const h = hue / 360; + const s = saturation / 100; + const l = 50 / 100; + let t2; + let t3; + let val; + + if (s === 0) { + val = l * 255; + RGB = { red: val, green: val, blue: val }; + } + + if (l < 0.5) { + t2 = l * (1 + s); + } else { + t2 = l + s - l * s; + } + + const t1 = 2 * l - t2; + + const rgb = [0, 0, 0]; + for (let i = 0; i < 3; i++) { + t3 = h + 1 / 3 * -(i - 1); + if (t3 < 0) { + t3++; + } + + if (t3 > 1) { + t3--; + } + + if (6 * t3 < 1) { + val = t1 + (t2 - t1) * 6 * t3; + } else if (2 * t3 < 1) { + val = t2; + } else if (3 * t3 < 2) { + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + } else { + val = t1; + } + + rgb[i] = val * 255; + } + RGB = { red: rgb[0], green: rgb[1], blue: rgb[2] }; + return RGB; +} +//================================================= +// End Convert HSLtoRGB // + +export function parseJson(value: string, replacement: T): T { + try { + return JSON.parse(value); + } catch (_error) { + return replacement; + } +} + +export function loadJson(file: string, replacement: T): T { + if (!existsSync(file)) { + return replacement; + } + return parseJson(readFileSync(file).toString(), replacement); +} + +/** + ** @calculateWhiteColor + * determine warmWhite/coldWhite values from hue + * the closer to 0/360 the weaker coldWhite brightness becomes + * the closer to 180 the weaker warmWhite brightness becomes + * the closer to 90/270 the stronger both warmWhite and coldWhite become simultaniously + */ +export function convertHueToColorCCT(hue: number): IColorCCT { + let multiplier = 0; + const colorCCT = { warmWhite: 0, coldWhite: 0 }; + + + if (hue <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue + colorCCT.warmWhite = 255; + multiplier = ((hue / 90)); + colorCCT.coldWhite = Math.round((255 * multiplier)); + } else if (hue > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue + colorCCT.warmWhite = 255; + multiplier = (1 - (hue - 270) / 90); + colorCCT.coldWhite = Math.round((255 * multiplier)); + } else if (hue > 180 && hue <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue + colorCCT.coldWhite = 255; + multiplier = ((hue - 180) / 90); + colorCCT.warmWhite = Math.round((255 * multiplier)); + } else if (hue > 90 && hue <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue + colorCCT.coldWhite = 255; + multiplier = (1 - (hue - 90) / 90); + colorCCT.warmWhite = Math.round((255 * multiplier)); + } + + return colorCCT; +} //hueToWhiteTemperature + +export function cctToWhiteTemperature(CCT: number, multiplier = 0): {warmWhite: number, coldWhite: number} { + CCT -= 140; + let warmWhite, coldWhite; + + const threshold = 110; + if (CCT >= threshold) { + warmWhite = 127; + multiplier = (1-((CCT-threshold) / (360 - threshold))); + coldWhite = Math.round((127 * multiplier)); + } else { + coldWhite = 127; + multiplier = (CCT / threshold); + warmWhite = Math.round((127 * multiplier)); + } + + // this.logs.trace('Calculated accessory %o\'s white values: %o from CCT: %o', this.accessory.context.displayName, {warmWhite, coldWhite}, CCT); + + return {warmWhite, coldWhite}; +} + +/* +export function delayToSpeed(delay: never) { + let clamped = clamp(delay, 1, 31); + clamped -= 1; // bring into interval [0, 30] + return 100 - (clamped / 30) * 100; +} + +export function speedToDelay(speed: never) { + const clamped = clamp(speed, 0, 100); + return 30 - (clamped / 100) * 30 + 1; +} +*/ +export function convertMiredColorTemperatureToHueSat(temperature: number): [number, number] { + const xy = convertMiredColorTemperatureToXY(temperature); + return convertXyToHueSat(xy[0], xy[1]); +} + +export function convertXyToHueSat(x: number, y: number): [number, number] { + // Based on: https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/ + const z: number = 1.0 - x - y; + const Y = 1.0; + const X: number = (Y / y) * x; + const Z: number = (Y / y) * z; + + // sRGB D65 conversion + let r: number = (X * 1.656492) - (Y * 0.354851) - (Z * 0.255038); + let g: number = (-X * 0.707196) + (Y * 1.655397) + (Z * 0.036152); + let b: number = (X * 0.051713) - (Y * 0.121364) + (Z * 1.011530); + + // Remove negative values + const m = Math.min(r, g, b); + if (m < 0.0) { + r -= m; + g -= m; + b -= m; + } + + // Normalize + if (r > b && r > g && r > 1.0) { + // red is too big + g = g / r; + b = b / r; + r = 1.0; + } else if (g > b && g > r && g > 1.0) { + // green is too big + r = r / g; + b = b / g; + g = 1.0; + } else if (b > r && b > g && b > 1.0) { + // blue is too big + r = r / b; + g = g / b; + b = 1.0; + } + + // Gamma correction + r = reverseGammaCorrection(r); + g = reverseGammaCorrection(g); + b = reverseGammaCorrection(b); + + // Maximize + const max = Math.max(r, g, b); + r = (r === max) ? 255 : (255 * (r / max)); + g = (g === max) ? 255 : (255 * (g / max)); + b = (b === max) ? 255 : (255 * (b / max)); + + const RGB:IColorRGB = { red: r, green: g, blue: b }; + const HSL = convertRGBtoHSL(RGB); + + const hsv = [HSL.hue, HSL.saturation]; + + return [hsv[0], hsv[1]]; +} + +function convertMiredColorTemperatureToXY(temperature: number): [number, number] { + // Based on MiredColorTemperatureToXY from: + // https://github.com/dresden-elektronik/deconz-rest-plugin/blob/78939ac4ee4b0646fbf542a0f6e83ee995f1a875/colorspace.cpp + const TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD = 4000; + + const TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD = 2222; + const TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD = 4000; + + const TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION = 17440695910400; + const TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION = 15358885888; + const TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION = 57520658; + const TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION = 11790; + + const TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION = 198301902438400; + const TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION = 138086835814; + const TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION = 14590587; + const TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION = 15754; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION = 18126; + const TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION = 22087; + const TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION = 35808; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION = 3312; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION = 15645; + const TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION = 22514; + const TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION = 34265; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION = 2744; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION = 50491; + const TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION = 96229; + const TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION = 61458; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION = 6062; + + let localX = 0; + let localY = 0; + const temp = 1000000 / temperature; + + if (TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD > temp) { + localX = TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION / temp + + TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION - + TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION / temp / temp - + TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION / temp / temp / temp; + } else { + localX = TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION / temp / temp + + TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION / temp + + TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION - + TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION / temp / temp / temp; + } + + if (TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD > temp) { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION * localX / 65536 - + TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION; + } else if (TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD > temp) { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION * localX / 65536 - + TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION; + } else { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION * localX / 65536 + + TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION; + } + + localY *= 4; + + localX /= 0xFFFF; + localY /= 0xFFFF; + + return [Math.round(localX * 10000) / 10000, Math.round(localY * 10000) / 10000]; +} + +function reverseGammaCorrection(v: number): number { + return (v <= 0.0031308) ? 12.92 * v : (1.0 + 0.055) * Math.pow(v, (1.0 / 2.4)) - 0.055; +} \ No newline at end of file From 38c4b1a63c277263ffeba7ad12a750687f16f980 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Mon, 11 Oct 2021 21:04:58 -0400 Subject: [PATCH 14/42] major change to device state --- package-lock.json | 147 +----------- package.json | 1 - src/AccessoryGenerator.ts | 102 +++++--- src/accessories/CCTStrip.ts | 2 +- src/accessories/GRBStrip.ts | 2 +- src/accessories/RGBStrip.ts | 2 +- src/accessories/RGBWBulb.ts | 11 +- src/accessories/RGBWStrip.ts | 6 +- src/accessories/RGBWWBulb.ts | 18 +- src/accessories/RGBWWStrip.ts | 64 +++-- src/magichome-interface/types.ts | 73 ------ src/magichome-interface/utils.ts | 351 --------------------------- src/misc/types.ts | 5 +- src/misc/utils.ts | 23 +- src/platform.ts | 16 +- src/platformAccessory.ts | 396 ++++++++++++++----------------- 16 files changed, 349 insertions(+), 870 deletions(-) delete mode 100644 src/magichome-interface/types.ts delete mode 100644 src/magichome-interface/utils.ts diff --git a/package-lock.json b/package-lock.json index 261898b..c31a45f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -249,52 +249,12 @@ } }, "ansi-align": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", - "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", "dev": true, "requires": { - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "string-width": "^4.1.0" } }, "ansi-colors": { @@ -691,11 +651,6 @@ "object-keys": "^1.0.12" } }, - "dgram": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dgram/-/dgram-1.0.1.tgz", - "integrity": "sha1-N/OyAPgDOl/3WTAwicgc42G2UcM=" - }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -758,11 +713,6 @@ "ansi-colors": "^4.1.1" } }, - "err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" - }, "es-abstract": { "version": "1.18.6", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", @@ -1592,11 +1542,6 @@ "json-buffer": "3.0.0" } }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" - }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -1658,34 +1603,6 @@ "yallist": "^4.0.0" } }, - "magichome-core": { - "version": "0.0.13", - "resolved": "https://registry.npmjs.org/magichome-core/-/magichome-core-0.0.13.tgz", - "integrity": "sha512-CkJCjVrvTXWsrRag3I7KFRdZeZFdDd7t9OsMz+d/Hc5HKm8ohKJg+Y3qSArTe3ArW3uU7I43fgLsBbB/vdxhJQ==", - "requires": { - "color-convert": "^2.0.1", - "dgram": "^1.0.1", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "promise-queue": "^2.2.5" - } - }, - "magichome-platform": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.11.tgz", - "integrity": "sha512-xC7cNbXxCQnUS8K6N3UnXwthRBkGgcS1dTUFo750ClmzpQ36TkJRplE6QNeWOSb9iBBA5G2mEO9uxBWM3W3g0g==", - "requires": { - "dgram": "^1.0.1", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "magichome-core": ">0.0.12", - "promise-queue": "^2.2.5", - "promise-retry": "^2.0.1", - "prompt-sync": "^4.2.0", - "prompts": "^2.4.1", - "uuid": "^8.3.2" - } - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -1960,47 +1877,6 @@ "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=" }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, - "prompt-sync": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/prompt-sync/-/prompt-sync-4.2.0.tgz", - "integrity": "sha512-BuEzzc5zptP5LsgV5MZETjDaKSWfchl5U9Luiu8SKp7iZWD5tZalOxvNcZRwv+d2phNFr8xlbxmFNcRKfJOzJw==", - "requires": { - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "prompts": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", - "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, "pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -2138,11 +2014,6 @@ "lowercase-keys": "^1.0.0" } }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" - }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -2208,11 +2079,6 @@ "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", "dev": true }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" - }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -2535,11 +2401,6 @@ "prepend-http": "^2.0.0" } }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", diff --git a/package.json b/package.json index 3aaacf8..9387156 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,6 @@ "homebridge-lib": "^5.1.14", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", - "magichome-platform": "0.0.11", "promise-queue": "^2.2.5", "queue-promise": "^2.2.1" }, diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index ae43a1e..917c2e3 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -1,12 +1,12 @@ import { BaseController, ControllerGenerator } from 'magichome-platform'; -import { IAccessoryState, MagicHomeAccessory } from './magichome-interface/types'; +import { IAccessoryState, MagicHomeAccessory } from './misc/types'; import { API, HAP, PlatformConfig, } from 'homebridge'; -import { homekitInterface } from './magichome-interface/types'; +import { homekitInterface } from './misc/types'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; @@ -14,16 +14,16 @@ const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; export class AccessoryGenerator { public readonly accessoriesFromDiskMap: Map = new Map(); - + public readonly activeAccessoriesMap: Map = new Map(); private hap: HAP; private api: API; private log; private config: PlatformConfig; private controllerGenerator: ControllerGenerator; - constructor(hap, api, log, config, accessoriesFromDiskMap, controllerGenerator) { - this.hap = hap; + constructor(api, log, config, accessoriesFromDiskMap, controllerGenerator) { this.api = api; + this.hap = api.hap; this.log = log; this.config = config; this.accessoriesFromDiskMap = accessoriesFromDiskMap; @@ -33,13 +33,13 @@ export class AccessoryGenerator { public async generateAccessories() { this.log.warn('started to generate accessories'); return await this.controllerGenerator.discoverControllers().then(async controllers => { + // await this.discoverAccessories(controllers); + // this.registerOfflineAccessories(this.accessoriesFromDiskMap); const accessories = this.discoverAccessories(controllers); return accessories; }).catch(error => { this.log.error(error); }); - - } /** @@ -66,16 +66,55 @@ export class AccessoryGenerator { * which is quite wasteful... */ - rescanAccessories(controllers: Map) { + public async rescanAccessories() { + this.log.warn('started to generate accessories'); + return await this.controllerGenerator.discoverControllers().then(async controllers => { + await this.reDiscoverAccessories(controllers); + }).catch(error => { + this.log.error(error); + }); + } + + reDiscoverAccessories(controllers: Map) { + + const newAccessoriesList: MagicHomeAccessory[] = []; + const existingAccessoriesList: MagicHomeAccessory[] = []; + let accessory; + for (const [uniqueId, controller] of Object.entries(controllers)) { + // this.log.warn(controller); + + const homebridgeUUID = this.hap.uuid.generate(uniqueId); + + if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { + const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); + accessory = this.processExistingAccessory(controller, existingAccessory); + + this.accessoriesFromDiskMap.delete(homebridgeUUID); + + existingAccessoriesList.push(accessory); + this.log.warn('re-registering existing accessory'); + + //this.log('Registering existing accessory...!', accessory); + + } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { + accessory = this.createNewAccessory(controller, homebridgeUUID); + newAccessoriesList.push(accessory); //add it to new accessory list + //this.log.printDeviceInfo('Registering new accessory...!', newAccessory); + this.log.warn('re-registering new accessory'); + } + + this.activeAccessoriesMap.set(homebridgeUUID, accessory); + } - // + this.registerNewAccessories(newAccessoriesList); //register new accessories from scan + this.registerExistingAccessories(existingAccessoriesList); } discoverAccessories(controllers: Map) { const newAccessoriesList: MagicHomeAccessory[] = []; const existingAccessoriesList: MagicHomeAccessory[] = []; - + let accessory; for (const [uniqueId, controller] of Object.entries(controllers)) { // this.log.warn(controller); @@ -84,39 +123,42 @@ export class AccessoryGenerator { if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); - const processedAccessory = this.processExistingAccessory(controller, existingAccessory); + accessory = this.processExistingAccessory(controller, existingAccessory); - this.log.warn(this.accessoriesFromDiskMap.delete(homebridgeUUID)); + this.accessoriesFromDiskMap.delete(homebridgeUUID); - existingAccessoriesList.push(processedAccessory); + existingAccessoriesList.push(accessory); this.log.warn('registering existing accessory'); - //this.log.printDeviceInfo('Registering existing accessory...!', processedAccessory); + //this.log('Registering existing accessory...!', accessory); } else { - const newAccessory = this.createNewAccessory(controller, homebridgeUUID); - newAccessoriesList.push(newAccessory); //add it to new accessory list + accessory = this.createNewAccessory(controller, homebridgeUUID); + newAccessoriesList.push(accessory); //add it to new accessory list //this.log.printDeviceInfo('Registering new accessory...!', newAccessory); this.log.warn('registering new accessory'); - } - - + this.activeAccessoriesMap.set(homebridgeUUID, accessory); } - // this.accessoriesFromDiskMap.forEach((accessory, homebridgeUUID) => { - // const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); - // const processedAccessory = this.processExistingAccessory(controller, existingAccessory); - - // existingAccessoriesList.push(processedAccessory); - // this.log.warn('registering accessory that has been unseen'); - // }); - this.registerNewAccessories(newAccessoriesList); //register new accessories from scan this.registerExistingAccessories(existingAccessoriesList); } + registerOfflineAccessories(accessories) { + accessories.forEach((accessory, homebridgeUUID) => { + accessory.context.restartsSinceSeen++; + // const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); + // const completeDeviceProp: Icustomcomp + // const controller = this.controllerGenerator.createCustomControllers() + // const processedAccessory = this.processExistingAccessory(controller, existingAccessory); + + // existingAccessoriesList.push(processedAccessory); + // this.log.warn('registering accessory that has been unseen'); + }); + } + createNewAccessory(controller: BaseController, homebridgeUUID: string): MagicHomeAccessory { const { @@ -137,9 +179,10 @@ export class AccessoryGenerator { const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; newAccessory.context = { displayName: description as string, restartsSinceSeen: 0 }; + //this.log.warn(description); try { - new homekitInterface[description](this.hap, this.api, newAccessory, this.config, controller); + new homekitInterface[description](this.api, newAccessory, this.config, controller); } catch (error) { this.log.error('The controllerLogicType does not exist in accessoryType list.'); this.log.error(error); @@ -148,6 +191,7 @@ export class AccessoryGenerator { } processExistingAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { + existingAccessory.context.restartsSinceSeen = 0; const cachedInformation = controller.getCachedDeviceInformation(); const { protoDevice: { uniqueId, ipAddress, modelNumber }, @@ -162,7 +206,7 @@ export class AccessoryGenerator { //existingAccessory.context.cachedInformation = cachedInformation; SAME HERE try { - new homekitInterface[description](this.hap, this.api, existingAccessory, this.config, controller); + new homekitInterface[description](this.api, existingAccessory, this.config, controller); } catch (error) { this.log.error('The controllerLogicType does not exist in accessoryType list.'); this.log.error(error); diff --git a/src/accessories/CCTStrip.ts b/src/accessories/CCTStrip.ts index b3779c1..19e2a2f 100644 --- a/src/accessories/CCTStrip.ts +++ b/src/accessories/CCTStrip.ts @@ -1,4 +1,4 @@ -import { clamp } from '../magichome-interface/utils'; +import { clamp } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class CCTStrip extends HomebridgeMagichomeDynamicPlatformAccessory { diff --git a/src/accessories/GRBStrip.ts b/src/accessories/GRBStrip.ts index 4e611fc..64b5893 100644 --- a/src/accessories/GRBStrip.ts +++ b/src/accessories/GRBStrip.ts @@ -1,4 +1,4 @@ -import { clamp, convertHSLtoRGB } from '../magichome-interface/utils'; +import { clamp, convertHSLtoRGB } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { diff --git a/src/accessories/RGBStrip.ts b/src/accessories/RGBStrip.ts index b09973c..dc32b8b 100644 --- a/src/accessories/RGBStrip.ts +++ b/src/accessories/RGBStrip.ts @@ -1,4 +1,4 @@ -import { clamp, convertHSLtoRGB } from '../magichome-interface/utils'; +import { clamp, convertHSLtoRGB } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index 54d4bce..7e8db72 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -1,6 +1,6 @@ import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; -import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../magichome-interface/utils'; +import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { @@ -10,8 +10,9 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; const {hue, saturation} = HSL; const RGB:IColorRGB = convertHSLtoRGB(HSL); - - let {red, green, blue} = RGB, warmWhite; + + let {red, green, blue} = RGB; + let warmWhite; //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); @@ -25,7 +26,7 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { red = Math.round((red / 100) * brightness); green = Math.round((green / 100) * brightness); blue = Math.round((blue / 100) * brightness); - warmWhite = Math.round(2.5 * brightness); + warmWhite = Math.round(2.55 * brightness); if (hue == 31 && saturation == 33) { diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 9cb622d..b3afba7 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -1,6 +1,6 @@ import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; -import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp } from '../magichome-interface/utils'; +import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -24,7 +24,7 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { red = Math.round((red / 100) * brightness); green = Math.round((green / 100) * brightness); blue = Math.round((blue / 100) * brightness); - warmWhite = Math.round(2.5 * brightness); + warmWhite = Math.round(2.55 * brightness); if (hue == 31 && saturation == 33) { diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index e5d4c39..545f15f 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -1,6 +1,6 @@ import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; -import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature } from '../magichome-interface/utils'; +import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { @@ -10,13 +10,13 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; const { hue, saturation } = HSL; const RGB: IColorRGB = convertHSLtoRGB(HSL); - let CCT: IColorCCT; - if (this.ColorCommandMode == 'CCT') { - CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - } else { - CCT = cctToWhiteTemperature(accessoryCommand.colorTemperature); - } - let { red, green, blue } = RGB, { warmWhite, coldWhite } = CCT; + // let _CCT: IColorCCT; + // if (this.ColorCommandMode == 'HSL') { + const _CCT:IColorCCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" + // } else { + // _CCT = cctToWhiteTemperature(colorTemperature); + // } + let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index ff1b1b8..cb8b485 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -1,6 +1,6 @@ import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; -import { IAccessoryCommand, IAccessoryState } from '../magichome-interface/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp } from '../magichome-interface/utils'; +import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { @@ -9,14 +9,14 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; const { hue, saturation } = HSL; - let RGB: IColorRGB = convertHSLtoRGB(HSL); - let CCT: IColorCCT; - if (this.ColorCommandMode == 'CCT') { - CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - } else { - CCT = cctToWhiteTemperature(accessoryCommand.colorTemperature); - } - let { red, green, blue } = RGB, { warmWhite, coldWhite } = CCT; + const RGB: IColorRGB = convertHSLtoRGB(HSL); + // let _CCT: IColorCCT; + // if (this.ColorCommandMode == 'HSL') { + const _CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "convertHueToColorCCT()" + // } else { + // _CCT = cctToWhiteTemperature(colorTemperature); + // } + let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); @@ -51,7 +51,7 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). //White colors were already calculated above - } else if (saturation < 20) { + } else if (saturation < 50) { // this.platform.log.debug('Turning off color'); red = 0; green = 0; @@ -63,9 +63,12 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { //this allows brightness to only affect the white colors, creating beautiful white+color balance //we've set the color saturation to 100% because the higher the white level the more washed out the colors become //the white brightness effectively acts as the saturation value - } else if (saturation < 50) { + } else if (saturation < 70) { - RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation + const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation + red = _RGB.red; + green = _RGB.green; + blue = _RGB.blue; // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); @@ -86,10 +89,11 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; - + let colorTemperature = 140; if (luminance > 0 && isOn) { brightness = luminance; } else if (isOn) { + colorTemperature = whiteTemperatureToCCT({warmWhite, coldWhite}); brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); if (warmWhite > coldWhite) { saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); @@ -98,7 +102,10 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { } } - const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; + + + const accessoryState = { HSL: { hue, saturation, luminance }, colorTemperature, isOn, brightness }; + return accessoryState; } @@ -109,4 +116,29 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); } -} \ No newline at end of file +} + + +// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; +// // eslint-disable-next-line prefer-const +// let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// let brightness = 0; +// //let colorTemperature = 140; +// if (luminance > 0 && isOn) { +// brightness = luminance; +// }else { +// // if(isOn){ +// brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// // } +// // colorTemperature = whiteTemperatureToCCT({warmWhite, coldWhite}); +// // const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// // hue = hueSat[0]; +// // saturation = 10; + +// } + +// const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; +// return accessoryState; +// } \ No newline at end of file diff --git a/src/magichome-interface/types.ts b/src/magichome-interface/types.ts deleted file mode 100644 index d194578..0000000 --- a/src/magichome-interface/types.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { PlatformAccessory } from 'homebridge'; -import { BaseController } from 'magichome-platform'; - -import { Switch } from '../accessories/Switch'; -import { DimmerStrip } from '../accessories/DimmerStrip'; -import { RGBStrip } from '../accessories/RGBStrip'; -import { GRBStrip } from '../accessories/GRBStrip'; -import { RGBWBulb } from '../accessories/RGBWBulb'; -import { RGBWWBulb } from '../accessories/RGBWWBulb'; -import { RGBWStrip } from '../accessories/RGBWStrip'; -import { RGBWWStrip } from '../accessories/RGBWWStrip'; -import { CCTStrip } from '../accessories/CCTStrip'; -import { IDeviceState, IDeviceCommand, IColorCCT } from 'magichome-platform/dist/types'; - - -export const homekitInterface = { - 'Power Socket': Switch, - 'Dimmer': DimmerStrip, - 'GRB Strip': GRBStrip, - 'RGB Strip': RGBStrip, - 'RGBW Non-Simultaneous': RGBWBulb, - 'RGBWW Non-Simultaneous': RGBWWBulb, - 'RGBW Simultaneous': RGBWStrip, - 'RGBWW Simultaneous': RGBWWStrip, - 'CCT Strip': CCTStrip, -}; - -export interface MagicHomeAccessory extends PlatformAccessory { - context: { - displayName: string; - restartsSinceSeen: number, - pendingRegistration?: boolean; - cachedAccessoryState?: IAccessoryState; - } -} - -export interface IAccessoryState { - isOn: boolean, - HSL: IColorHSL, - colorTemperature: number, - brightness: number, -} - -export interface IAccessoryCommand { - isOn?: boolean, - HSL?: IColorHSL, - colorTemperature?: number, - brightness?: number, -} - -export interface IColorHSL { - hue?: number; - saturation?: number; - luminance?: number; -} - -/*----------------------[Constants]----------------------*/ - -export const ColorCommandModes = { - CCT: 'CCT', - HSL: 'HSL', -}; - -export const DefaultAccessoryCommand = { - isOn: true, - HSL: { - hue: 0, - saturation: 100, - luminance: 0, - }, - colorTemperature: 140, - brightness: 100, -}; \ No newline at end of file diff --git a/src/magichome-interface/utils.ts b/src/magichome-interface/utils.ts deleted file mode 100644 index 1ef2b82..0000000 --- a/src/magichome-interface/utils.ts +++ /dev/null @@ -1,351 +0,0 @@ -import { existsSync, readFileSync } from 'fs'; -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; -import { IAccessoryCommand, IAccessoryState, IColorHSL } from './types'; - -export function clamp(value: number, min: number, max: number) { - return Math.min(max, Math.max(min, value)); -} - - -//================================================= -// Start checksum // - - - -/** - * @checksum - * a checksum is needed at the end of the byte array otherwise the message is rejected by the device - * add all bytes and chop off the beginning by & with 0xFF - * @param buffer - * @returns checksum number - */ -export function checksum(buffer: Uint8Array) { - let chk = 0; - - for (const byte of buffer) { - chk += byte; - } - - return chk & 0xff; -} - -//================================================= -// Start Convert RGBtoHSL // -export function convertRGBtoHSL(RGB: IColorRGB) { - const { red, green, blue } = RGB; - const r = red / 255; - const g = green / 255; - const b = blue / 255; - const min = Math.min(r, g, b); - const max = Math.max(r, g, b); - const delta = max - min; - let h = 0; - let s = 0; - - if (max === min) { - h = 0; - } else if (r === max) { - h = (g - b) / delta; - } else if (g === max) { - h = 2 + (b - r) / delta; - } else if (b === max) { - h = 4 + (r - g) / delta; - } - - h = Math.min(h * 60, 360); - - if (h < 0) { - h += 360; - } - - const l = max; - - if (max === min) { - s = 0; - } else if (l <= 0.5) { - s = delta / (max + min); - } else { - s = delta / (2 - max - min); - } - const HSL: IColorHSL = { hue: h, saturation: s * 100, luminance: l * 100 }; - return HSL; -} - -//================================================= -// End Convert RGBtoHSL // - - -//================================================= -// Start Convert HSLtoRGB // -export function convertHSLtoRGB(HSL: IColorHSL): IColorRGB { - - let RGB: IColorRGB; - const { hue, saturation, luminance } = HSL; - const h = hue / 360; - const s = saturation / 100; - const l = 50 / 100; - let t2; - let t3; - let val; - - if (s === 0) { - val = l * 255; - RGB = { red: val, green: val, blue: val }; - } - - if (l < 0.5) { - t2 = l * (1 + s); - } else { - t2 = l + s - l * s; - } - - const t1 = 2 * l - t2; - - const rgb = [0, 0, 0]; - for (let i = 0; i < 3; i++) { - t3 = h + 1 / 3 * -(i - 1); - if (t3 < 0) { - t3++; - } - - if (t3 > 1) { - t3--; - } - - if (6 * t3 < 1) { - val = t1 + (t2 - t1) * 6 * t3; - } else if (2 * t3 < 1) { - val = t2; - } else if (3 * t3 < 2) { - val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; - } else { - val = t1; - } - - rgb[i] = val * 255; - } - RGB = { red: rgb[0], green: rgb[1], blue: rgb[2] }; - return RGB; -} -//================================================= -// End Convert HSLtoRGB // - -export function parseJson(value: string, replacement: T): T { - try { - return JSON.parse(value); - } catch (_error) { - return replacement; - } -} - -export function loadJson(file: string, replacement: T): T { - if (!existsSync(file)) { - return replacement; - } - return parseJson(readFileSync(file).toString(), replacement); -} - -/** - ** @calculateWhiteColor - * determine warmWhite/coldWhite values from hue - * the closer to 0/360 the weaker coldWhite brightness becomes - * the closer to 180 the weaker warmWhite brightness becomes - * the closer to 90/270 the stronger both warmWhite and coldWhite become simultaniously - */ -export function convertHueToColorCCT(hue: number): IColorCCT { - let multiplier = 0; - const colorCCT = { warmWhite: 0, coldWhite: 0 }; - - - if (hue <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue - colorCCT.warmWhite = 255; - multiplier = ((hue / 90)); - colorCCT.coldWhite = Math.round((255 * multiplier)); - } else if (hue > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue - colorCCT.warmWhite = 255; - multiplier = (1 - (hue - 270) / 90); - colorCCT.coldWhite = Math.round((255 * multiplier)); - } else if (hue > 180 && hue <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue - colorCCT.coldWhite = 255; - multiplier = ((hue - 180) / 90); - colorCCT.warmWhite = Math.round((255 * multiplier)); - } else if (hue > 90 && hue <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue - colorCCT.coldWhite = 255; - multiplier = (1 - (hue - 90) / 90); - colorCCT.warmWhite = Math.round((255 * multiplier)); - } - - return colorCCT; -} //hueToWhiteTemperature - -export function cctToWhiteTemperature(CCT: number, multiplier = 0): {warmWhite: number, coldWhite: number} { - CCT -= 140; - let warmWhite, coldWhite; - - const threshold = 110; - if (CCT >= threshold) { - warmWhite = 127; - multiplier = (1-((CCT-threshold) / (360 - threshold))); - coldWhite = Math.round((127 * multiplier)); - } else { - coldWhite = 127; - multiplier = (CCT / threshold); - warmWhite = Math.round((127 * multiplier)); - } - - // this.logs.trace('Calculated accessory %o\'s white values: %o from CCT: %o', this.accessory.context.displayName, {warmWhite, coldWhite}, CCT); - - return {warmWhite, coldWhite}; -} - -/* -export function delayToSpeed(delay: never) { - let clamped = clamp(delay, 1, 31); - clamped -= 1; // bring into interval [0, 30] - return 100 - (clamped / 30) * 100; -} - -export function speedToDelay(speed: never) { - const clamped = clamp(speed, 0, 100); - return 30 - (clamped / 100) * 30 + 1; -} -*/ -export function convertMiredColorTemperatureToHueSat(temperature: number): [number, number] { - const xy = convertMiredColorTemperatureToXY(temperature); - return convertXyToHueSat(xy[0], xy[1]); -} - -export function convertXyToHueSat(x: number, y: number): [number, number] { - // Based on: https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/ - const z: number = 1.0 - x - y; - const Y = 1.0; - const X: number = (Y / y) * x; - const Z: number = (Y / y) * z; - - // sRGB D65 conversion - let r: number = (X * 1.656492) - (Y * 0.354851) - (Z * 0.255038); - let g: number = (-X * 0.707196) + (Y * 1.655397) + (Z * 0.036152); - let b: number = (X * 0.051713) - (Y * 0.121364) + (Z * 1.011530); - - // Remove negative values - const m = Math.min(r, g, b); - if (m < 0.0) { - r -= m; - g -= m; - b -= m; - } - - // Normalize - if (r > b && r > g && r > 1.0) { - // red is too big - g = g / r; - b = b / r; - r = 1.0; - } else if (g > b && g > r && g > 1.0) { - // green is too big - r = r / g; - b = b / g; - g = 1.0; - } else if (b > r && b > g && b > 1.0) { - // blue is too big - r = r / b; - g = g / b; - b = 1.0; - } - - // Gamma correction - r = reverseGammaCorrection(r); - g = reverseGammaCorrection(g); - b = reverseGammaCorrection(b); - - // Maximize - const max = Math.max(r, g, b); - r = (r === max) ? 255 : (255 * (r / max)); - g = (g === max) ? 255 : (255 * (g / max)); - b = (b === max) ? 255 : (255 * (b / max)); - - const RGB:IColorRGB = { red: r, green: g, blue: b }; - const HSL = convertRGBtoHSL(RGB); - - const hsv = [HSL.hue, HSL.saturation]; - - return [hsv[0], hsv[1]]; -} - -function convertMiredColorTemperatureToXY(temperature: number): [number, number] { - // Based on MiredColorTemperatureToXY from: - // https://github.com/dresden-elektronik/deconz-rest-plugin/blob/78939ac4ee4b0646fbf542a0f6e83ee995f1a875/colorspace.cpp - const TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD = 4000; - - const TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD = 2222; - const TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD = 4000; - - const TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION = 17440695910400; - const TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION = 15358885888; - const TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION = 57520658; - const TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION = 11790; - - const TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION = 198301902438400; - const TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION = 138086835814; - const TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION = 14590587; - const TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION = 15754; - - const TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION = 18126; - const TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION = 22087; - const TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION = 35808; - const TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION = 3312; - - const TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION = 15645; - const TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION = 22514; - const TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION = 34265; - const TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION = 2744; - - const TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION = 50491; - const TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION = 96229; - const TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION = 61458; - const TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION = 6062; - - let localX = 0; - let localY = 0; - const temp = 1000000 / temperature; - - if (TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD > temp) { - localX = TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION / temp + - TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION - - TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION / temp / temp - - TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION / temp / temp / temp; - } else { - localX = TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION / temp / temp + - TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION / temp + - TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION - - TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION / temp / temp / temp; - } - - if (TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD > temp) { - localY = TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION * localX / 65536 - - TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION * localX * localX * localX / 281474976710656 - - TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION * localX * localX / 4294967296 - - TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION; - } else if (TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD > temp) { - localY = TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION * localX / 65536 - - TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION * localX * localX * localX / 281474976710656 - - TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION * localX * localX / 4294967296 - - TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION; - } else { - localY = TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION * localX / 65536 + - TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION * localX * localX * localX / 281474976710656 - - TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION * localX * localX / 4294967296 - - TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION; - } - - localY *= 4; - - localX /= 0xFFFF; - localY /= 0xFFFF; - - return [Math.round(localX * 10000) / 10000, Math.round(localY * 10000) / 10000]; -} - -function reverseGammaCorrection(v: number): number { - return (v <= 0.0031308) ? 12.92 * v : (1.0 + 0.055) * Math.pow(v, (1.0 / 2.4)) - 0.055; -} \ No newline at end of file diff --git a/src/misc/types.ts b/src/misc/types.ts index d194578..551e383 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -37,8 +37,8 @@ export interface MagicHomeAccessory extends PlatformAccessory { export interface IAccessoryState { isOn: boolean, HSL: IColorHSL, - colorTemperature: number, - brightness: number, + colorTemperature?: number, + brightness?: number, } export interface IAccessoryCommand { @@ -46,6 +46,7 @@ export interface IAccessoryCommand { HSL?: IColorHSL, colorTemperature?: number, brightness?: number, + isPowerCommand?: boolean, } export interface IColorHSL { diff --git a/src/misc/utils.ts b/src/misc/utils.ts index 1ef2b82..daf89cd 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -178,16 +178,16 @@ export function convertHueToColorCCT(hue: number): IColorCCT { return colorCCT; } //hueToWhiteTemperature -export function cctToWhiteTemperature(CCT: number, multiplier = 0): {warmWhite: number, coldWhite: number} { +export function cctToWhiteTemperature(CCT: number, multiplier = 0): { warmWhite: number, coldWhite: number } { CCT -= 140; let warmWhite, coldWhite; const threshold = 110; - if (CCT >= threshold) { + if (CCT >= threshold) { warmWhite = 127; - multiplier = (1-((CCT-threshold) / (360 - threshold))); + multiplier = (1 - ((CCT - threshold) / (360 - threshold))); coldWhite = Math.round((127 * multiplier)); - } else { + } else { coldWhite = 127; multiplier = (CCT / threshold); warmWhite = Math.round((127 * multiplier)); @@ -195,8 +195,15 @@ export function cctToWhiteTemperature(CCT: number, multiplier = 0): {warmWhite: // this.logs.trace('Calculated accessory %o\'s white values: %o from CCT: %o', this.accessory.context.displayName, {warmWhite, coldWhite}, CCT); - return {warmWhite, coldWhite}; -} + return { warmWhite, coldWhite }; +} + +export function whiteTemperatureToCCT(whiteTemperature: IColorCCT) { + const { coldWhite } = whiteTemperature; + const CCT = (coldWhite * 1.41) + 140; + + return CCT; +} /* export function delayToSpeed(delay: never) { @@ -211,7 +218,7 @@ export function speedToDelay(speed: never) { } */ export function convertMiredColorTemperatureToHueSat(temperature: number): [number, number] { - const xy = convertMiredColorTemperatureToXY(temperature); + const xy = convertMiredColorTemperatureToXY(500 - temperature); return convertXyToHueSat(xy[0], xy[1]); } @@ -264,7 +271,7 @@ export function convertXyToHueSat(x: number, y: number): [number, number] { g = (g === max) ? 255 : (255 * (g / max)); b = (b === max) ? 255 : (255 * (b / max)); - const RGB:IColorRGB = { red: r, green: g, blue: b }; + const RGB: IColorRGB = { red: r, green: g, blue: b }; const HSL = convertRGBtoHSL(RGB); const hsv = [HSL.hue, HSL.saturation]; diff --git a/src/platform.ts b/src/platform.ts index 6e32e26..856c32a 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -1,5 +1,5 @@ import { join } from 'path'; -import { loadJson } from './magichome-interface/utils'; +import { loadJson } from './misc/utils'; import { cloneDeep } from 'lodash'; import { Logs } from './logs'; import { @@ -8,19 +8,13 @@ import { DynamicPlatformPlugin, HAP, Logging, - PlatformAccessory, PlatformConfig, } from 'homebridge'; -import { ICommandOptions, IDeviceAPI, IDeviceCommand, IProtoDevice, ControllerGenerator } from 'magichome-platform'; +import { ControllerGenerator } from 'magichome-platform'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -import { MagicHomeAccessory } from './magichome-interface/types'; -import { BaseController } from 'magichome-platform/dist/DeviceControllers/BaseController'; -//const NEW_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0x81, 0x8a, 0x8b]); -//const LEGACY_COMMAND_QUERY_STATE: Uint8Array = Uint8Array.from([0xEF, 0x01, 0x77]); +import { MagicHomeAccessory } from './misc/types'; import { AccessoryGenerator } from './AccessoryGenerator'; -import { UUID } from 'hap-nodejs'; /** */ @@ -104,9 +98,9 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - const accesssoryGenerator = new AccessoryGenerator(hap, this.api, this.log, this.config, this.accessoriesFromDiskMap, controllerGenerator); + const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.config, this.accessoriesFromDiskMap, controllerGenerator); await accesssoryGenerator.generateAccessories(); - + // this.periodicDiscovery = setInterval( () => accesssoryGenerator.rescanAccessories(), 10000); } diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index f981e26..177b72e 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -1,204 +1,83 @@ -import { API, CharacteristicEventTypes } from 'homebridge'; import type { - Service, PlatformConfig, CharacteristicValue, + API, Service, PlatformConfig, CharacteristicValue, CharacteristicSetCallback, CharacteristicGetCallback, HAP, } from 'homebridge'; -import { clamp, convertHSLtoRGB, convertMiredColorTemperatureToHueSat, convertRGBtoHSL } from './magichome-interface/utils'; -import { getLogs } from './logs'; -import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, MagicHomeAccessory } from './magichome-interface/types'; -import * as types from './magichome-interface/types'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus, IDeviceAPI, IProtoDevice } from 'magichome-platform'; + +import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; +import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, MagicHomeAccessory } from './misc/types'; +import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus, IProtoDevice } from 'magichome-platform'; import { _ } from 'lodash'; import Queue from 'queue-promise'; -import { Hue } from 'hap-nodejs/dist/lib/definitions'; +import { getLogs } from './logs'; const { ready, pending, busy } = DeviceWriteStatus; const CCT = 'CCT'; const HSL = 'HSL'; -const BUFFER_MS = 50; +const BUFFER_MS = 20; +const FINAL_COMMAND_TIMEOUT = 100; +const QUEUE_INTERVAL = 150; + +const SLOW_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 10, bufferMS: 10, timeoutMS: 1000 }; +const MEDIUM_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 10, bufferMS: 10, timeoutMS: 200 }; +const FAST_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 0, bufferMS: 0, timeoutMS: 20 }; + /** * 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 HomebridgeMagichomeDynamicPlatformAccessory { + protected service: Service; - protected colorWhiteThreshold = this.config.whiteEffects.colorWhiteThreshold; - protected colorWhiteThresholdSimultaniousDevices = this.config.whiteEffects.colorWhiteThresholdSimultaniousDevices; - protected colorOffThresholdSimultaniousDevices = this.config.whiteEffects.colorOffThresholdSimultaniousDevices; - protected simultaniousDevicesColorWhite = this.config.whiteEffects.simultaniousDevicesColorWhite; - protected alController; + protected adaptiveLightingService; protected newAccessoryCommand: IAccessoryCommand; protected latestDeviceCommand: IDeviceCommand; + protected latestAccessoryCommand: IAccessoryCommand; protected ColorCommandMode = HSL; - + protected readonly hap: HAP; protected logs = getLogs(); + + protected colorWhiteThreshold; + protected colorWhiteThresholdSimultaniousDevices; + protected colorOffThresholdSimultaniousDevices; + protected simultaniousDevicesColorWhite; + protected accessoryState: IAccessoryState = DefaultAccessoryCommand; protected accessoryStateTemporary: IAccessoryState; protected deviceWriteStatus = ready; - // protected deviceAPI: IDeviceAPI; - protected protoDevice: IProtoDevice; protected queue; protected deviceAPI: { hasBrightness, hasCCT }; - saturationCharacteristic: any; + protected slowQueueRetry = false; //================================================= // Start Constructor // + constructor( - protected readonly hap: HAP, protected readonly api: API, protected readonly accessory: MagicHomeAccessory, public readonly config: PlatformConfig, - private readonly controller: BaseController, + protected readonly controller: BaseController, ) { - this.accessoryState = this.accessory.context.cachedAccessoryState || DefaultAccessoryCommand; - - // this.accessoryState.HSL = Object.assign( DefaultAccessoryCommand.HSL); - this.logs.warn(this.accessoryState); - //get acessory state from device - - - this.queue = new Queue({ - concurrent: 1, - interval: 20, - }); - - let timeout; - - this.queue.on('start', () => { - clearTimeout(timeout); - }); - - this.queue.on('end', async () => { - - timeout = setTimeout(async () => { - this.logs.warn(this.accessory.displayName, ': FINAL STATE', this.latestDeviceCommand); - const options: ICommandOptions = { verifyRetries: 10, bufferMS: 0, timeoutMS: 200 }; - let deviceState: IDeviceState; - if (this.latestDeviceCommand.isOn) { - deviceState = await this.controller.setAllValues(this.latestDeviceCommand, options); - } else { - deviceState = await this.controller.setOn(false, options); - } - //this.accessoryState = deviceStateToAccessoryState(deviceState); - this.accessory.context.cachedAccessoryState = this.accessoryState; + this.colorWhiteThreshold = this.config.whiteEffects.colorWhiteThreshold; + this.colorWhiteThresholdSimultaniousDevices = this.config.whiteEffects.colorWhiteThresholdSimultaniousDevices; + this.colorOffThresholdSimultaniousDevices = this.config.whiteEffects.colorOffThresholdSimultaniousDevices; + this.simultaniousDevicesColorWhite = this.config.whiteEffects.simultaniousDevicesColorWhite; - }, 500); - }); + this.accessoryState = this.accessory.context.cachedAccessoryState || DefaultAccessoryCommand; - this.queue.on('resolve', data => {/** */ }); - this.queue.on('reject', error => {/** */ }); - this.hap = hap; + this.controller = controller; + this.hap = api.hap; this.api = api; - const { - protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, - deviceAPI: { description, hasBrightness, hasCCT, hasColor }, - } = controller.getCachedDeviceInformation(); - // set accessory information - this.accessory.getService(hap.Service.AccessoryInformation)! - .setCharacteristic(hap.Characteristic.Manufacturer, 'MagicHome') - .setCharacteristic(hap.Characteristic.SerialNumber, uniqueId) - .setCharacteristic(hap.Characteristic.Model, modelNumber) - .setCharacteristic(hap.Characteristic.HardwareRevision, controllerHardwareVersion.toString(16)) - .setCharacteristic(hap.Characteristic.FirmwareRevision, controllerFirmwareVersion.toString(16)) - .getCharacteristic(hap.Characteristic.Identify) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below - - this.accessory.getService(hap.Service.AccessoryInformation)! - .addOptionalCharacteristic(hap.Characteristic.ConfiguredName); - - - // get the LightBulb service if it exists, otherwise create a new LightBulb service - // you can create multiple services for each accessory - if (hasBrightness) { - - if (this.accessory.getService(hap.Service.Switch)) { - this.accessory.removeService(this.accessory.getService(hap.Service.Switch)); - } - - this.service = this.accessory.getService(hap.Service.Lightbulb) ?? this.accessory.addService(hap.Service.Lightbulb); - - this.service.getCharacteristic(hap.Characteristic.ConfiguredName) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); - - // register handlers for the Brightness Characteristic - this.service.getCharacteristic(hap.Characteristic.Brightness) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setBrightness.bind(this)) // SET - bind to the 'setBrightness` method below - .on(CharacteristicEventTypes.GET, this.getBrightness.bind(this)); // GET - bind to the 'getBrightness` method below - - if (hasColor) { - - // register handlers for the Hue Characteristic - this.logs.trace('Adding Hue characteristic to device.'); - this.service.getCharacteristic(hap.Characteristic.Hue) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setHue.bind(this)) // SET - bind to the 'setHue` method below - .on(CharacteristicEventTypes.GET, this.getHue.bind(this)); // GET - bind to the 'getHue` method below - - // register handlers for the Saturation Characteristic - this.logs.trace('Adding Saturation characteristic to device.'); - this.saturationCharacteristic = this.service.getCharacteristic(hap.Characteristic.Saturation) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setSaturation.bind(this)); // SET - bind to the 'setSaturation` method below - //.on(CharacteristicEventTypes.GET, this.getSaturation.bind(this)); // GET - bind to the 'getSaturation` method below - // register handlers for the On/Off Characteristic - - } - - if (hasCCT) { - // register handlers for the Saturation Characteristic - this.logs.trace('Adding ColorTemperature characteristic to device.'); - this.service.getCharacteristic(hap.Characteristic.ColorTemperature) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setColorTemperature.bind(this)) // SET - bind to the 'setSaturation` method below - .on(CharacteristicEventTypes.GET, this.getColorTemperature.bind(this)); // GET - bind to the 'getSaturation` method below - - if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { - this.logs.trace('Adding the adaptive lighting controller to the accessory...'); - this.alController = new this.api.hap.AdaptiveLightingController(this.service); - this.accessory.configureController(this.alController); - } - } - } else { - //device is switch, register it as such - this.logs.trace('Adding Switch service to device.'); - this.service = this.accessory.getService(hap.Service.Switch) ?? this.accessory.addService(hap.Service.Switch); - this.service.getCharacteristic(hap.Characteristic.ConfiguredName) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setConfiguredName.bind(this)); - - } - // register handlers for the On/Off Characteristic - this.logs.trace('Adding On characteristic to device.'); - this.service.getCharacteristic(hap.Characteristic.On) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.setOn.bind(this)) // SET - bind to the `setOn` method below - .on(CharacteristicEventTypes.GET, this.getOn.bind(this)); // GET - bind to the `getOn` method below - - this.updateLocalState(); - // set the service name, this is what is displayed as the default name on the Home app - // in this example we are using the name we stored in the `accessory.context` in the `discoverDevices` method. - - // this.logListeners(); - + this.setupCommandQueue(); + this.initializeCharacteristics(); + this.fetchAndUpdateState(2); } //================================================= @@ -216,6 +95,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setHue(value: CharacteristicValue, callback: CharacteristicSetCallback) { callback(null); + this.accessoryState.HSL.hue = value as number; this.ColorCommandMode = HSL; @@ -226,6 +106,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setSaturation(value: CharacteristicValue, callback: CharacteristicSetCallback) { callback(null); + this.accessoryState.HSL.saturation = value as number; this.ColorCommandMode = HSL; @@ -237,8 +118,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { callback(null); + this.accessoryState.brightness = value as number; const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; - this.logs.error(accessoryCommand); this.processAccessoryCommand(accessoryCommand); } @@ -276,22 +157,21 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { const hue = this.accessoryState.HSL.hue; callback(null, hue); - this.updateLocalState(); + this.fetchAndUpdateState(2); } getColorTemperature(callback: CharacteristicGetCallback) { const colorTemperature = this.accessoryState.colorTemperature; callback(null, colorTemperature); //immediately return cached state to prevent laggy HomeKit UI - - this.updateLocalState(); + this.fetchAndUpdateState(3); } getBrightness(callback: CharacteristicGetCallback) { const brightness = this.accessoryState.brightness; callback(null, brightness); //immediately return cached state to prevent laggy HomeKit UI - this.updateLocalState(); + this.fetchAndUpdateState(2); } /** @@ -303,8 +183,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { const isOn = this.accessoryState.isOn; callback(null, isOn); //immediately return cached state to prevent laggy HomeKit UI - - this.updateLocalState(); + this.fetchAndUpdateState(2); } flashEffect() { @@ -317,7 +196,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { const deviceWriteStatus = this.deviceWriteStatus; - this.logs.info(this.deviceWriteStatus); + this.logs.trace(this.deviceWriteStatus); switch (deviceWriteStatus) { case ready: @@ -325,16 +204,12 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { await this.writeStateToDevice(accessoryCommand).then((msg) => { //error logging }).finally(() => { - //this.newAccessoryCommand = DefaultCommand; this.deviceWriteStatus = ready; }); break; case pending: _.merge(this.newAccessoryCommand, accessoryCommand); - // Object.assign(this.newAccessoryCommand, accessoryCommand); - // Object.assign(this.newAccessoryCommand.HSL, accessoryCommand.HSL); - //this.logs.warn('PENDING', this.newAccessoryCommand); break; } } @@ -342,21 +217,21 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async writeStateToDevice(accessoryCommand: IAccessoryCommand): Promise { this.newAccessoryCommand = accessoryCommand; return new Promise((resolve, reject) => { - this.logs.info(this.ColorCommandMode); + this.logs.trace(this.ColorCommandMode); return setTimeout(() => { - this.logs.warn(this.accessory.context.displayName, '\nthis.accessoryState: ', this.accessoryState, '\n this.newAccessoryCommand: ', this.newAccessoryCommand); - const sanitizedAcessoryCommand = _.merge({}, this.accessoryState, this.newAccessoryCommand); - // const sanitizedAcessoryCommand = Object.assign({}, this.accessoryState, this.newAccessoryCommand); - // sanitizedAcessoryCommand.HSL = Object.assign({}, this.accessoryState.HSL, this.newAccessoryCommand.HSL); - this.logs.warn('\nSanatizedCommand: ', sanitizedAcessoryCommand); + this.logs.trace(this.accessory.context.displayName, '\nthis.accessoryState: ', this.accessoryState, '\n this.newAccessoryCommand: ', this.newAccessoryCommand); + const sanitizedAcessoryCommand: IAccessoryCommand = _.merge({}, this.accessoryState, this.newAccessoryCommand); + + // eslint-disable-next-line no-prototype-builtins + if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { + sanitizedAcessoryCommand.isPowerCommand = true; + } + + this.logs.trace('\nSanatizedCommand: ', sanitizedAcessoryCommand); - //this.logs.warn(sanitizedAcessoryCommand); this.deviceWriteStatus = ready; - //console.log('everything is probably fine', this.deviceAPI.description, this.protoDevice.uniqueId, this.deviceState.controllerHardwareVersion.toString(16), this.deviceAPI.needsPowerCommand, this.deviceState.controllerFirmwareVersion) - return this.prepareCommand(sanitizedAcessoryCommand).then(state => { - //set current state to state - }); + return this.prepareCommand(sanitizedAcessoryCommand); }, BUFFER_MS); }); } @@ -364,15 +239,28 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async prepareCommand(accessoryCommand: IAccessoryCommand) { const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); this.latestDeviceCommand = deviceCommand; - - this.queue.enqueue(() => { - const options: ICommandOptions = { verifyRetries: 0, bufferMS: 0, timeoutMS: 100 }; - this.accessoryState = Object.assign(accessoryCommand); + this.latestAccessoryCommand = accessoryCommand; + this.queue.enqueue(async () => { + let options: ICommandOptions = MEDIUM_COMMAND_OPTIONS; + //this.accessoryState = Object.assign(accessoryCommand); //this.logs.warn(deviceCommand); - if (deviceCommand.isOn) { - return this.controller.setAllValues(deviceCommand, options); - } else { - return this.controller.setOn(false, options); + + if (this.queue.size > 0) { + this.slowQueueRetry = true; + options = FAST_COMMAND_OPTIONS; + } + + if (!(this.slowQueueRetry && this.queue.size < 1)) { + let deviceState: IDeviceState; + + if (!accessoryCommand.isPowerCommand) { + deviceState = await this.controller.setAllValues(deviceCommand, options); + } else { + deviceState = await this.controller.setOn(deviceCommand.isOn, options); + } + + this.updateLocalState(0, deviceState); + return deviceState; } }); @@ -390,11 +278,36 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { return deviceCommand; } - protected async updateLocalState() { - const deviceState = await this.controller.fetchState(); - const accessoryState = this.deviceStateToAccessoryState(deviceState); - _.merge(this.accessoryState, accessoryState); - this.updateHomekitState(); + protected async updateLocalState(requestLevel, deviceState) { + if (!deviceState) { + deviceState = await this.controller.fetchState(); + } + + const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); + let accessoryState: IAccessoryState; + if (deviceState) { + switch (requestLevel) { + case 0: + accessoryState = { HSL: { luminance }, isOn }; + break; + case 1: + accessoryState = { HSL: { hue, luminance }, isOn }; + break; + case 2: + accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; + break; + case 3: + accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; + break; + } + // if (deviceState && deviceState.LED.isOn) { + _.merge(this.accessoryState, accessoryState); + // } + this.accessory.context.cachedAccessoryState = this.accessoryState; + this.logs.trace(this.accessory.displayName, ': FINAL STATE', this.accessoryState); + } else { + _.merge(this.accessoryState, { isOn: false }); + } } updateHomekitState() { @@ -426,25 +339,76 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { return accessoryState; } - // /** - // * This is a debug function to show the number of listeners for each .on event. - // */ - // logListeners() { - // this.logs.warn('On set Listener count: ', this.service.getCharacteristic(hap.Characteristic.On).listenerCount('set')); - // this.logs.warn('Identify set Listener count: ', this.service.getCharacteristic(hap.Characteristic.Identify).listenerCount('set')); - // this.logs.warn('Name set Listener count: ', this.service.getCharacteristic(hap.Characteristic.ConfiguredName).listenerCount('set')); - // this.logs.warn('Brightness set Listener count: ', this.service.getCharacteristic(hap.Characteristic.Brightness).listenerCount('set')); - // this.logs.warn('Hue set Listener count: ', this.service.getCharacteristic(hap.Characteristic.Hue).listenerCount('set')); - // this.logs.warn('Sat set Listener count: ', this.service.getCharacteristic(hap.Characteristic.Saturation).listenerCount('set')); - // this.logs.warn('Manufacturer set: Listener count: ', this.service.setCharacteristic(hap.Characteristic.Manufacturer, null).listenerCount('set') ); - - // this.logs.warn('On get Listener count: ', this.service.getCharacteristic(hap.Characteristic.On).listenerCount('get')); - // this.logs.warn('Identify get Listener count: ', this.service.getCharacteristic(hap.Characteristic.Identify).listenerCount('get')); - // this.logs.warn('Name get Listener count: ', this.service.getCharacteristic(hap.Characteristic.ConfiguredName).listenerCount('get')); - // this.logs.warn('Brightness get Listener count: ', this.service.getCharacteristic(hap.Characteristic.Brightness).listenerCount('get')); - // this.logs.warn('Hue get Listener count: ', this.service.getCharacteristic(hap.Characteristic.Hue).listenerCount('get')); - // this.logs.warn('Sat get Listener count: ', this.service.getCharacteristic(hap.Characteristic.Saturation).listenerCount('get')); - // this.logs.warn('Manufacturer get: Listener count: ', this.service.setCharacteristic(hap.Characteristic.Manufacturer, null).listenerCount('get') ); - //} -} // ZackneticMagichomePlatformAccessory class + setupCommandQueue() { + this.queue = new Queue({ + concurrent: 1, + interval: QUEUE_INTERVAL, + }); + + let timeout; + + this.queue.on('start', () => { + clearTimeout(timeout); + }); + + this.queue.on('end', async () => { + if (this.slowQueueRetry) { + timeout = setTimeout(async () => { + this.logs.trace(this.accessory.displayName, ': FINAL WRITE', this.latestDeviceCommand); + let deviceState: IDeviceState; + + + if (!this.latestAccessoryCommand.isPowerCommand) { + deviceState = await this.controller.setAllValues(this.latestDeviceCommand, SLOW_COMMAND_OPTIONS); + } else { + deviceState = await this.controller.setOn(this.latestDeviceCommand.isOn, SLOW_COMMAND_OPTIONS); + } + + this.slowQueueRetry = false; + this.updateLocalState(0, deviceState); + this.updateHomekitState(); + }, FINAL_COMMAND_TIMEOUT); + } + + }); + + this.queue.on('resolve', data => {/** */ }); + this.queue.on('reject', error => {/** */ }); + } + + initializeCharacteristics() { + + const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = this.controller.getCachedDeviceInformation(); + + addAccessoryInformationCharacteristic(this); + + this.logs.trace('Adding Lightbulb service to accessory.'); + this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); + + if (hasColor) { + addHueCharacteristic(this); + addSaturationCharacteristic(this); + } + + if (hasBrightness) { + addBrightnessCharacteristic(this); + } + + if (hasCCT) { + addColorTemperatureCharacteristic(this); + } + + if (!hasBrightness) { + this.logs.trace('Adding Switch service to accessory.'); //device is switch, register it as such + this.service = this.accessory.getService(this.hap.Service.Switch) ?? this.accessory.addService(this.hap.Service.Switch); + } + addOnCharacteristic(this); + addConfiguredNameCharacteristic(this); + } + + async fetchAndUpdateState(requestLevel) { + await this.updateLocalState(requestLevel, null); + this.updateHomekitState(); + } +} // ZackneticMagichomePlatformAccessory class \ No newline at end of file From 8a00cfd5da8bb730c1ce1ab64a193ae5f8385db7 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Thu, 14 Oct 2021 13:16:25 -0400 Subject: [PATCH 15/42] Updated On/Off handler --- package-lock.json | 5 +++ package.json | 3 +- src/AccessoryGenerator.ts | 34 +++++++------------- src/accessories/RGBWStrip.ts | 36 ++++++++++++++------- src/accessories/RGBWWStrip.ts | 59 +++++++++++++---------------------- src/platform.ts | 8 ++--- src/platformAccessory.ts | 12 ++++--- 7 files changed, 77 insertions(+), 80 deletions(-) diff --git a/package-lock.json b/package-lock.json index c31a45f..09144d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1682,6 +1682,11 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "node-color-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/node-color-log/-/node-color-log-6.0.0.tgz", + "integrity": "sha512-zaDIxwDZWCwjcndvyXY30sT+h6pcviEvIpuSGZx2kBKVPloMU5xcFgHK85cnAmMeaDyL4xQmbSsGzp3fwOt3Bg==" + }, "node-persist": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", diff --git a/package.json b/package.json index 9387156..50607bd 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "main": "dist/index.js", "scripts": { "lint": "eslint src/**.ts", - "watch": "npm run build && npm link && nodemon", + "watch": "npm run build && nodemon", "build": "rimraf ./dist && tsc", "prepublishOnly": "npm run lint && npm run build" }, @@ -65,6 +65,7 @@ "homebridge-lib": "^5.1.14", "lodash": "^4.17.21", "lodash.debounce": "^4.0.8", + "node-color-log": "^6.0.0", "promise-queue": "^2.2.5", "queue-promise": "^2.2.1" }, diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 917c2e3..7a796f9 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -31,9 +31,8 @@ export class AccessoryGenerator { } public async generateAccessories() { - this.log.warn('started to generate accessories'); + this.log.info('Scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { - // await this.discoverAccessories(controllers); // this.registerOfflineAccessories(this.accessoriesFromDiskMap); const accessories = this.discoverAccessories(controllers); return accessories; @@ -67,7 +66,7 @@ export class AccessoryGenerator { */ public async rescanAccessories() { - this.log.warn('started to generate accessories'); + this.log.trace('Re-scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { await this.reDiscoverAccessories(controllers); }).catch(error => { @@ -92,22 +91,20 @@ export class AccessoryGenerator { this.accessoriesFromDiskMap.delete(homebridgeUUID); existingAccessoriesList.push(accessory); - this.log.warn('re-registering existing accessory'); - - //this.log('Registering existing accessory...!', accessory); + this.log.info('Found previously unreachable existing accessory. Updating...'); } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { accessory = this.createNewAccessory(controller, homebridgeUUID); newAccessoriesList.push(accessory); //add it to new accessory list //this.log.printDeviceInfo('Registering new accessory...!', newAccessory); - this.log.warn('re-registering new accessory'); + this.log.info('Found previously unseen accessory during a re-scan. Registering...'); } this.activeAccessoriesMap.set(homebridgeUUID, accessory); } this.registerNewAccessories(newAccessoriesList); //register new accessories from scan - this.registerExistingAccessories(existingAccessoriesList); + this.updateExistingAccessories(existingAccessoriesList); } discoverAccessories(controllers: Map) { @@ -121,29 +118,24 @@ export class AccessoryGenerator { const homebridgeUUID = this.hap.uuid.generate(uniqueId); if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { + this.log.info('Found existing accessory. Updating...'); const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); accessory = this.processExistingAccessory(controller, existingAccessory); - this.accessoriesFromDiskMap.delete(homebridgeUUID); - existingAccessoriesList.push(accessory); - this.log.warn('registering existing accessory'); - - //this.log('Registering existing accessory...!', accessory); - } else { + this.log.info('Found new accessory. Registering...'); + accessory = this.createNewAccessory(controller, homebridgeUUID); newAccessoriesList.push(accessory); //add it to new accessory list - //this.log.printDeviceInfo('Registering new accessory...!', newAccessory); - this.log.warn('registering new accessory'); } this.activeAccessoriesMap.set(homebridgeUUID, accessory); } this.registerNewAccessories(newAccessoriesList); //register new accessories from scan - this.registerExistingAccessories(existingAccessoriesList); + this.updateExistingAccessories(existingAccessoriesList); } registerOfflineAccessories(accessories) { @@ -202,8 +194,6 @@ export class AccessoryGenerator { return; } - this.log.info(existingAccessory.context.displayName); - //existingAccessory.context.cachedInformation = cachedInformation; SAME HERE try { new homekitInterface[description](this.api, existingAccessory, this.config, controller); @@ -221,7 +211,7 @@ export class AccessoryGenerator { } - registerExistingAccessories(existingAccessories: MagicHomeAccessory[]) { + updateExistingAccessories(existingAccessories: MagicHomeAccessory[]) { this.api.updatePlatformAccessories(existingAccessories); } @@ -253,8 +243,8 @@ export class AccessoryGenerator { isAllowed(uniqueId: string): boolean { - const blacklistedUniqueIDs = this.config.deviceManagement.blacklistedUniqueIDs; - const isWhitelist: boolean = this.config.deviceManagement.blacklistOrWhitelist.includes('whitelist'); + const blacklistedUniqueIDs = this.config.deviceManagement.blacklistedUniqueIDs ?? []; + const isWhitelist: boolean = this.config.deviceManagement.blacklistOrWhitelist.includes('whitelist') ?? false; const onList: boolean = (blacklistedUniqueIDs).includes(uniqueId); const isAllowed = isWhitelist ? onList : !onList; diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index b3afba7..17e90dd 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -1,6 +1,6 @@ import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp } from '../misc/utils'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp, convertMiredColorTemperatureToHueSat, whiteTemperatureToCCT } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -10,7 +10,7 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; const { hue, saturation } = HSL; - let RGB: IColorRGB = convertHSLtoRGB(HSL); + const RGB: IColorRGB = convertHSLtoRGB(HSL); let { red, green, blue } = RGB, warmWhite; @@ -48,7 +48,15 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { //the white brightness effectively acts as the saturation value } else if (saturation < 50) { - RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation + const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation + red = _RGB.red; + green = _RGB.green; + blue = _RGB.blue; + + red = Math.round((red / 100) * (saturation * 2)); + green = Math.round((green / 100) * (saturation * 2)); + blue = Math.round((blue / 100) * (saturation * 2)); + // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); @@ -68,19 +76,25 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; - + let colorTemperature = 140; if (luminance > 0 && isOn) { brightness = luminance; - } else if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - if (warmWhite > coldWhite) { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); - } else { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + if (coldWhite > 0 || warmWhite > 0) { + saturation = 25; + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); } + } else { + if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + } + colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); + const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); + hue = hueSat[0]; + saturation = 10; + } - const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; + const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; return accessoryState; } diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index cb8b485..77d4deb 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -1,6 +1,6 @@ import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT } from '../misc/utils'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { @@ -12,7 +12,7 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { const RGB: IColorRGB = convertHSLtoRGB(HSL); // let _CCT: IColorCCT; // if (this.ColorCommandMode == 'HSL') { - const _CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "convertHueToColorCCT()" + const _CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "convertHueToColorCCT()" // } else { // _CCT = cctToWhiteTemperature(colorTemperature); // } @@ -51,7 +51,7 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). //White colors were already calculated above - } else if (saturation < 50) { + } else if (saturation < 20) { // this.platform.log.debug('Turning off color'); red = 0; green = 0; @@ -63,13 +63,17 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { //this allows brightness to only affect the white colors, creating beautiful white+color balance //we've set the color saturation to 100% because the higher the white level the more washed out the colors become //the white brightness effectively acts as the saturation value - } else if (saturation < 70) { + } else if (saturation <= 50) { const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation red = _RGB.red; green = _RGB.green; blue = _RGB.blue; + red = Math.round((red / 100) * (saturation * 2)); + green = Math.round((green / 100) * (saturation * 2)); + blue = Math.round((blue / 100) * (saturation * 2)); + // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs @@ -92,20 +96,22 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { let colorTemperature = 140; if (luminance > 0 && isOn) { brightness = luminance; - } else if (isOn) { - colorTemperature = whiteTemperatureToCCT({warmWhite, coldWhite}); - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - if (warmWhite > coldWhite) { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); - } else { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + if (coldWhite > 0 || warmWhite > 0) { + saturation = 25; + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); } - } - - + } else { + if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + } + colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); + const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); + hue = hueSat[0]; + saturation = 10; - const accessoryState = { HSL: { hue, saturation, luminance }, colorTemperature, isOn, brightness }; + } + const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; return accessoryState; } @@ -119,26 +125,3 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { } -// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - -// const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; -// // eslint-disable-next-line prefer-const -// let { hue, saturation, luminance } = convertRGBtoHSL(RGB); -// let brightness = 0; -// //let colorTemperature = 140; -// if (luminance > 0 && isOn) { -// brightness = luminance; -// }else { -// // if(isOn){ -// brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); -// // } -// // colorTemperature = whiteTemperatureToCCT({warmWhite, coldWhite}); -// // const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); -// // hue = hueSat[0]; -// // saturation = 10; - -// } - -// const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; -// return accessoryState; -// } \ No newline at end of file diff --git a/src/platform.ts b/src/platform.ts index 856c32a..982a7b9 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -15,7 +15,7 @@ import { ControllerGenerator } from 'magichome-platform'; import { MagicHomeAccessory } from './misc/types'; import { AccessoryGenerator } from './AccessoryGenerator'; - +import logger from 'node-color-log'; /** */ @@ -53,7 +53,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin //this.logs = getLogger(); this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); - this.log.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); + logger.reverse().log('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); // When this event is fired it means Homebridge has restored all cached accessories from disk. // Dynamic Platform plugins should only register new accessories after this event was fired, @@ -80,7 +80,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const homebridgeUUID = accessory.UUID; this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); - this.log.debug('%o - Loading accessory from cache...', this.accessoriesFromDiskMap.keys.length, accessory.context.displayName); + this.log.debug(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); } @@ -100,7 +100,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.config, this.accessoriesFromDiskMap, controllerGenerator); await accesssoryGenerator.generateAccessories(); - // this.periodicDiscovery = setInterval( () => accesssoryGenerator.rescanAccessories(), 10000); + this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 10000); } diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 177b72e..520e27b 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -1,6 +1,6 @@ import type { API, Service, PlatformConfig, CharacteristicValue, - CharacteristicSetCallback, CharacteristicGetCallback, HAP, + CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, } from 'homebridge'; import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; @@ -9,7 +9,7 @@ import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, add import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus, IProtoDevice } from 'magichome-platform'; import { _ } from 'lodash'; import Queue from 'queue-promise'; -import { getLogs } from './logs'; +import { Logs } from './logs'; const { ready, pending, busy } = DeviceWriteStatus; const CCT = 'CCT'; @@ -40,7 +40,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected ColorCommandMode = HSL; protected readonly hap: HAP; - protected logs = getLogs(); + protected logs; protected colorWhiteThreshold; @@ -63,8 +63,10 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected readonly accessory: MagicHomeAccessory, public readonly config: PlatformConfig, protected readonly controller: BaseController, + protected readonly logging: Logging, ) { + this.colorWhiteThreshold = this.config.whiteEffects.colorWhiteThreshold; this.colorWhiteThresholdSimultaniousDevices = this.config.whiteEffects.colorWhiteThresholdSimultaniousDevices; this.colorOffThresholdSimultaniousDevices = this.config.whiteEffects.colorOffThresholdSimultaniousDevices; @@ -75,6 +77,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.controller = controller; this.hap = api.hap; this.api = api; + + this.logs = new Logs(logging, this.config.loggingLevel ?? 3); this.setupCommandQueue(); this.initializeCharacteristics(); this.fetchAndUpdateState(2); @@ -171,7 +175,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { const brightness = this.accessoryState.brightness; callback(null, brightness); //immediately return cached state to prevent laggy HomeKit UI - this.fetchAndUpdateState(2); + // this.fetchAndUpdateState(2); } /** From 7e5526f86985dcb23375ee57a9c16532b9ab170c Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 16 Oct 2021 12:37:42 -0400 Subject: [PATCH 16/42] update characteristic binding --- .homebridge-dev/config.json | 2 +- src/AccessoryGenerator.ts | 37 ++++--- src/accessories/RGBWBulb.ts | 16 +-- src/accessories/RGBWStrip.ts | 28 ++---- src/accessories/RGBWWBulb.ts | 33 +++---- src/accessories/RGBWWStrip.ts | 27 ++--- src/logs.ts | 2 +- src/misc/serviceCharacteristics.ts | 106 +++++++++++++------- src/misc/types.ts | 10 ++ src/misc/utils.ts | 2 - src/platform.ts | 10 +- src/platformAccessory.ts | 154 ++++++++++++++--------------- 12 files changed, 219 insertions(+), 208 deletions(-) diff --git a/.homebridge-dev/config.json b/.homebridge-dev/config.json index 283ce78..c522a73 100644 --- a/.homebridge-dev/config.json +++ b/.homebridge-dev/config.json @@ -27,7 +27,7 @@ "simultaniousDevicesColorWhite": true, "colorWhiteThreshold": 10, "colorWhiteThresholdSimultaniousDevices": 50, - "colorOffThresholdSimultaniousDevices": 5 + "colorOffThresholdSimultaniousDevices": 1 }, "deviceManagement": { "blacklistOrWhitelist": "blacklist", diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 7a796f9..76a36ef 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -1,4 +1,4 @@ -import { BaseController, ControllerGenerator } from 'magichome-platform'; +import { BaseController, ControllerGenerator, ICustomProtoDevice, IDeviceAPI } from 'magichome-platform'; import { IAccessoryState, MagicHomeAccessory } from './misc/types'; import { API, @@ -6,6 +6,7 @@ import { PlatformConfig, } from 'homebridge'; +import { _ } from 'lodash'; import { homekitInterface } from './misc/types'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; @@ -33,9 +34,11 @@ export class AccessoryGenerator { public async generateAccessories() { this.log.info('Scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { - // this.registerOfflineAccessories(this.accessoriesFromDiskMap); const accessories = this.discoverAccessories(controllers); + this.registerOfflineAccessories(this.accessoriesFromDiskMap); + return accessories; + }).catch(error => { this.log.error(error); }); @@ -139,12 +142,11 @@ export class AccessoryGenerator { } registerOfflineAccessories(accessories) { - accessories.forEach((accessory, homebridgeUUID) => { - accessory.context.restartsSinceSeen++; - // const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); - // const completeDeviceProp: Icustomcomp - // const controller = this.controllerGenerator.createCustomControllers() - // const processedAccessory = this.processExistingAccessory(controller, existingAccessory); + accessories.forEach(async (offlineAccessory, homebridgeUUID) => { + offlineAccessory.context.restartsSinceSeen++; + const { protoDevice, deviceAPI } = offlineAccessory.context; + const controller = await this.controllerGenerator.createCustomControllers({ protoDevice, deviceAPI })[0]; + new homekitInterface[deviceAPI.description](this.api, offlineAccessory, this.config, controller, this.log); // existingAccessoriesList.push(processedAccessory); // this.log.warn('registering accessory that has been unseen'); @@ -154,6 +156,8 @@ export class AccessoryGenerator { createNewAccessory(controller: BaseController, homebridgeUUID: string): MagicHomeAccessory { const { + protoDevice, + deviceAPI, protoDevice: { uniqueId }, deviceAPI: { description }, deviceState: { LED: { RGB, CCT, isOn } }, @@ -170,11 +174,11 @@ export class AccessoryGenerator { // const accessoryState: IAccessoryState = {isOn, } JUST KIDDING, DO IT AFTER INITIALIZING DEVICE const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; - newAccessory.context = { displayName: description as string, restartsSinceSeen: 0 }; + newAccessory.context = { protoDevice, deviceAPI, displayName: description as string, restartsSinceSeen: 0 }; //this.log.warn(description); try { - new homekitInterface[description](this.api, newAccessory, this.config, controller); + new homekitInterface[description](this.api, newAccessory, this.config, controller, this.log); } catch (error) { this.log.error('The controllerLogicType does not exist in accessoryType list.'); this.log.error(error); @@ -186,6 +190,8 @@ export class AccessoryGenerator { existingAccessory.context.restartsSinceSeen = 0; const cachedInformation = controller.getCachedDeviceInformation(); const { + protoDevice, + deviceAPI, protoDevice: { uniqueId, ipAddress, modelNumber }, deviceState, deviceAPI: { description }, } = cachedInformation; @@ -194,9 +200,9 @@ export class AccessoryGenerator { return; } - //existingAccessory.context.cachedInformation = cachedInformation; SAME HERE + _.merge(existingAccessory.context, { protoDevice, deviceAPI, restartsSinceSeen: 0 }); try { - new homekitInterface[description](this.api, existingAccessory, this.config, controller); + new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.log); } catch (error) { this.log.error('The controllerLogicType does not exist in accessoryType list.'); this.log.error(error); @@ -230,7 +236,7 @@ export class AccessoryGenerator { `Successfully pruned accessory: ${existingAccessory.context.displayName} due to being marked for deletion\n`); isFresh = false; - } else if (this.config.pruning.pruneRestarts) { + } else if (this.config.pruning?.pruneRestarts ?? false) { if (existingAccessory.context.restartsSinceSeen >= this.config.pruning.pruneRestarts) { this.unregisterAccessory(existingAccessory, `Successfully pruned accessory: ${existingAccessory.context.displayName} which had not being seen for ${existingAccessory.context.restartsSinceSeen} restart(s).\n`); @@ -243,13 +249,14 @@ export class AccessoryGenerator { isAllowed(uniqueId: string): boolean { - const blacklistedUniqueIDs = this.config.deviceManagement.blacklistedUniqueIDs ?? []; - const isWhitelist: boolean = this.config.deviceManagement.blacklistOrWhitelist.includes('whitelist') ?? false; + const blacklistedUniqueIDs = this.config.deviceManagement?.blacklistedUniqueIDs ?? []; + const isWhitelist: boolean = this.config.deviceManagement?.blacklistOrWhitelist?.includes('whitelist') ?? false; const onList: boolean = (blacklistedUniqueIDs).includes(uniqueId); const isAllowed = isWhitelist ? onList : !onList; return isAllowed; + return true; } unregisterAccessory(existingAccessory: MagicHomeAccessory, reason: string) { diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index 7e8db72..8dde2c7 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -13,10 +13,6 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { let {red, green, blue} = RGB; let warmWhite; - - //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - let colorMask = 0xF0; @@ -34,18 +30,16 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { green = 0; blue = 0; colorMask = 0x0F; - // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); + } else if (saturation < 20) { - // this.platform.log.debug('Turning off color'); + red = 0; green = 0; blue = 0; - colorMask = 0x0F; - // this.platform.log.debug('Setting warmWhite and coldWhite without colors: ww:%o cw:%o', ww, cw); + } else { warmWhite = 0; - // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); } const deviceCommand: IDeviceCommand = { isOn, RGB:{red, green, blue}, CCT: {warmWhite}, colorMask}; @@ -65,9 +59,9 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { } else if (isOn) { brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); if (warmWhite > coldWhite) { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); + saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); } else { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); } } diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 17e90dd..086786d 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -14,9 +14,6 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { let { red, green, blue } = RGB, warmWhite; - //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - let colorMask = 0xFF; //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed @@ -32,21 +29,21 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { green = 0; blue = 0; colorMask = 0x0F; - // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); - } else if (saturation < 20) { - // this.platform.log.debug('Turning off color'); + } else if (saturation < this.colorOffSaturationLevel) { red = 0; green = 0; blue = 0; - // this.platform.log.debug('Setting only white: ww:%o cw:%o', ww, cw); - //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" - //set RGB to 100% saturation and 100% brightness - //this allows brightness to only affect the white colors, creating beautiful white+color balance - //we've set the color saturation to 100% because the higher the white level the more washed out the colors become - //the white brightness effectively acts as the saturation value - } else if (saturation < 50) { + /** + * else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" + * set RGB to 100% saturation and 100% brightness + * this allows brightness to only affect the white colors, creating beautiful white+color balance + * we've set the color saturation to 100% because the higher the white level the more washed out the colors become + * the white brightness effectively acts as the saturation value + */ + + } else if (saturation < this.colorWhiteSimultaniousSaturationLevel) { const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation red = _RGB.red; @@ -57,13 +54,8 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { green = Math.round((green / 100) * (saturation * 2)); blue = Math.round((blue / 100) * (saturation * 2)); - - // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); - - //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs } else { warmWhite = 0; - // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); } const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite }, colorMask }; diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index 545f15f..d076e72 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -1,6 +1,6 @@ import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature } from '../misc/utils'; +import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { @@ -18,9 +18,6 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { // } let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; - //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - let colorMask = 0xF0; @@ -41,7 +38,6 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { blue = 0; coldWhite = 0; colorMask = 0x0F; - // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); } else if (hue == 208 && saturation == 17) { red = 0; @@ -49,22 +45,19 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { blue = 0; warmWhite = 0; colorMask = 0x0F; - // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). //White colors were already calculated above } else if (saturation < 20) { - // this.platform.log.debug('Turning off color'); + red = 0; green = 0; blue = 0; colorMask = 0x0F; - // this.platform.log.debug('Setting warmWhite and coldWhite without colors: ww:%o cw:%o', ww, cw); } else { warmWhite = 0; coldWhite = 0; - // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); } const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; @@ -73,23 +66,27 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { }//setColor deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; - + let colorTemperature = 140; if (luminance > 0 && isOn) { brightness = luminance; - } else if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - if (warmWhite > coldWhite) { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); - } else { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + if (coldWhite > 0 || warmWhite > 0) { + saturation = 25; + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); } - } + } else { + if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + } + colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); + const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); + hue = hueSat[0]; + saturation = 10; + } const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; return accessoryState; } diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index 77d4deb..81c582f 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -17,10 +17,6 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { // _CCT = cctToWhiteTemperature(colorTemperature); // } let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; - - //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - let colorMask = 0xFF; //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed @@ -39,7 +35,6 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { blue = 0; coldWhite = 0; colorMask = 0x0F; - // this.platform.log.debug('Setting warmWhite only without colors or coldWhite: ww:%o', ww); } else if (hue == 208 && saturation == 17) { red = 0; @@ -47,16 +42,14 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { blue = 0; warmWhite = 0; colorMask = 0x0F; - // this.platform.log.debug('Setting coldWhite only without colors or warmWhite: cw:%o', cw); //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). //White colors were already calculated above - } else if (saturation < 20) { - // this.platform.log.debug('Turning off color'); + } else if (saturation < 2) { + red = 0; green = 0; blue = 0; - // this.platform.log.debug('Setting only white: ww:%o cw:%o', ww, cw); //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" //set RGB to 100% saturation and 100% brightness @@ -74,13 +67,11 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { green = Math.round((green / 100) * (saturation * 2)); blue = Math.round((blue / 100) * (saturation * 2)); - // this.platform.log.debug('Setting fully saturated color mixed with white: r:%o g:%o b:%o ww:%o cw:%o', r, g, b, ww, cw); //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs } else { warmWhite = 0; coldWhite = 0; - // this.platform.log.debug('Setting colors without white: r:%o g:%o b:%o', r, g, b); } const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; @@ -94,21 +85,17 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; let colorTemperature = 140; - if (luminance > 0 && isOn) { - brightness = luminance; - if (coldWhite > 0 || warmWhite > 0) { - saturation = 25; - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - } - } else { + if (coldWhite > 0 || warmWhite > 0) { if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + brightness = clamp((Math.max(coldWhite / 2.55), (warmWhite / 2.55)), 0, 100); } colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); hue = hueSat[0]; saturation = 10; - + + } else { + brightness = luminance; } const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; diff --git a/src/logs.ts b/src/logs.ts index fa8c5f8..566d09c 100644 --- a/src/logs.ts +++ b/src/logs.ts @@ -7,7 +7,7 @@ export class Logs { } trace(message, ...parameters: any[]) { - if (this.level == 5) { + if (this.level >= 5) { this.logger.info(message, ...parameters); } } diff --git a/src/misc/serviceCharacteristics.ts b/src/misc/serviceCharacteristics.ts index 3af810e..6c85155 100644 --- a/src/misc/serviceCharacteristics.ts +++ b/src/misc/serviceCharacteristics.ts @@ -6,49 +6,44 @@ import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessor export function addOnCharacteristic(_this) { _this.logs.trace('Adding On characteristic to service.'); _this.service.getCharacteristic(_this.hap.Characteristic.On) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, _this.setOn.bind(_this)) // SET - bind to the `setOn` method below - .on(CharacteristicEventTypes.GET, _this.getOn.bind(_this)); // GET - bind to the `getOn` method below -} - -export function addBrightnessCharacteristic(_this) { - _this.logs.trace('Adding Hue characteristic to service.'); - _this.service.getCharacteristic(_this.hap.Characteristic.Brightness) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, _this.setBrightness.bind(_this)) // SET - bind to the 'setBrightness` method below - .on(CharacteristicEventTypes.GET, _this.getBrightness.bind(_this)); // GET - bind to the 'getBrightness` method below + .onSet(_this.setOn.bind(_this)) + .onGet(_this.getOn.bind(_this)); } export function addHueCharacteristic(_this) { _this.logs.trace('Adding Hue characteristic to service.'); _this.service.getCharacteristic(_this.hap.Characteristic.Hue) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, _this.setHue.bind(_this)) // SET - bind to the 'setHue` method below - .on(CharacteristicEventTypes.GET, _this.getHue.bind(_this)); // GET - bind to the 'getHue` method below + .onSet(_this.setHue.bind(_this)) + .onGet(_this.getHue.bind(_this)); } +// if (!_this.service.testCharacteristic(_this.hap.Characteristic.CHANGE_ME)) { +// _this.service.addCharacteristic(_this.hap.Characteristic.CHANGE_ME) +// .onSet(_this.CHANGE_ME.bind(_this)) +// .onGet(_this.CHANGE_ME.bind(_this)); +// } export function addSaturationCharacteristic(_this) { _this.logs.trace('Adding Saturation characteristic to service.'); - _this.saturationCharacteristic = _this.service.getCharacteristic(_this.hap.Characteristic.Saturation) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, _this.setSaturation.bind(_this)); // SET - bind to the 'setSaturation` method below - //.on(CharacteristicEventTypes.GET, _this.getSaturation.bind(_this)); // GET - bind to the 'getSaturation` method below + _this.service.getCharacteristic(_this.hap.Characteristic.Saturation) + .onSet(_this.setSaturation.bind(_this)); + // .onGet(_this.CHANGE_ME.bind(_this)); + +} +export function addBrightnessCharacteristic(_this) { + _this.logs.trace('Adding Brightness characteristic to service.'); + _this.service.getCharacteristic(_this.hap.Characteristic.Brightness) + .onSet(_this.setBrightness.bind(_this)) + .onGet(_this.getBrightness.bind(_this)); } export function addColorTemperatureCharacteristic(_this) { _this.logs.trace('Adding ColorTemperature characteristic to service.'); - _this.service.getCharacteristic(_this.hap.Characteristic.ColorTemperature) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, _this.setColorTemperature.bind(_this)) // SET - bind to the 'setSaturation` method below - .on(CharacteristicEventTypes.GET, _this.getColorTemperature.bind(_this)); // GET - bind to the 'getSaturation` method below + _this.service.getCharacteristic(_this.hap.Characteristic.ColorTemperature) + .onSet(_this.setColorTemperature.bind(_this)) + .onGet(_this.getColorTemperature.bind(_this)); - if (_this.api.versionGreaterOrEqual && _this.api.versionGreaterOrEqual('1.3.0-beta.46')) { + if (_this.api.versionGreaterOrEqual && _this.api.versionGreaterOrEqual('1.3.0-beta.46')) { _this.logs.trace('Adding the adaptive lighting service to the accessory...'); _this.adaptiveLightingService = new _this.api.hap.AdaptiveLightingController(_this.service); _this.accessory.configureController(_this.adaptiveLightingService); @@ -60,15 +55,15 @@ export function addAccessoryInformationCharacteristic(_this) { const { protoDevice: { uniqueId, modelNumber }, deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, - } = _this.controller.getCachedDeviceInformation(); + } = _this.controller?.getCachedDeviceInformation() ?? _this.accessory.context; // set accessory information _this.accessory.getService(_this.hap.Service.AccessoryInformation)! .setCharacteristic(_this.hap.Characteristic.Manufacturer, 'MagicHome') .setCharacteristic(_this.hap.Characteristic.SerialNumber, uniqueId) .setCharacteristic(_this.hap.Characteristic.Model, modelNumber) - .setCharacteristic(_this.hap.Characteristic.HardwareRevision, controllerHardwareVersion.toString(16)) - .setCharacteristic(_this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion.toString(16)) + .setCharacteristic(_this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') + .setCharacteristic(_this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') .getCharacteristic(_this.hap.Characteristic.Identify) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) @@ -80,8 +75,47 @@ export function addAccessoryInformationCharacteristic(_this) { } export function addConfiguredNameCharacteristic(_this) { - _this.service.getCharacteristic(_this.hap.Characteristic.ConfiguredName) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, _this.setConfiguredName.bind(_this)); -} \ No newline at end of file + if (!_this.service.testCharacteristic(_this.hap.Characteristic.ConfiguredName)) { + _this.service.addCharacteristic(_this.hap.Characteristic.ConfiguredName) + .onSet(_this.setConfiguredName.bind(_this)); + } +} + + +/* + // Add the garage door service if it doesn't already exist + this.service = + this.accessory.getService(this.hapServ.GarageDoorOpener) || + this.accessory.addService(this.hapServ.GarageDoorOpener) + + // Add some extra Eve characteristics + if (!this.service.testCharacteristic(this.eveChar.LastActivation)) { + this.service.addCharacteristic(this.eveChar.LastActivation) + } + if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) { + this.service.addCharacteristic(this.eveChar.ResetTotal) + } + if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) { + this.service.addCharacteristic(this.eveChar.TimesOpened) + } + + // Add the set handler to the garage door target state characteristic + this.service + .getCharacteristic(this.hapChar.TargetDoorState) + .onSet(value => this.internalTargetUpdate(value)) + this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value + this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value + + // Add the set handler to the garage door reset total characteristic + this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { + this.service.updateCharacteristic(this.eveChar.TimesOpened, 0) + }) + + // Update the obstruction detected to false on plugin load + this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false) + + // Pass the accessory to Fakegato to set up with Eve + this.accessory.eveService = new platform.eveService('door', this.accessory, { + log: platform.config.debugFakegato ? this.log : () => {} + }) + */ \ No newline at end of file diff --git a/src/misc/types.ts b/src/misc/types.ts index 551e383..1d3a533 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -29,6 +29,8 @@ export interface MagicHomeAccessory extends PlatformAccessory { context: { displayName: string; restartsSinceSeen: number, + protoDevice, + deviceAPI, pendingRegistration?: boolean; cachedAccessoryState?: IAccessoryState; } @@ -55,6 +57,14 @@ export interface IColorHSL { luminance?: number; } + +export interface IConfigOptions { + logLevel: number, + colorWhiteInterfaceMode: string, + colorOffSaturationLevel: number, + colorWhiteSimultaniousSaturationLevel?: number, +} + /*----------------------[Constants]----------------------*/ export const ColorCommandModes = { diff --git a/src/misc/utils.ts b/src/misc/utils.ts index daf89cd..0a8142f 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -193,8 +193,6 @@ export function cctToWhiteTemperature(CCT: number, multiplier = 0): { warmWhite: warmWhite = Math.round((127 * multiplier)); } - // this.logs.trace('Calculated accessory %o\'s white values: %o from CCT: %o', this.accessory.context.displayName, {warmWhite, coldWhite}, CCT); - return { warmWhite, coldWhite }; } diff --git a/src/platform.ts b/src/platform.ts index 982a7b9..9501dc4 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -39,7 +39,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin public readonly config: PlatformConfig; public readonly accessoriesFromDiskMap: Map = new Map(); - + private readonly hbLogger: Logging; constructor( hbLogger: Logging, config: PlatformConfig, @@ -48,9 +48,9 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin hap = api.hap; this.config = config; // this.log = new Logs(hbLogger, this.config.advancedOptions.logLevel); - this.log = new Logs(hbLogger, config.advancedOptions.logLevel); + this.log = new Logs(hbLogger, config.globalAccessoryOptions?.logLevel ?? 3); this.api = api; - + this.hbLogger = hbLogger; //this.logs = getLogger(); this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); logger.reverse().log('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); @@ -98,9 +98,9 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.config, this.accessoriesFromDiskMap, controllerGenerator); + const accesssoryGenerator = new AccessoryGenerator(this.api, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); await accesssoryGenerator.generateAccessories(); - this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 10000); + //this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 10000); } diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 520e27b..1bbd660 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -4,7 +4,7 @@ import type { } from 'homebridge'; import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; -import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, MagicHomeAccessory } from './misc/types'; +import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus, IProtoDevice } from 'magichome-platform'; import { _ } from 'lodash'; @@ -14,12 +14,11 @@ import { Logs } from './logs'; const { ready, pending, busy } = DeviceWriteStatus; const CCT = 'CCT'; const HSL = 'HSL'; - const BUFFER_MS = 20; const FINAL_COMMAND_TIMEOUT = 100; const QUEUE_INTERVAL = 150; -const SLOW_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 10, bufferMS: 10, timeoutMS: 1000 }; +const SLOW_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 20, bufferMS: 10, timeoutMS: 2000 }; const MEDIUM_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 10, bufferMS: 10, timeoutMS: 200 }; const FAST_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 0, bufferMS: 0, timeoutMS: 20 }; @@ -38,14 +37,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected latestDeviceCommand: IDeviceCommand; protected latestAccessoryCommand: IAccessoryCommand; + protected lastAccessoryCommand: IAccessoryCommand = DefaultAccessoryCommand; + protected ColorCommandMode = HSL; protected readonly hap: HAP; protected logs; - - protected colorWhiteThreshold; - protected colorWhiteThresholdSimultaniousDevices; - protected colorOffThresholdSimultaniousDevices; + protected colorWhiteSimultaniousSaturationLevel; + protected colorOffSaturationLevel; protected simultaniousDevicesColorWhite; protected accessoryState: IAccessoryState = DefaultAccessoryCommand; @@ -54,6 +53,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected queue; protected deviceAPI: { hasBrightness, hasCCT }; protected slowQueueRetry = false; + latestDeviceState: IDeviceState; //================================================= // Start Constructor // @@ -67,18 +67,13 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { ) { - this.colorWhiteThreshold = this.config.whiteEffects.colorWhiteThreshold; - this.colorWhiteThresholdSimultaniousDevices = this.config.whiteEffects.colorWhiteThresholdSimultaniousDevices; - this.colorOffThresholdSimultaniousDevices = this.config.whiteEffects.colorOffThresholdSimultaniousDevices; - this.simultaniousDevicesColorWhite = this.config.whiteEffects.simultaniousDevicesColorWhite; + this.setupMisc(); - this.accessoryState = this.accessory.context.cachedAccessoryState || DefaultAccessoryCommand; this.controller = controller; this.hap = api.hap; this.api = api; - - this.logs = new Logs(logging, this.config.loggingLevel ?? 3); + this.config = config; this.setupCommandQueue(); this.initializeCharacteristics(); this.fetchAndUpdateState(2); @@ -89,27 +84,21 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // Start Setters // - - async setOn(value: CharacteristicValue, callback: CharacteristicSetCallback) { - callback(null); - + async setOn(value: CharacteristicValue) { + this.lastAccessoryCommand.isOn = value as boolean; const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; this.processAccessoryCommand(accessoryCommand); } - setHue(value: CharacteristicValue, callback: CharacteristicSetCallback) { - callback(null); + setHue(value: CharacteristicValue) { this.accessoryState.HSL.hue = value as number; - this.ColorCommandMode = HSL; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; this.processAccessoryCommand(accessoryCommand); } - setSaturation(value: CharacteristicValue, callback: CharacteristicSetCallback) { + setSaturation(value: CharacteristicValue) { - callback(null); this.accessoryState.HSL.saturation = value as number; this.ColorCommandMode = HSL; @@ -118,31 +107,27 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.processAccessoryCommand(accessoryCommand); } - async setBrightness(value: CharacteristicValue, callback: CharacteristicSetCallback) { + async setBrightness(value: CharacteristicValue) { - callback(null); this.accessoryState.brightness = value as number; const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; this.processAccessoryCommand(accessoryCommand); } - setColorTemperature(value: CharacteristicValue, callback: CharacteristicSetCallback) { + setColorTemperature(value: CharacteristicValue) { this.ColorCommandMode = CCT; - callback(null); const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; this.processAccessoryCommand(accessoryCommand); } - setConfiguredName(value: CharacteristicValue, callback: CharacteristicSetCallback) { + setConfiguredName(value: CharacteristicValue) { const name: string = value.toString(); this.logs.debug('Renaming device to %o', name); this.accessory.context.displayName = name; this.api.updatePlatformAccessories([this.accessory]); - - callback(null); } identifyLight() { @@ -156,26 +141,26 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // Start Getters // - getHue(callback: CharacteristicGetCallback) { + getHue() { const hue = this.accessoryState.HSL.hue; - callback(null, hue); - this.fetchAndUpdateState(2); + return hue; + } - getColorTemperature(callback: CharacteristicGetCallback) { + getColorTemperature() { const colorTemperature = this.accessoryState.colorTemperature; - callback(null, colorTemperature); //immediately return cached state to prevent laggy HomeKit UI this.fetchAndUpdateState(3); + return colorTemperature; } - getBrightness(callback: CharacteristicGetCallback) { + getBrightness() { const brightness = this.accessoryState.brightness; - callback(null, brightness); //immediately return cached state to prevent laggy HomeKit UI - // this.fetchAndUpdateState(2); + this.fetchAndUpdateState(2); + return brightness; } /** @@ -183,11 +168,10 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { * instantly retrieve the current on/off state stored in our object * next call this.getState() which will update all values asynchronously as they are ready */ - getOn(callback: CharacteristicGetCallback) { - + async getOn() { const isOn = this.accessoryState.isOn; - callback(null, isOn); //immediately return cached state to prevent laggy HomeKit UI this.fetchAndUpdateState(2); + return isOn; } flashEffect() { @@ -223,9 +207,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { return new Promise((resolve, reject) => { this.logs.trace(this.ColorCommandMode); return setTimeout(() => { - this.logs.trace(this.accessory.context.displayName, '\nthis.accessoryState: ', this.accessoryState, '\n this.newAccessoryCommand: ', this.newAccessoryCommand); + this.logs.debug(this.accessory.context.displayName, '\nthis.accessoryState: ', this.accessoryState, '\n this.newAccessoryCommand: ', this.newAccessoryCommand); const sanitizedAcessoryCommand: IAccessoryCommand = _.merge({}, this.accessoryState, this.newAccessoryCommand); - + // eslint-disable-next-line no-prototype-builtins if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; @@ -240,14 +224,13 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { }); } - protected async prepareCommand(accessoryCommand: IAccessoryCommand) { + protected async prepareCommand(accessoryCommand: IAccessoryCommand, options: ICommandOptions = MEDIUM_COMMAND_OPTIONS) { const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); this.latestDeviceCommand = deviceCommand; this.latestAccessoryCommand = accessoryCommand; + let deviceState: IDeviceState; + this.queue.enqueue(async () => { - let options: ICommandOptions = MEDIUM_COMMAND_OPTIONS; - //this.accessoryState = Object.assign(accessoryCommand); - //this.logs.warn(deviceCommand); if (this.queue.size > 0) { this.slowQueueRetry = true; @@ -255,19 +238,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } if (!(this.slowQueueRetry && this.queue.size < 1)) { - let deviceState: IDeviceState; if (!accessoryCommand.isPowerCommand) { - deviceState = await this.controller.setAllValues(deviceCommand, options); + this.latestDeviceState = await this.controller.setAllValues(deviceCommand, options); } else { - deviceState = await this.controller.setOn(deviceCommand.isOn, options); + this.latestDeviceState = await this.controller.setOn(deviceCommand.isOn, options); } - - this.updateLocalState(0, deviceState); - return deviceState; } }); - } protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { @@ -286,7 +264,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if (!deviceState) { deviceState = await this.controller.fetchState(); } - + this.latestDeviceCommand = deviceState.LED; + //this.logs.warn(deviceState); const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); let accessoryState: IAccessoryState; if (deviceState) { @@ -304,11 +283,10 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; break; } - // if (deviceState && deviceState.LED.isOn) { _.merge(this.accessoryState, accessoryState); - // } + this.accessory.context.cachedAccessoryState = this.accessoryState; - this.logs.trace(this.accessory.displayName, ': FINAL STATE', this.accessoryState); + this.logs.debug(this.accessory.displayName, ': FINAL STATE', this.accessoryState); } else { _.merge(this.accessoryState, { isOn: false }); } @@ -333,9 +311,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } else if (isOn) { brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); if (warmWhite > coldWhite) { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (coldWhite / 255)); + saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); } else { - saturation = this.colorWhiteThreshold - (this.colorWhiteThreshold * (warmWhite / 255)); + saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); } } @@ -344,6 +322,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setupCommandQueue() { + let deviceState; this.queue = new Queue({ concurrent: 1, interval: QUEUE_INTERVAL, @@ -356,33 +335,32 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { }); this.queue.on('end', async () => { - if (this.slowQueueRetry) { - timeout = setTimeout(async () => { - this.logs.trace(this.accessory.displayName, ': FINAL WRITE', this.latestDeviceCommand); - let deviceState: IDeviceState; - - - if (!this.latestAccessoryCommand.isPowerCommand) { - deviceState = await this.controller.setAllValues(this.latestDeviceCommand, SLOW_COMMAND_OPTIONS); - } else { - deviceState = await this.controller.setOn(this.latestDeviceCommand.isOn, SLOW_COMMAND_OPTIONS); - } - - this.slowQueueRetry = false; - this.updateLocalState(0, deviceState); - this.updateHomekitState(); - }, FINAL_COMMAND_TIMEOUT); - } + if (!_.isEqual(_.omit(this.latestDeviceState?.LED ?? {}, ['colorMask']), _.omit(this.latestDeviceCommand, ['colorMask']))) { + if (this.slowQueueRetry) { + timeout = setTimeout(async () => { + this.logs.trace(this.accessory.displayName, ': FINAL WRITE', this.latestDeviceCommand); + this.slowQueueRetry = false; + await this.prepareCommand(this.latestAccessoryCommand, SLOW_COMMAND_OPTIONS); + this.updateLocalState(0, null); + + }, FINAL_COMMAND_TIMEOUT); + } + deviceState = null; + } }); - this.queue.on('resolve', data => {/** */ }); - this.queue.on('reject', error => {/** */ }); + this.queue.on('resolve', _deviceState => { + deviceState = _deviceState; + }); + this.queue.on('reject', error => { + this.logs.error(error); + }); } initializeCharacteristics() { - const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = this.controller.getCachedDeviceInformation(); + const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = this.controller?.getCachedDeviceInformation() ?? this.accessory.context; addAccessoryInformationCharacteristic(this); @@ -410,6 +388,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { addConfiguredNameCharacteristic(this); } + setupMisc() { + this.accessoryState = this.accessory.context.cachedAccessoryState ?? DefaultAccessoryCommand; + + const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName); + const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = _.merge({}, this.config.globalAccessoryOptions, localAccessoryOptions); + + + this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; + this.colorOffSaturationLevel = colorOffSaturationLevel; + this.logs = new Logs(this.logging, logLevel ?? 3); + + } + + async fetchAndUpdateState(requestLevel) { await this.updateLocalState(requestLevel, null); this.updateHomekitState(); From 78c166c795e81b606f834a7b56b9afe983a39292 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sun, 17 Oct 2021 23:23:43 -0400 Subject: [PATCH 17/42] add offline devices --- src/AccessoryGenerator.ts | 107 ++++++++++++----------------- src/accessories/RGBWBulb.ts | 8 --- src/accessories/RGBWStrip.ts | 8 --- src/accessories/RGBWWBulb.ts | 7 -- src/accessories/RGBWWStrip.ts | 36 +++++----- src/misc/serviceCharacteristics.ts | 40 +++++------ src/misc/types.ts | 18 ++--- src/misc/utils.ts | 2 +- src/platformAccessory.ts | 67 +++++++++--------- 9 files changed, 126 insertions(+), 167 deletions(-) diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 76a36ef..d84fa46 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -1,5 +1,5 @@ import { BaseController, ControllerGenerator, ICustomProtoDevice, IDeviceAPI } from 'magichome-platform'; -import { IAccessoryState, MagicHomeAccessory } from './misc/types'; +import { IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; import { API, HAP, @@ -35,7 +35,6 @@ export class AccessoryGenerator { this.log.info('Scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { const accessories = this.discoverAccessories(controllers); - this.registerOfflineAccessories(this.accessoriesFromDiskMap); return accessories; @@ -83,7 +82,6 @@ export class AccessoryGenerator { const existingAccessoriesList: MagicHomeAccessory[] = []; let accessory; for (const [uniqueId, controller] of Object.entries(controllers)) { - // this.log.warn(controller); const homebridgeUUID = this.hap.uuid.generate(uniqueId); @@ -94,12 +92,11 @@ export class AccessoryGenerator { this.accessoriesFromDiskMap.delete(homebridgeUUID); existingAccessoriesList.push(accessory); - this.log.info('Found previously unreachable existing accessory. Updating...'); + this.log.info('Found previously unreachable existing accessory during a re-scan. Updating...'); } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { accessory = this.createNewAccessory(controller, homebridgeUUID); newAccessoriesList.push(accessory); //add it to new accessory list - //this.log.printDeviceInfo('Registering new accessory...!', newAccessory); this.log.info('Found previously unseen accessory during a re-scan. Registering...'); } @@ -129,7 +126,6 @@ export class AccessoryGenerator { existingAccessoriesList.push(accessory); } else { this.log.info('Found new accessory. Registering...'); - accessory = this.createNewAccessory(controller, homebridgeUUID); newAccessoriesList.push(accessory); //add it to new accessory list } @@ -137,45 +133,28 @@ export class AccessoryGenerator { this.activeAccessoriesMap.set(homebridgeUUID, accessory); } + this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { + const homebridgeUUID = this.hap.uuid.generate(offlineAccessory.context.cachedDeviceInformation.protoDevice.uniqueId); + await this.processOfflineAccessory(offlineAccessory); + existingAccessoriesList.push(offlineAccessory); + this.activeAccessoriesMap.set(homebridgeUUID, offlineAccessory); + }); + this.registerNewAccessories(newAccessoriesList); //register new accessories from scan this.updateExistingAccessories(existingAccessoriesList); } - registerOfflineAccessories(accessories) { - accessories.forEach(async (offlineAccessory, homebridgeUUID) => { - offlineAccessory.context.restartsSinceSeen++; - const { protoDevice, deviceAPI } = offlineAccessory.context; - const controller = await this.controllerGenerator.createCustomControllers({ protoDevice, deviceAPI })[0]; - new homekitInterface[deviceAPI.description](this.api, offlineAccessory, this.config, controller, this.log); - - // existingAccessoriesList.push(processedAccessory); - // this.log.warn('registering accessory that has been unseen'); - }); - } - createNewAccessory(controller: BaseController, homebridgeUUID: string): MagicHomeAccessory { - const { - protoDevice, - deviceAPI, - protoDevice: { uniqueId }, - deviceAPI: { description }, - deviceState: { LED: { RGB, CCT, isOn } }, - } = controller.getCachedDeviceInformation(); + const cachedDeviceInformation = controller.getCachedDeviceInformation(); + const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; if (!this.isAllowed(uniqueId)) { return; } - // //convert RGB to HSL - // //convert CCT to colorTemperature - // const HSL = convertRGBtoHSL(RGB) - // const - // const accessoryState: IAccessoryState = {isOn, } JUST KIDDING, DO IT AFTER INITIALIZING DEVICE - const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; - newAccessory.context = { protoDevice, deviceAPI, displayName: description as string, restartsSinceSeen: 0 }; - //this.log.warn(description); + newAccessory.context = { cachedDeviceInformation, displayName: description as string, restartsSinceSeen: 0 }; try { new homekitInterface[description](this.api, newAccessory, this.config, controller, this.log); @@ -187,27 +166,35 @@ export class AccessoryGenerator { } processExistingAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { - existingAccessory.context.restartsSinceSeen = 0; - const cachedInformation = controller.getCachedDeviceInformation(); - const { - protoDevice, - deviceAPI, - protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState, deviceAPI: { description }, - } = cachedInformation; - - if (!this.isAllowed(uniqueId) || !this.isFresh(cachedInformation, existingAccessory)) { - return; - } - - _.merge(existingAccessory.context, { protoDevice, deviceAPI, restartsSinceSeen: 0 }); try { - new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.log); + + + const cachedDeviceInformation = controller?.getCachedDeviceInformation() ?? existingAccessory.context.cachedDeviceInformation; + const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; + if (!this.isAllowed(uniqueId) || !this.isFresh(cachedDeviceInformation, existingAccessory)) { + return; + } + _.merge(existingAccessory.context, { cachedDeviceInformation, restartsSinceSeen: 0 }); + + try { + new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.log); + } catch (error) { + this.log.error('[processExistingAccessory] [Error]: ', error); + } + return existingAccessory; } catch (error) { - this.log.error('The controllerLogicType does not exist in accessoryType list.'); this.log.error(error); } - return existingAccessory; + } + + async processOfflineAccessory(offlineAccessory) { + offlineAccessory.context.restartsSinceSeen++; + const { deviceState, protoDevice, deviceAPI, deviceAPI: { description } } = offlineAccessory.context.cachedDeviceInformation; + this.log.warn(`[Warning] Device Unreachable. Registering accessory { ${offlineAccessory.context.displayName} - UID: ${protoDevice.uniqueId} } with cached information.`); + this.log.error(deviceState); + const controller = await this.controllerGenerator.createCustomControllers({ protoDevice, deviceAPI, deviceState }); + new homekitInterface[description](this.api, offlineAccessory, this.config, controller, this.log); + } @@ -223,27 +210,23 @@ export class AccessoryGenerator { isFresh(cachedInformation, existingAccessory: MagicHomeAccessory): boolean { - let isFresh = true; - const { - protoDevice: { uniqueId, ipAddress, modelNumber }, - deviceState, deviceAPI: { description }, - } = cachedInformation; - if (existingAccessory.context.displayName.toString().toLowerCase().includes('delete')) { this.unregisterAccessory(existingAccessory, `Successfully pruned accessory: ${existingAccessory.context.displayName} due to being marked for deletion\n`); isFresh = false; - } else if (this.config.pruning?.pruneRestarts ?? false) { - if (existingAccessory.context.restartsSinceSeen >= this.config.pruning.pruneRestarts) { - this.unregisterAccessory(existingAccessory, `Successfully pruned accessory: ${existingAccessory.context.displayName} - which had not being seen for ${existingAccessory.context.restartsSinceSeen} restart(s).\n`); - isFresh = false; - } } + // else if (this.config.pruning?.pruneRestarts ?? false) { + // if (existingAccessory.context.restartsSinceSeen >= this.config.pruning.pruneRestarts) { + // this.unregisterAccessory(existingAccessory, `Successfully pruned accessory: ${existingAccessory.context.displayName} + // which had not being seen for ${existingAccessory.context.restartsSinceSeen} restart(s).\n`); + // isFresh = false; + // } + // } + return isFresh; } diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index 8dde2c7..7a9529e 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -68,13 +68,5 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; return accessoryState; } - - updateHomekiState() { - this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); - } - } \ No newline at end of file diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 086786d..1a1db10 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -89,12 +89,4 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; return accessoryState; } - - updateHomekitState() { - this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); - } - } \ No newline at end of file diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index d076e72..ff1064f 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -91,11 +91,4 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { return accessoryState; } - updateHomekitState() { - this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); - } - } \ No newline at end of file diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index 81c582f..6fc9ccc 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -45,7 +45,7 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). //White colors were already calculated above - } else if (saturation < 2) { + } else if (saturation <= 2) { red = 0; green = 0; @@ -80,35 +80,35 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { LED: { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; let colorTemperature = 140; - if (coldWhite > 0 || warmWhite > 0) { - if (isOn) { + + //Brightness + if (isOn) { + if (coldWhite == 0 && warmWhite == 0) { + brightness = luminance; + } else { brightness = clamp((Math.max(coldWhite / 2.55), (warmWhite / 2.55)), 0, 100); } + } + //Hue && Saturation + if (coldWhite > 0 || warmWhite > 0) { + saturation = luminance; colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); - const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); - hue = hueSat[0]; - saturation = 10; - - } else { - brightness = luminance; + if (saturation <= 2) { + const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); + hue = hueSat[0]; + saturation = 10; + } } const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; return accessoryState; } - - updateHomekitState() { - this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); - } - } diff --git a/src/misc/serviceCharacteristics.ts b/src/misc/serviceCharacteristics.ts index 6c85155..752fb25 100644 --- a/src/misc/serviceCharacteristics.ts +++ b/src/misc/serviceCharacteristics.ts @@ -17,33 +17,28 @@ export function addHueCharacteristic(_this) { .onGet(_this.getHue.bind(_this)); } -// if (!_this.service.testCharacteristic(_this.hap.Characteristic.CHANGE_ME)) { -// _this.service.addCharacteristic(_this.hap.Characteristic.CHANGE_ME) -// .onSet(_this.CHANGE_ME.bind(_this)) -// .onGet(_this.CHANGE_ME.bind(_this)); -// } export function addSaturationCharacteristic(_this) { _this.logs.trace('Adding Saturation characteristic to service.'); - _this.service.getCharacteristic(_this.hap.Characteristic.Saturation) - .onSet(_this.setSaturation.bind(_this)); - // .onGet(_this.CHANGE_ME.bind(_this)); - + _this.service.getCharacteristic(_this.hap.Characteristic.Saturation) + .onSet(_this.setSaturation.bind(_this)); + // .onGet(_this.CHANGE_ME.bind(_this)); + } export function addBrightnessCharacteristic(_this) { _this.logs.trace('Adding Brightness characteristic to service.'); - _this.service.getCharacteristic(_this.hap.Characteristic.Brightness) - .onSet(_this.setBrightness.bind(_this)) - .onGet(_this.getBrightness.bind(_this)); + _this.service.getCharacteristic(_this.hap.Characteristic.Brightness) + .onSet(_this.setBrightness.bind(_this)) + .onGet(_this.getBrightness.bind(_this)); } export function addColorTemperatureCharacteristic(_this) { _this.logs.trace('Adding ColorTemperature characteristic to service.'); - _this.service.getCharacteristic(_this.hap.Characteristic.ColorTemperature) - .onSet(_this.setColorTemperature.bind(_this)) - .onGet(_this.getColorTemperature.bind(_this)); + _this.service.getCharacteristic(_this.hap.Characteristic.ColorTemperature) + .onSet(_this.setColorTemperature.bind(_this)) + .onGet(_this.getColorTemperature.bind(_this)); - if (_this.api.versionGreaterOrEqual && _this.api.versionGreaterOrEqual('1.3.0-beta.46')) { + if (_this.api.versionGreaterOrEqual && _this.api.versionGreaterOrEqual('1.3.0-beta.46')) { _this.logs.trace('Adding the adaptive lighting service to the accessory...'); _this.adaptiveLightingService = new _this.api.hap.AdaptiveLightingController(_this.service); _this.accessory.configureController(_this.adaptiveLightingService); @@ -54,16 +49,16 @@ export function addAccessoryInformationCharacteristic(_this) { const { protoDevice: { uniqueId, modelNumber }, - deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, - } = _this.controller?.getCachedDeviceInformation() ?? _this.accessory.context; - + // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, + } = _this.accessory.context.cachedDeviceInformation; + _this.logs.warn(_this.accessory.context.cachedDeviceInformation); // set accessory information _this.accessory.getService(_this.hap.Service.AccessoryInformation)! .setCharacteristic(_this.hap.Characteristic.Manufacturer, 'MagicHome') .setCharacteristic(_this.hap.Characteristic.SerialNumber, uniqueId) .setCharacteristic(_this.hap.Characteristic.Model, modelNumber) - .setCharacteristic(_this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') - .setCharacteristic(_this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') + // .setCharacteristic(_this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') + // .setCharacteristic(_this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') .getCharacteristic(_this.hap.Characteristic.Identify) .removeAllListeners(CharacteristicEventTypes.SET) .removeAllListeners(CharacteristicEventTypes.GET) @@ -78,6 +73,9 @@ export function addConfiguredNameCharacteristic(_this) { if (!_this.service.testCharacteristic(_this.hap.Characteristic.ConfiguredName)) { _this.service.addCharacteristic(_this.hap.Characteristic.ConfiguredName) .onSet(_this.setConfiguredName.bind(_this)); + } else { + _this.service.getCharacteristic(_this.hap.Characteristic.ConfiguredName) + .onSet(_this.setConfiguredName.bind(_this)); } } diff --git a/src/misc/types.ts b/src/misc/types.ts index 1d3a533..be90ec3 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -10,7 +10,7 @@ import { RGBWWBulb } from '../accessories/RGBWWBulb'; import { RGBWStrip } from '../accessories/RGBWStrip'; import { RGBWWStrip } from '../accessories/RGBWWStrip'; import { CCTStrip } from '../accessories/CCTStrip'; -import { IDeviceState, IDeviceCommand, IColorCCT } from 'magichome-platform/dist/types'; +import { IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation } from 'magichome-platform/dist/types'; export const homekitInterface = { @@ -26,14 +26,14 @@ export const homekitInterface = { }; export interface MagicHomeAccessory extends PlatformAccessory { - context: { - displayName: string; - restartsSinceSeen: number, - protoDevice, - deviceAPI, - pendingRegistration?: boolean; - cachedAccessoryState?: IAccessoryState; - } + context: IAccessoryContext +} + +export interface IAccessoryContext { + displayName?: string; + restartsSinceSeen: number, + accessoryState?: IAccessoryState; + cachedDeviceInformation: IDeviceInformation; } export interface IAccessoryState { diff --git a/src/misc/utils.ts b/src/misc/utils.ts index 0a8142f..d599af5 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -58,7 +58,7 @@ export function convertRGBtoHSL(RGB: IColorRGB) { h += 360; } - const l = max; + const l = max / 2.55; if (max === min) { s = 0; diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 1bbd660..b82f1f0 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -14,7 +14,7 @@ import { Logs } from './logs'; const { ready, pending, busy } = DeviceWriteStatus; const CCT = 'CCT'; const HSL = 'HSL'; -const BUFFER_MS = 20; +const BUFFER_MS = 100; const FINAL_COMMAND_TIMEOUT = 100; const QUEUE_INTERVAL = 150; @@ -30,6 +30,7 @@ const FAST_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 0, bufferMS: 0, t export class HomebridgeMagichomeDynamicPlatformAccessory { protected service: Service; + protected readonly hap: HAP; protected adaptiveLightingService; @@ -37,21 +38,15 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected latestDeviceCommand: IDeviceCommand; protected latestAccessoryCommand: IAccessoryCommand; - protected lastAccessoryCommand: IAccessoryCommand = DefaultAccessoryCommand; - protected ColorCommandMode = HSL; - protected readonly hap: HAP; protected logs; protected colorWhiteSimultaniousSaturationLevel; protected colorOffSaturationLevel; protected simultaniousDevicesColorWhite; - protected accessoryState: IAccessoryState = DefaultAccessoryCommand; - protected accessoryStateTemporary: IAccessoryState; protected deviceWriteStatus = ready; protected queue; - protected deviceAPI: { hasBrightness, hasCCT }; protected slowQueueRetry = false; latestDeviceState: IDeviceState; @@ -69,7 +64,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.setupMisc(); - this.controller = controller; this.hap = api.hap; this.api = api; @@ -85,13 +79,12 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // Start Setters // async setOn(value: CharacteristicValue) { - this.lastAccessoryCommand.isOn = value as boolean; const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; this.processAccessoryCommand(accessoryCommand); } setHue(value: CharacteristicValue) { - this.accessoryState.HSL.hue = value as number; + this.accessory.context.accessoryState.HSL.hue = value as number; this.ColorCommandMode = HSL; const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; this.processAccessoryCommand(accessoryCommand); @@ -99,7 +92,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setSaturation(value: CharacteristicValue) { - this.accessoryState.HSL.saturation = value as number; + this.accessory.context.accessoryState.HSL.saturation = value as number; this.ColorCommandMode = HSL; @@ -110,7 +103,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { async setBrightness(value: CharacteristicValue) { - this.accessoryState.brightness = value as number; + this.accessory.context.accessoryState.brightness = value as number; const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; this.processAccessoryCommand(accessoryCommand); } @@ -143,7 +136,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getHue() { - const hue = this.accessoryState.HSL.hue; + const hue = this.accessory.context.accessoryState.HSL.hue; this.fetchAndUpdateState(2); return hue; @@ -151,14 +144,13 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getColorTemperature() { - const colorTemperature = this.accessoryState.colorTemperature; + const colorTemperature = this.accessory.context.accessoryState.colorTemperature; this.fetchAndUpdateState(3); return colorTemperature; } getBrightness() { - - const brightness = this.accessoryState.brightness; + const brightness = this.accessory.context.accessoryState.brightness; this.fetchAndUpdateState(2); return brightness; } @@ -169,7 +161,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { * next call this.getState() which will update all values asynchronously as they are ready */ async getOn() { - const isOn = this.accessoryState.isOn; + const isOn = this.accessory.context.accessoryState.isOn; this.fetchAndUpdateState(2); return isOn; } @@ -207,15 +199,15 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { return new Promise((resolve, reject) => { this.logs.trace(this.ColorCommandMode); return setTimeout(() => { - this.logs.debug(this.accessory.context.displayName, '\nthis.accessoryState: ', this.accessoryState, '\n this.newAccessoryCommand: ', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = _.merge({}, this.accessoryState, this.newAccessoryCommand); + this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessory.context.accessoryState, '\n Received Command', this.newAccessoryCommand); + const sanitizedAcessoryCommand: IAccessoryCommand = _.merge({}, this.accessory.context.accessoryState, this.newAccessoryCommand); // eslint-disable-next-line no-prototype-builtins if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; } - this.logs.trace('\nSanatizedCommand: ', sanitizedAcessoryCommand); + // this.logs.trace('\nSanatizedCommand: ', sanitizedAcessoryCommand); this.deviceWriteStatus = ready; @@ -226,6 +218,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async prepareCommand(accessoryCommand: IAccessoryCommand, options: ICommandOptions = MEDIUM_COMMAND_OPTIONS) { const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); + this.logs.trace('Outgoing Command:', deviceCommand); this.latestDeviceCommand = deviceCommand; this.latestAccessoryCommand = accessoryCommand; let deviceState: IDeviceState; @@ -245,6 +238,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.latestDeviceState = await this.controller.setOn(deviceCommand.isOn, options); } } + + this.logs.debug('Received Device State:', this.latestDeviceState); }); } @@ -262,8 +257,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async updateLocalState(requestLevel, deviceState) { if (!deviceState) { - deviceState = await this.controller.fetchState(); + deviceState = await this.controller?.fetchState() ?? this.accessory.context.cachedDeviceInformation.deviceState; } + this.logs.trace('FETCHED STATE:', deviceState); this.latestDeviceCommand = deviceState.LED; //this.logs.warn(deviceState); const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); @@ -283,20 +279,19 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; break; } - _.merge(this.accessoryState, accessoryState); + _.merge(this.accessory.context.accessoryState, accessoryState); - this.accessory.context.cachedAccessoryState = this.accessoryState; - this.logs.debug(this.accessory.displayName, ': FINAL STATE', this.accessoryState); + this.logs.debug(this.accessory.displayName, ': FINAL STATE', this.accessory.context.accessoryState); } else { - _.merge(this.accessoryState, { isOn: false }); + _.merge(this.accessory.context.accessoryState, { isOn: false }); } } updateHomekitState() { - this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessoryState.isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessoryState.HSL.hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSL.saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessoryState.brightness); + this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessory.context.accessoryState.isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessory.context.accessoryState.HSL.hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessory.context.accessoryState.HSL.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessory.context.accessoryState.brightness); } deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { @@ -342,7 +337,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.logs.trace(this.accessory.displayName, ': FINAL WRITE', this.latestDeviceCommand); this.slowQueueRetry = false; await this.prepareCommand(this.latestAccessoryCommand, SLOW_COMMAND_OPTIONS); - this.updateLocalState(0, null); + this.fetchAndUpdateState(2); }, FINAL_COMMAND_TIMEOUT); } @@ -360,7 +355,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { initializeCharacteristics() { - const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = this.controller?.getCachedDeviceInformation() ?? this.accessory.context; + let cachedDeviceInformation = this.controller?.getCachedDeviceInformation(); + if (cachedDeviceInformation) { + this.accessory.context.cachedDeviceInformation = cachedDeviceInformation; + } else { + cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; + } + + const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; addAccessoryInformationCharacteristic(this); @@ -389,7 +391,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setupMisc() { - this.accessoryState = this.accessory.context.cachedAccessoryState ?? DefaultAccessoryCommand; + this.accessory.context.accessoryState = this.accessory.context.accessoryState ?? DefaultAccessoryCommand; const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName); const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = _.merge({}, this.config.globalAccessoryOptions, localAccessoryOptions); @@ -401,7 +403,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } - async fetchAndUpdateState(requestLevel) { await this.updateLocalState(requestLevel, null); this.updateHomekitState(); From 5a669d3d3b02a4f3fc06e411a58970008a4d7c3f Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 23 Oct 2021 14:58:49 -0400 Subject: [PATCH 18/42] White LEDs can be 255 max combined --- src/misc/utils.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/misc/utils.ts b/src/misc/utils.ts index d599af5..6458559 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -154,28 +154,29 @@ export function loadJson(file: string, replacement: T): T { */ export function convertHueToColorCCT(hue: number): IColorCCT { let multiplier = 0; - const colorCCT = { warmWhite: 0, coldWhite: 0 }; + let warmWhite = 0, coldWhite = 0; if (hue <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue - colorCCT.warmWhite = 255; multiplier = ((hue / 90)); - colorCCT.coldWhite = Math.round((255 * multiplier)); + coldWhite = Math.round((127 * multiplier)); + warmWhite = 255 - coldWhite; } else if (hue > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue - colorCCT.warmWhite = 255; multiplier = (1 - (hue - 270) / 90); - colorCCT.coldWhite = Math.round((255 * multiplier)); + coldWhite = Math.round((127 * multiplier)); + warmWhite = 255 - coldWhite; } else if (hue > 180 && hue <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue - colorCCT.coldWhite = 255; multiplier = ((hue - 180) / 90); - colorCCT.warmWhite = Math.round((255 * multiplier)); + warmWhite = Math.round((127 * multiplier)); + coldWhite = 255 - warmWhite; + } else if (hue > 90 && hue <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue - colorCCT.coldWhite = 255; multiplier = (1 - (hue - 90) / 90); - colorCCT.warmWhite = Math.round((255 * multiplier)); + warmWhite = Math.round((127 * multiplier)); + coldWhite = 255 - warmWhite; } - return colorCCT; + return {warmWhite, coldWhite}; } //hueToWhiteTemperature export function cctToWhiteTemperature(CCT: number, multiplier = 0): { warmWhite: number, coldWhite: number } { From cd803c2c87989a23f2112f4b6ca0725372a3afd5 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 23 Oct 2021 15:15:04 -0400 Subject: [PATCH 19/42] Added buffer for device read state --- src/platformAccessory.ts | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index b82f1f0..c0c44da 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -6,12 +6,13 @@ import type { import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus, IProtoDevice } from 'magichome-platform'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus as DeviceStatus, IProtoDevice } from 'magichome-platform'; import { _ } from 'lodash'; import Queue from 'queue-promise'; import { Logs } from './logs'; -const { ready, pending, busy } = DeviceWriteStatus; +const { ready, pending, busy } = DeviceStatus; + const CCT = 'CCT'; const HSL = 'HSL'; const BUFFER_MS = 100; @@ -46,6 +47,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected simultaniousDevicesColorWhite; protected deviceWriteStatus = ready; + protected deviceReadStatus = ready; + protected readRequestLevel = 0; + protected queue; protected slowQueueRetry = false; latestDeviceState: IDeviceState; @@ -404,8 +408,22 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } async fetchAndUpdateState(requestLevel) { - await this.updateLocalState(requestLevel, null); - this.updateHomekitState(); + switch (this.deviceReadStatus) { + case ready: + this.deviceReadStatus = pending; + this.readRequestLevel = requestLevel; + setTimeout(async () => { + await this.updateLocalState(this.readRequestLevel, null); + this.updateHomekitState(); + this.deviceReadStatus = ready; + }, BUFFER_MS); + break; + case pending: + this.readRequestLevel = Math.max(requestLevel, this.readRequestLevel); + break; + + } + } } // ZackneticMagichomePlatformAccessory class \ No newline at end of file From f3c23a18b8a6e8474a9efc77c3c89e2d5dabf344 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 23 Oct 2021 15:24:55 -0400 Subject: [PATCH 20/42] cached device state saves each fetch --- src/platformAccessory.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index c0c44da..f213620 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -263,9 +263,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if (!deviceState) { deviceState = await this.controller?.fetchState() ?? this.accessory.context.cachedDeviceInformation.deviceState; } - this.logs.trace('FETCHED STATE:', deviceState); - this.latestDeviceCommand = deviceState.LED; - //this.logs.warn(deviceState); + this.logs.debug(this.accessory.context.displayName, '- Device State:\n', deviceState); + this.accessory.context.cachedDeviceInformation.deviceState = deviceState; const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); let accessoryState: IAccessoryState; if (deviceState) { @@ -285,7 +284,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } _.merge(this.accessory.context.accessoryState, accessoryState); - this.logs.debug(this.accessory.displayName, ': FINAL STATE', this.accessory.context.accessoryState); + this.logs.debug(this.accessory.context.displayName, '- Homebridge State:\n', this.accessory.context.accessoryState); } else { _.merge(this.accessory.context.accessoryState, { isOn: false }); } @@ -421,7 +420,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { case pending: this.readRequestLevel = Math.max(requestLevel, this.readRequestLevel); break; - } } From aabc063e47913f7ddbcfd01a156e92966c34886a Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 23 Oct 2021 16:28:34 -0400 Subject: [PATCH 21/42] changed error handling --- src/AccessoryGenerator.ts | 49 +++++++++++++++--------------- src/logs.ts | 14 +++++---- src/misc/serviceCharacteristics.ts | 15 ++++----- src/platform.ts | 6 ++-- src/platformAccessory.ts | 27 +++++++--------- 5 files changed, 53 insertions(+), 58 deletions(-) diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index d84fa46..6003c98 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -8,6 +8,7 @@ import { import { _ } from 'lodash'; import { homekitInterface } from './misc/types'; +import { Logs } from './logs'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; @@ -18,28 +19,28 @@ export class AccessoryGenerator { public readonly activeAccessoriesMap: Map = new Map(); private hap: HAP; private api: API; - private log; + private hbLogger; private config: PlatformConfig; private controllerGenerator: ControllerGenerator; - - constructor(api, log, config, accessoriesFromDiskMap, controllerGenerator) { + private logs: Logs; + constructor(api, logs, hbLogger, config, accessoriesFromDiskMap, controllerGenerator) { this.api = api; this.hap = api.hap; - this.log = log; + this.hbLogger = hbLogger; + this.logs = logs; this.config = config; this.accessoriesFromDiskMap = accessoriesFromDiskMap; this.controllerGenerator = controllerGenerator; } public async generateAccessories() { - this.log.info('Scanning network for MagicHome accessories.'); + this.logs.info('Scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { const accessories = this.discoverAccessories(controllers); return accessories; - }).catch(error => { - this.log.error(error); + this.logs.error(error); }); } @@ -68,11 +69,11 @@ export class AccessoryGenerator { */ public async rescanAccessories() { - this.log.trace('Re-scanning network for MagicHome accessories.'); + this.logs.trace('Re-scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { await this.reDiscoverAccessories(controllers); }).catch(error => { - this.log.error(error); + this.logs.error(error); }); } @@ -92,12 +93,12 @@ export class AccessoryGenerator { this.accessoriesFromDiskMap.delete(homebridgeUUID); existingAccessoriesList.push(accessory); - this.log.info('Found previously unreachable existing accessory during a re-scan. Updating...'); + this.logs.info(`[Info] [${existingAccessory.context.displayName}] - Found previously unreachable existing accessory during a re-scan. Updating...`); } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { accessory = this.createNewAccessory(controller, homebridgeUUID); newAccessoriesList.push(accessory); //add it to new accessory list - this.log.info('Found previously unseen accessory during a re-scan. Registering...'); + this.logs.info(`[Info] [${accessory.context.displayName}] - Found previously unseen accessory during a re-scan. Registering...`); } this.activeAccessoriesMap.set(homebridgeUUID, accessory); @@ -113,20 +114,18 @@ export class AccessoryGenerator { const existingAccessoriesList: MagicHomeAccessory[] = []; let accessory; for (const [uniqueId, controller] of Object.entries(controllers)) { - // this.log.warn(controller); - const homebridgeUUID = this.hap.uuid.generate(uniqueId); if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { - this.log.info('Found existing accessory. Updating...'); const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); accessory = this.processExistingAccessory(controller, existingAccessory); + this.logs.info(`[Info] [${accessory.context.displayName}] - Found existing accessory. Updating...`); this.accessoriesFromDiskMap.delete(homebridgeUUID); existingAccessoriesList.push(accessory); } else { - this.log.info('Found new accessory. Registering...'); accessory = this.createNewAccessory(controller, homebridgeUUID); + this.logs.info(`[Info] [${accessory.context.displayName}] - Found new accessory. Registering...`); newAccessoriesList.push(accessory); //add it to new accessory list } @@ -157,10 +156,10 @@ export class AccessoryGenerator { newAccessory.context = { cachedDeviceInformation, displayName: description as string, restartsSinceSeen: 0 }; try { - new homekitInterface[description](this.api, newAccessory, this.config, controller, this.log); + new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger); } catch (error) { - this.log.error('The controllerLogicType does not exist in accessoryType list.'); - this.log.error(error); + this.logs.error('The controllerLogicType does not exist in accessoryType list.'); + this.logs.error(error); } return newAccessory; } @@ -177,23 +176,23 @@ export class AccessoryGenerator { _.merge(existingAccessory.context, { cachedDeviceInformation, restartsSinceSeen: 0 }); try { - new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.log); + new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger); } catch (error) { - this.log.error('[processExistingAccessory] [Error]: ', error); + this.logs.error('[processExistingAccessory] [Error]: ', error); } return existingAccessory; } catch (error) { - this.log.error(error); + this.logs.error(error); } } async processOfflineAccessory(offlineAccessory) { offlineAccessory.context.restartsSinceSeen++; const { deviceState, protoDevice, deviceAPI, deviceAPI: { description } } = offlineAccessory.context.cachedDeviceInformation; - this.log.warn(`[Warning] Device Unreachable. Registering accessory { ${offlineAccessory.context.displayName} - UID: ${protoDevice.uniqueId} } with cached information.`); - this.log.error(deviceState); + this.logs.warn(`[Warning] [${offlineAccessory.context.displayName}] [UID: ${protoDevice.uniqueId}] - Device Unreachable. Registering accessory with cached information.`); + this.logs.trace(deviceState); const controller = await this.controllerGenerator.createCustomControllers({ protoDevice, deviceAPI, deviceState }); - new homekitInterface[description](this.api, offlineAccessory, this.config, controller, this.log); + new homekitInterface[description](this.api, offlineAccessory, this.config, controller, this.hbLogger); } @@ -244,7 +243,7 @@ export class AccessoryGenerator { unregisterAccessory(existingAccessory: MagicHomeAccessory, reason: string) { this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]); - this.log.warn(reason); + this.hbLogger.warn(reason); } // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; diff --git a/src/logs.ts b/src/logs.ts index 566d09c..827ab5f 100644 --- a/src/logs.ts +++ b/src/logs.ts @@ -1,38 +1,40 @@ import { Logging } from 'homebridge'; +import logger from 'node-color-log'; export class Logs { - constructor(private logger: Logging, private readonly level = 3) { + constructor(private logging: Logging, private readonly level = 3) { logs = this; this.level = level; } trace(message, ...parameters: any[]) { if (this.level >= 5) { - this.logger.info(message, ...parameters); + this.logging.info(message, ...parameters); } } debug(message, ...parameters: any[]) { if (this.level >= 4) { - this.logger.info(message, ...parameters); + this.logging.info(message, ...parameters); } } info(message, ...parameters: any[]) { if (this.level >= 3) { - this.logger.info(message, ...parameters); + this.logging.info(message, ...parameters); } } warn(message, ...parameters: any[]) { if (this.level >= 2) { - this.logger.warn(message, ...parameters); + logger.bgColor('yellow').color('black').log('[Warning] ').joint().color('yellow').log(message, ...parameters); + // this.logging.warn(message, ...parameters); } } error(message, ...parameters: any[]) { if (this.level >= 1) { - this.logger.error(message, ...parameters); + this.logging.error(message, ...parameters); } } } diff --git a/src/misc/serviceCharacteristics.ts b/src/misc/serviceCharacteristics.ts index 752fb25..86b43ae 100644 --- a/src/misc/serviceCharacteristics.ts +++ b/src/misc/serviceCharacteristics.ts @@ -4,21 +4,21 @@ import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessor /*-------------------------- Characteristics -------------------------------------*/ export function addOnCharacteristic(_this) { - _this.logs.trace('Adding On characteristic to service.'); + _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding On characteristic to service.`); _this.service.getCharacteristic(_this.hap.Characteristic.On) .onSet(_this.setOn.bind(_this)) .onGet(_this.getOn.bind(_this)); } export function addHueCharacteristic(_this) { - _this.logs.trace('Adding Hue characteristic to service.'); + _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Hue characteristic to service.`); _this.service.getCharacteristic(_this.hap.Characteristic.Hue) .onSet(_this.setHue.bind(_this)) .onGet(_this.getHue.bind(_this)); } export function addSaturationCharacteristic(_this) { - _this.logs.trace('Adding Saturation characteristic to service.'); + _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); _this.service.getCharacteristic(_this.hap.Characteristic.Saturation) .onSet(_this.setSaturation.bind(_this)); // .onGet(_this.CHANGE_ME.bind(_this)); @@ -26,20 +26,20 @@ export function addSaturationCharacteristic(_this) { } export function addBrightnessCharacteristic(_this) { - _this.logs.trace('Adding Brightness characteristic to service.'); + _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); _this.service.getCharacteristic(_this.hap.Characteristic.Brightness) .onSet(_this.setBrightness.bind(_this)) .onGet(_this.getBrightness.bind(_this)); } export function addColorTemperatureCharacteristic(_this) { - _this.logs.trace('Adding ColorTemperature characteristic to service.'); + _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); _this.service.getCharacteristic(_this.hap.Characteristic.ColorTemperature) .onSet(_this.setColorTemperature.bind(_this)) .onGet(_this.getColorTemperature.bind(_this)); if (_this.api.versionGreaterOrEqual && _this.api.versionGreaterOrEqual('1.3.0-beta.46')) { - _this.logs.trace('Adding the adaptive lighting service to the accessory...'); + _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); _this.adaptiveLightingService = new _this.api.hap.AdaptiveLightingController(_this.service); _this.accessory.configureController(_this.adaptiveLightingService); } @@ -51,7 +51,6 @@ export function addAccessoryInformationCharacteristic(_this) { protoDevice: { uniqueId, modelNumber }, // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, } = _this.accessory.context.cachedDeviceInformation; - _this.logs.warn(_this.accessory.context.cachedDeviceInformation); // set accessory information _this.accessory.getService(_this.hap.Service.AccessoryInformation)! .setCharacteristic(_this.hap.Characteristic.Manufacturer, 'MagicHome') @@ -77,6 +76,8 @@ export function addConfiguredNameCharacteristic(_this) { _this.service.getCharacteristic(_this.hap.Characteristic.ConfiguredName) .onSet(_this.setConfiguredName.bind(_this)); } + _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + } diff --git a/src/platform.ts b/src/platform.ts index 9501dc4..4eb4992 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -47,10 +47,8 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin ) { hap = api.hap; this.config = config; - // this.log = new Logs(hbLogger, this.config.advancedOptions.logLevel); this.log = new Logs(hbLogger, config.globalAccessoryOptions?.logLevel ?? 3); this.api = api; - this.hbLogger = hbLogger; //this.logs = getLogger(); this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); logger.reverse().log('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); @@ -98,9 +96,9 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - const accesssoryGenerator = new AccessoryGenerator(this.api, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); + const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); await accesssoryGenerator.generateAccessories(); - //this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 10000); + this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 10000); } diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index f213620..4e6fd07 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -122,7 +122,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setConfiguredName(value: CharacteristicValue) { const name: string = value.toString(); - this.logs.debug('Renaming device to %o', name); + this.logs.debug('[Debug] Renaming device to %o', name); this.accessory.context.displayName = name; this.api.updatePlatformAccessories([this.accessory]); } @@ -180,7 +180,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { const deviceWriteStatus = this.deviceWriteStatus; - this.logs.trace(this.deviceWriteStatus); switch (deviceWriteStatus) { case ready: @@ -201,7 +200,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async writeStateToDevice(accessoryCommand: IAccessoryCommand): Promise { this.newAccessoryCommand = accessoryCommand; return new Promise((resolve, reject) => { - this.logs.trace(this.ColorCommandMode); return setTimeout(() => { this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessory.context.accessoryState, '\n Received Command', this.newAccessoryCommand); const sanitizedAcessoryCommand: IAccessoryCommand = _.merge({}, this.accessory.context.accessoryState, this.newAccessoryCommand); @@ -211,8 +209,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { sanitizedAcessoryCommand.isPowerCommand = true; } - // this.logs.trace('\nSanatizedCommand: ', sanitizedAcessoryCommand); - this.deviceWriteStatus = ready; return this.prepareCommand(sanitizedAcessoryCommand); @@ -222,10 +218,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async prepareCommand(accessoryCommand: IAccessoryCommand, options: ICommandOptions = MEDIUM_COMMAND_OPTIONS) { const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); - this.logs.trace('Outgoing Command:', deviceCommand); + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); this.latestDeviceCommand = deviceCommand; this.latestAccessoryCommand = accessoryCommand; - let deviceState: IDeviceState; this.queue.enqueue(async () => { @@ -235,15 +230,15 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } if (!(this.slowQueueRetry && this.queue.size < 1)) { - + let response; if (!accessoryCommand.isPowerCommand) { - this.latestDeviceState = await this.controller.setAllValues(deviceCommand, options); + response = await this.controller.setAllValues(deviceCommand, options); } else { - this.latestDeviceState = await this.controller.setOn(deviceCommand.isOn, options); + response = await this.controller.setOn(deviceCommand.isOn, options); } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); } - this.logs.debug('Received Device State:', this.latestDeviceState); }); } @@ -263,7 +258,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if (!deviceState) { deviceState = await this.controller?.fetchState() ?? this.accessory.context.cachedDeviceInformation.deviceState; } - this.logs.debug(this.accessory.context.displayName, '- Device State:\n', deviceState); + this.logs.debug(`[Debug] [${this.accessory.context.displayName}] - Device State:\n`, deviceState); this.accessory.context.cachedDeviceInformation.deviceState = deviceState; const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); let accessoryState: IAccessoryState; @@ -284,7 +279,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } _.merge(this.accessory.context.accessoryState, accessoryState); - this.logs.debug(this.accessory.context.displayName, '- Homebridge State:\n', this.accessory.context.accessoryState); + this.logs.debug(`[Debug] [${this.accessory.context.displayName}] - Homebridge State:\n`, this.accessory.context.accessoryState); } else { _.merge(this.accessory.context.accessoryState, { isOn: false }); } @@ -337,7 +332,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if (!_.isEqual(_.omit(this.latestDeviceState?.LED ?? {}, ['colorMask']), _.omit(this.latestDeviceCommand, ['colorMask']))) { if (this.slowQueueRetry) { timeout = setTimeout(async () => { - this.logs.trace(this.accessory.displayName, ': FINAL WRITE', this.latestDeviceCommand); + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Sending a slow write command to increase chance of success:\n`, this.latestDeviceCommand); this.slowQueueRetry = false; await this.prepareCommand(this.latestAccessoryCommand, SLOW_COMMAND_OPTIONS); this.fetchAndUpdateState(2); @@ -369,7 +364,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { addAccessoryInformationCharacteristic(this); - this.logs.trace('Adding Lightbulb service to accessory.'); + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); if (hasColor) { @@ -386,7 +381,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } if (!hasBrightness) { - this.logs.trace('Adding Switch service to accessory.'); //device is switch, register it as such + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Switch service to accessory.`); //device is switch, register it as such this.service = this.accessory.getService(this.hap.Service.Switch) ?? this.accessory.addService(this.hap.Service.Switch); } addOnCharacteristic(this); From 5cbfe1bb79eb339929d459830e6b208341c032cb Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Mon, 25 Oct 2021 22:19:29 -0400 Subject: [PATCH 22/42] changes to animations --- src/platformAccessory.ts | 79 ++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 4e6fd07..4b818ff 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -3,10 +3,45 @@ import type { CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, } from 'homebridge'; +const thunderstruck: IAnimationLoop = { + + 'name': 'ThunderStruck', + 'pattern': [ + { + 'colorStart': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + + }, + 'colorTarget': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + }, + 'transitionTimeMS': 0, + 'durationAtTargetMS': 100, + 'chancePercent': 10, + }, + { + 'colorStart': { + RGB: { red: 0, green: 255, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + + }, + 'colorTarget': { + RGB: { red: 255, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + }, + 'transitionTimeMS': 0, + 'durationAtTargetMS': 100, + 'chancePercent': 100, + }, + ], + 'accessories': [ + 'Office Light', + ], + 'accessoryOffsetMS': 0, +}; + import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus as DeviceStatus, IProtoDevice } from 'magichome-platform'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus as DeviceStatus, IProtoDevice, IAnimationLoop } from 'magichome-platform'; import { _ } from 'lodash'; import Queue from 'queue-promise'; import { Logs } from './logs'; @@ -19,9 +54,9 @@ const BUFFER_MS = 100; const FINAL_COMMAND_TIMEOUT = 100; const QUEUE_INTERVAL = 150; -const SLOW_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 20, bufferMS: 10, timeoutMS: 2000 }; -const MEDIUM_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 10, bufferMS: 10, timeoutMS: 200 }; -const FAST_COMMAND_OPTIONS: ICommandOptions = { verifyRetries: 0, bufferMS: 0, timeoutMS: 20 }; +const SLOW_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 20, bufferMS: 10, timeoutMS: 2000 }; +const MEDIUM_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 10, bufferMS: 10, timeoutMS: 200 }; +const FAST_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 0, bufferMS: 0, timeoutMS: 20 }; /** * Platform Accessory @@ -34,6 +69,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected readonly hap: HAP; protected adaptiveLightingService; + protected animationInterval; + protected interruptInterval; + protected intervals; protected newAccessoryCommand: IAccessoryCommand; protected latestDeviceCommand: IDeviceCommand; @@ -62,10 +100,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected readonly accessory: MagicHomeAccessory, public readonly config: PlatformConfig, protected readonly controller: BaseController, - protected readonly logging: Logging, + protected readonly hbLogger: Logging, ) { - this.setupMisc(); this.controller = controller; @@ -122,7 +159,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setConfiguredName(value: CharacteristicValue) { const name: string = value.toString(); - this.logs.debug('[Debug] Renaming device to %o', name); + this.logs.warn('Renaming device to %o', name); this.accessory.context.displayName = name; this.api.updatePlatformAccessories([this.accessory]); } @@ -179,6 +216,12 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { + // for (const interval of this.intervals) { + this.controller.clearAnimations(); + clearInterval(this.animationInterval); + + //} + const deviceWriteStatus = this.deviceWriteStatus; switch (deviceWriteStatus) { case ready: @@ -258,7 +301,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if (!deviceState) { deviceState = await this.controller?.fetchState() ?? this.accessory.context.cachedDeviceInformation.deviceState; } - this.logs.debug(`[Debug] [${this.accessory.context.displayName}] - Device State:\n`, deviceState); + this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); this.accessory.context.cachedDeviceInformation.deviceState = deviceState; const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); let accessoryState: IAccessoryState; @@ -279,7 +322,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } _.merge(this.accessory.context.accessoryState, accessoryState); - this.logs.debug(`[Debug] [${this.accessory.context.displayName}] - Homebridge State:\n`, this.accessory.context.accessoryState); + this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, this.accessory.context.accessoryState); } else { _.merge(this.accessory.context.accessoryState, { isOn: false }); } @@ -294,7 +337,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; @@ -329,7 +372,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.queue.on('end', async () => { - if (!_.isEqual(_.omit(this.latestDeviceState?.LED ?? {}, ['colorMask']), _.omit(this.latestDeviceCommand, ['colorMask']))) { + if (!_.isEqual(_.omit(this.latestDeviceState?.LEDState ?? {}, ['colorMask']), _.omit(this.latestDeviceCommand, ['colorMask']))) { if (this.slowQueueRetry) { timeout = setTimeout(async () => { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Sending a slow write command to increase chance of success:\n`, this.latestDeviceCommand); @@ -397,7 +440,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; this.colorOffSaturationLevel = colorOffSaturationLevel; - this.logs = new Logs(this.logging, logLevel ?? 3); + this.logs = new Logs(this.hbLogger, logLevel ?? 3); } @@ -419,4 +462,16 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } + protected async animateMe() { + this.logs.warn('animating thunderstruck'); + clearInterval(this.animationInterval); + //this.controller.animateIndividual(thunderstruck); + + + this.controller.animateIndividual(thunderstruck).then(() => this.animateMe()); + // this.animationInterval = setInterval(() => { + // this.controller.animateIndividual(thunderstruck); + // }, 1000); + } + } // ZackneticMagichomePlatformAccessory class \ No newline at end of file From d67ec6fc3778ad220b9b36ffa5299622d0fd166f Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Mon, 25 Oct 2021 22:19:56 -0400 Subject: [PATCH 23/42] changes to animation --- src/AccessoryGenerator.ts | 99 ++++++++++++++--------------------- src/accessories/GRBStrip.ts | 85 +++++++++++++++++------------- src/accessories/RGBWBulb.ts | 2 +- src/accessories/RGBWStrip.ts | 2 +- src/accessories/RGBWWBulb.ts | 2 +- src/accessories/RGBWWStrip.ts | 8 ++- src/logs.ts | 14 +++-- src/platform.ts | 7 +-- 8 files changed, 106 insertions(+), 113 deletions(-) diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 6003c98..a1e14f9 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -36,9 +36,8 @@ export class AccessoryGenerator { public async generateAccessories() { this.logs.info('Scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { - const accessories = this.discoverAccessories(controllers); - - return accessories; + this.discoverAccessories(controllers); + this.registerOfflineAccessories(); }).catch(error => { this.logs.error(error); }); @@ -71,74 +70,43 @@ export class AccessoryGenerator { public async rescanAccessories() { this.logs.trace('Re-scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { - await this.reDiscoverAccessories(controllers); + await this.discoverAccessories(controllers); }).catch(error => { this.logs.error(error); }); } - reDiscoverAccessories(controllers: Map) { - - const newAccessoriesList: MagicHomeAccessory[] = []; - const existingAccessoriesList: MagicHomeAccessory[] = []; - let accessory; - for (const [uniqueId, controller] of Object.entries(controllers)) { - - const homebridgeUUID = this.hap.uuid.generate(uniqueId); - - if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { - const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); - accessory = this.processExistingAccessory(controller, existingAccessory); - - this.accessoriesFromDiskMap.delete(homebridgeUUID); - - existingAccessoriesList.push(accessory); - this.logs.info(`[Info] [${existingAccessory.context.displayName}] - Found previously unreachable existing accessory during a re-scan. Updating...`); - - } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { - accessory = this.createNewAccessory(controller, homebridgeUUID); - newAccessoriesList.push(accessory); //add it to new accessory list - this.logs.info(`[Info] [${accessory.context.displayName}] - Found previously unseen accessory during a re-scan. Registering...`); - } - - this.activeAccessoriesMap.set(homebridgeUUID, accessory); - } - - this.registerNewAccessories(newAccessoriesList); //register new accessories from scan - this.updateExistingAccessories(existingAccessoriesList); - } - discoverAccessories(controllers: Map) { const newAccessoriesList: MagicHomeAccessory[] = []; const existingAccessoriesList: MagicHomeAccessory[] = []; - let accessory; - for (const [uniqueId, controller] of Object.entries(controllers)) { + for (const [uniqueId, controller] of controllers.entries()) { const homebridgeUUID = this.hap.uuid.generate(uniqueId); - + let accessory; if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); - accessory = this.processExistingAccessory(controller, existingAccessory); - this.logs.info(`[Info] [${accessory.context.displayName}] - Found existing accessory. Updating...`); this.accessoriesFromDiskMap.delete(homebridgeUUID); - existingAccessoriesList.push(accessory); - } else { + if (this.activeAccessoriesMap.has(homebridgeUUID)) { + this.logs.warn(`[${existingAccessory.context.displayName}] - Found existing accessory that was unseen previous scan. Updating...`); + continue; + } + accessory = this.processExistingAccessory(controller, existingAccessory); + this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); + if (accessory) { + existingAccessoriesList.push(accessory); + } else { + continue; + } + } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { accessory = this.createNewAccessory(controller, homebridgeUUID); - this.logs.info(`[Info] [${accessory.context.displayName}] - Found new accessory. Registering...`); + this.logs.info(`[${accessory.context.displayName}] - Found new accessory. Registering...`); newAccessoriesList.push(accessory); //add it to new accessory list } this.activeAccessoriesMap.set(homebridgeUUID, accessory); } - this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { - const homebridgeUUID = this.hap.uuid.generate(offlineAccessory.context.cachedDeviceInformation.protoDevice.uniqueId); - await this.processOfflineAccessory(offlineAccessory); - existingAccessoriesList.push(offlineAccessory); - this.activeAccessoriesMap.set(homebridgeUUID, offlineAccessory); - }); - this.registerNewAccessories(newAccessoriesList); //register new accessories from scan this.updateExistingAccessories(existingAccessoriesList); } @@ -164,21 +132,31 @@ export class AccessoryGenerator { return newAccessory; } + registerOfflineAccessories() { + const existingAccessoriesList: MagicHomeAccessory[] = []; + this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { + const homebridgeUUID = this.hap.uuid.generate(offlineAccessory.context.cachedDeviceInformation.protoDevice.uniqueId); + await this.processOfflineAccessory(offlineAccessory); + existingAccessoriesList.push(offlineAccessory); + this.activeAccessoriesMap.set(homebridgeUUID, offlineAccessory); + }); + this.updateExistingAccessories(existingAccessoriesList); + } + processExistingAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { try { - const cachedDeviceInformation = controller?.getCachedDeviceInformation() ?? existingAccessory.context.cachedDeviceInformation; const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; if (!this.isAllowed(uniqueId) || !this.isFresh(cachedDeviceInformation, existingAccessory)) { - return; + return null; } _.merge(existingAccessory.context, { cachedDeviceInformation, restartsSinceSeen: 0 }); try { new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger); } catch (error) { - this.logs.error('[processExistingAccessory] [Error]: ', error); + this.logs.error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: `, error); } return existingAccessory; } catch (error) { @@ -189,12 +167,11 @@ export class AccessoryGenerator { async processOfflineAccessory(offlineAccessory) { offlineAccessory.context.restartsSinceSeen++; const { deviceState, protoDevice, deviceAPI, deviceAPI: { description } } = offlineAccessory.context.cachedDeviceInformation; - this.logs.warn(`[Warning] [${offlineAccessory.context.displayName}] [UID: ${protoDevice.uniqueId}] - Device Unreachable. Registering accessory with cached information.`); + this.logs.warn(`[${offlineAccessory.context.displayName}] [UID: ${protoDevice.uniqueId}] - Device Unreachable. Registering accessory with cached information.`); this.logs.trace(deviceState); const controller = await this.controllerGenerator.createCustomControllers({ protoDevice, deviceAPI, deviceState }); new homekitInterface[description](this.api, offlineAccessory, this.config, controller, this.hbLogger); - } registerNewAccessories(newAccessories: MagicHomeAccessory[]) { @@ -208,13 +185,11 @@ export class AccessoryGenerator { } isFresh(cachedInformation, existingAccessory: MagicHomeAccessory): boolean { - let isFresh = true; - if (existingAccessory.context.displayName.toString().toLowerCase().includes('delete')) { - + if (existingAccessory.context.displayName?.toString().toLowerCase().includes('delete')) { + this.logs.warn('should be deleting...'); this.unregisterAccessory(existingAccessory, - `Successfully pruned accessory: ${existingAccessory.context.displayName} - due to being marked for deletion\n`); + `Successfully pruned accessory: ${existingAccessory.context.displayName} due to being marked for deletion\n`); isFresh = false; } @@ -242,8 +217,10 @@ export class AccessoryGenerator { } unregisterAccessory(existingAccessory: MagicHomeAccessory, reason: string) { + + this.activeAccessoriesMap.delete(existingAccessory.UUID); this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]); - this.hbLogger.warn(reason); + this.logs.warn(reason); } // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; diff --git a/src/accessories/GRBStrip.ts b/src/accessories/GRBStrip.ts index 64b5893..4e8b2e7 100644 --- a/src/accessories/GRBStrip.ts +++ b/src/accessories/GRBStrip.ts @@ -1,39 +1,52 @@ -import { clamp, convertHSLtoRGB } from '../misc/utils'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + + export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - // public eightByteProtocol = 2; - // async updateDeviceState() { - - // //**** local variables ****\\ - // const hsl = this.lightState.HSL; - // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - // const brightness = this.lightState.brightness; - - // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // // this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - - // const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - // //we default the mask to turn on color. Other values can still be set, they just wont turn on - - // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - // const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - // const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - // const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - - - // if(this.eightByteProtocol == 0){ - // // await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() - // } else if(this.eightByteProtocol == 1){ - // //await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); - // } else if (this.eightByteProtocol == 2){ - // //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - // // await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() - // } - - - // }//setColor - - -} \ No newline at end of file + + + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + + const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + const { hue, saturation } = HSL; + const { red, green, blue }: IColorRGB = convertHSLtoRGB(HSL); + + + //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed + //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) + const _green = Math.round((red / 100) * brightness); + const _red = Math.round((green / 100) * brightness); + const _blue = Math.round((blue / 100) * brightness); + + + const deviceCommand: IDeviceCommand = { isOn, RGB: {red: _red, green: _green, blue: _blue } }; + return deviceCommand; + }//setColor + + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { LEDState: { RGB: { red, green, blue }, isOn } } = deviceState; + const RGB: IColorRGB = { red: green, green: red, blue }; + // eslint-disable-next-line prefer-const + let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let brightness = 0; + + //Brightness + if (isOn) { + brightness = luminance; + } + + + const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; + return accessoryState; + } + + +} + + + + diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index 7a9529e..7f1e6b2 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -49,7 +49,7 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 1a1db10..82ea7ef 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -64,7 +64,7 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index ff1064f..53f4992 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -66,7 +66,7 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { }//setColor deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LED: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index 6fc9ccc..ad0f6fd 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -8,6 +8,10 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + if(HSL.saturation < 10){ + this.animateMe(); + return; + } const { hue, saturation } = HSL; const RGB: IColorRGB = convertHSLtoRGB(HSL); // let _CCT: IColorCCT; @@ -79,8 +83,8 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { }//setColor deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - - const { LED: { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + + const { LEDState: { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); diff --git a/src/logs.ts b/src/logs.ts index 827ab5f..aebc78b 100644 --- a/src/logs.ts +++ b/src/logs.ts @@ -1,40 +1,38 @@ import { Logging } from 'homebridge'; -import logger from 'node-color-log'; export class Logs { - constructor(private logging: Logging, private readonly level = 3) { + constructor(private hbLogger: Logging, private readonly level = 3) { logs = this; this.level = level; } trace(message, ...parameters: any[]) { if (this.level >= 5) { - this.logging.info(message, ...parameters); + this.hbLogger.info('[Trace]', message, ...parameters); } } debug(message, ...parameters: any[]) { if (this.level >= 4) { - this.logging.info(message, ...parameters); + this.hbLogger.info('[Debug]', message, ...parameters); } } info(message, ...parameters: any[]) { if (this.level >= 3) { - this.logging.info(message, ...parameters); + this.hbLogger.info('[Info]', message, ...parameters); } } warn(message, ...parameters: any[]) { if (this.level >= 2) { - logger.bgColor('yellow').color('black').log('[Warning] ').joint().color('yellow').log(message, ...parameters); - // this.logging.warn(message, ...parameters); + this.hbLogger.warn('[Warning]', message, ...parameters); } } error(message, ...parameters: any[]) { if (this.level >= 1) { - this.logging.error(message, ...parameters); + this.hbLogger.error('[Error]', message, ...parameters); } } } diff --git a/src/platform.ts b/src/platform.ts index 4eb4992..e5b10ea 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -41,13 +41,14 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin public readonly accessoriesFromDiskMap: Map = new Map(); private readonly hbLogger: Logging; constructor( - hbLogger: Logging, + logging: Logging, config: PlatformConfig, api: API, ) { + this.hbLogger = logging; hap = api.hap; this.config = config; - this.log = new Logs(hbLogger, config.globalAccessoryOptions?.logLevel ?? 3); + this.log = new Logs(logging, config?.globalAccessoryOptions?.logLevel ?? 3); this.api = api; //this.logs = getLogger(); this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); @@ -98,7 +99,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); await accesssoryGenerator.generateAccessories(); - this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 10000); + this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); } From 565f4dfdbb251dcd82099f8ee45f941b5668a78d Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Wed, 27 Oct 2021 13:28:15 -0400 Subject: [PATCH 24/42] animation improvement --- src/accessories/RGBWBulb.ts | 47 ++++++------ src/accessories/RGBWStrip.ts | 8 +- src/accessories/RGBWWBulb.ts | 9 ++- src/accessories/RGBWWStrip.ts | 16 +--- src/misc/utils.ts | 133 +++++++++++++++++----------------- src/platformAccessory.ts | 68 ++++++++++------- 6 files changed, 146 insertions(+), 135 deletions(-) diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index 7f1e6b2..d6b589b 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -1,27 +1,27 @@ import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT } from '../misc/utils'; +import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - const {hue, saturation} = HSL; - const RGB:IColorRGB = convertHSLtoRGB(HSL); - - let {red, green, blue} = RGB; + const { hue, saturation } = HSL; + const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); + + let { red, green, blue } = RGB; let warmWhite; let colorMask = 0xF0; - + //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - red = Math.round((red / 100) * brightness); - green = Math.round((green / 100) * brightness); - blue = Math.round((blue / 100) * brightness); + // red = Math.round((red / 100) * brightness); + // green = Math.round((green / 100) * brightness); + // blue = Math.round((blue / 100) * brightness); warmWhite = Math.round(2.55 * brightness); if (hue == 31 && saturation == 33) { @@ -42,31 +42,36 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { warmWhite = 0; } - const deviceCommand: IDeviceCommand = { isOn, RGB:{red, green, blue}, CCT: {warmWhite}, colorMask}; + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite }, colorMask }; return deviceCommand; - + }//setColor - + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; - + let colorTemperature = 140; if (luminance > 0 && isOn) { brightness = luminance; } else if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - if (warmWhite > coldWhite) { - saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); - } else { - saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); + brightness = clamp(warmWhite / 2.55, 0, 100); + } + + if (warmWhite > 0) { + saturation = luminance; + colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); + if (saturation <= 2) { + const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); + hue = hueSat[0]; + saturation = 10; } } - const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; + const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; return accessoryState; } - + } \ No newline at end of file diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 82ea7ef..b244ad3 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -10,17 +10,11 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; const { hue, saturation } = HSL; - const RGB: IColorRGB = convertHSLtoRGB(HSL); - + const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); let { red, green, blue } = RGB, warmWhite; let colorMask = 0xFF; - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - red = Math.round((red / 100) * brightness); - green = Math.round((green / 100) * brightness); - blue = Math.round((blue / 100) * brightness); warmWhite = Math.round(2.55 * brightness); if (hue == 31 && saturation == 33) { diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index 53f4992..668042d 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -9,10 +9,11 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; const { hue, saturation } = HSL; - const RGB: IColorRGB = convertHSLtoRGB(HSL); + + const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); // let _CCT: IColorCCT; // if (this.ColorCommandMode == 'HSL') { - const _CCT:IColorCCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" + const _CCT: IColorCCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" // } else { // _CCT = cctToWhiteTemperature(colorTemperature); // } @@ -49,7 +50,7 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). //White colors were already calculated above } else if (saturation < 20) { - + red = 0; green = 0; blue = 0; @@ -87,7 +88,7 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { saturation = 10; } - const accessoryState: IAccessoryState = { HSL: {hue, saturation, luminance}, isOn, colorTemperature: 140, brightness }; + const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; return accessoryState; } diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index ad0f6fd..62af9cd 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -8,12 +8,10 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - if(HSL.saturation < 10){ - this.animateMe(); - return; - } + const { hue, saturation } = HSL; - const RGB: IColorRGB = convertHSLtoRGB(HSL); + const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); + // let _CCT: IColorCCT; // if (this.ColorCommandMode == 'HSL') { const _CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "convertHueToColorCCT()" @@ -23,12 +21,6 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; let colorMask = 0xFF; - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - red = Math.round((red / 100) * brightness); - green = Math.round((green / 100) * brightness); - blue = Math.round((blue / 100) * brightness); - warmWhite = Math.round((warmWhite / 100) * brightness); coldWhite = Math.round((coldWhite / 100) * brightness); @@ -108,7 +100,7 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { hue = hueSat[0]; saturation = 10; } - } + } const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; return accessoryState; diff --git a/src/misc/utils.ts b/src/misc/utils.ts index 6458559..4dc7812 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -2,6 +2,7 @@ import { existsSync, readFileSync } from 'fs'; import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; import { IAccessoryCommand, IAccessoryState, IColorHSL } from './types'; + export function clamp(value: number, min: number, max: number) { return Math.min(max, Math.max(min, value)); } @@ -32,42 +33,43 @@ export function checksum(buffer: Uint8Array) { //================================================= // Start Convert RGBtoHSL // export function convertRGBtoHSL(RGB: IColorRGB) { + const { red, green, blue } = RGB; + + const r = red / 255; const g = green / 255; const b = blue / 255; - const min = Math.min(r, g, b); - const max = Math.max(r, g, b); - const delta = max - min; - let h = 0; - let s = 0; - if (max === min) { + let h, s, l; + h = s = l = 0; + + const max = Math.max(r, g, b); + const min = Math.min(r, g, b); + const C = max - min; + if (C == 0) { h = 0; - } else if (r === max) { - h = (g - b) / delta; - } else if (g === max) { - h = 2 + (b - r) / delta; - } else if (b === max) { - h = 4 + (r - g) / delta; + } else if (max == r) { + h = ((g - b) / C) % 6; + } else if (max == g) { + h = (b - r) / C + 2; + } else { + h = (r - g) / C + 4; } - - h = Math.min(h * 60, 360); - + h *= 60; if (h < 0) { h += 360; } - - const l = max / 2.55; - - if (max === min) { + l = max; + if (l == 0) { s = 0; - } else if (l <= 0.5) { - s = delta / (max + min); } else { - s = delta / (2 - max - min); + s = C / l; } - const HSL: IColorHSL = { hue: h, saturation: s * 100, luminance: l * 100 }; + s *= 100; + l *= 100; + + const HSL: IColorHSL = { hue: Math.floor(h), saturation: Math.floor(s), luminance: Math.floor(l) }; return HSL; } @@ -79,52 +81,51 @@ export function convertRGBtoHSL(RGB: IColorRGB) { // Start Convert HSLtoRGB // export function convertHSLtoRGB(HSL: IColorHSL): IColorRGB { - let RGB: IColorRGB; const { hue, saturation, luminance } = HSL; - const h = hue / 360; - const s = saturation / 100; - const l = 50 / 100; - let t2; - let t3; - let val; - - if (s === 0) { - val = l * 255; - RGB = { red: val, green: val, blue: val }; - } - if (l < 0.5) { - t2 = l * (1 + s); + const h = hue; + const s = saturation / 100.0; + const l = luminance / 100.0; + + const C = l * s; + const hh = h / 60.0; + const X = C * (1.0 - Math.abs((hh % 2) - 1.0)); + + let r, g, b; + r = g = b = 0; + + if (hh >= 0 && hh < 1) { + r = C; + g = X; + } else if (hh >= 1 && hh < 2) { + r = X; + g = C; + } else if (hh >= 2 && hh < 3) { + g = C; + b = X; + } else if (hh >= 3 && hh < 4) { + g = X; + b = C; + } else if (hh >= 4 && hh < 5) { + r = X; + b = C; } else { - t2 = l + s - l * s; + r = C; + b = X; } - const t1 = 2 * l - t2; - - const rgb = [0, 0, 0]; - for (let i = 0; i < 3; i++) { - t3 = h + 1 / 3 * -(i - 1); - if (t3 < 0) { - t3++; - } - - if (t3 > 1) { - t3--; - } - - if (6 * t3 < 1) { - val = t1 + (t2 - t1) * 6 * t3; - } else if (2 * t3 < 1) { - val = t2; - } else if (3 * t3 < 2) { - val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; - } else { - val = t1; - } - - rgb[i] = val * 255; - } - RGB = { red: rgb[0], green: rgb[1], blue: rgb[2] }; + const m = l - C; + r += m; + g += m; + b += m; + r *= 255.0; + g *= 255.0; + b *= 255.0; + r = Math.floor(r); + g = Math.floor(g); + b = Math.floor(b); + + const RGB = { red: r, green: g, blue: b }; return RGB; } //================================================= @@ -176,7 +177,7 @@ export function convertHueToColorCCT(hue: number): IColorCCT { coldWhite = 255 - warmWhite; } - return {warmWhite, coldWhite}; + return { warmWhite, coldWhite }; } //hueToWhiteTemperature export function cctToWhiteTemperature(CCT: number, multiplier = 0): { warmWhite: number, coldWhite: number } { @@ -210,7 +211,7 @@ export function delayToSpeed(delay: never) { clamped -= 1; // bring into interval [0, 30] return 100 - (clamped / 30) * 100; } - + export function speedToDelay(speed: never) { const clamped = clamp(speed, 0, 100); return 30 - (clamped / 100) * 30 + 1; diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 4b818ff..fc22c97 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -11,24 +11,48 @@ const thunderstruck: IAnimationLoop = { 'colorStart': { RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + }, + 'colorTarget': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + }, + 'transitionTimeMS': 1000, + 'durationAtTargetMS': [10000, 30000], + 'chancePercent': 100, + }, + { + 'colorStart': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + }, 'colorTarget': { RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, }, - 'transitionTimeMS': 0, - 'durationAtTargetMS': 100, - 'chancePercent': 10, + 'transitionTimeMS': 50, + 'durationAtTargetMS': [50, 150], + 'chancePercent': 50, }, { 'colorStart': { - RGB: { red: 0, green: 255, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, }, 'colorTarget': { - RGB: { red: 255, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, }, - 'transitionTimeMS': 0, - 'durationAtTargetMS': 100, + 'transitionTimeMS': 30, + 'durationAtTargetMS': [200, 300], + 'chancePercent': 100, + }, + { + 'colorStart': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + + }, + 'colorTarget': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + }, + 'transitionTimeMS': 30, + 'durationAtTargetMS': [50, 300], 'chancePercent': 100, }, ], @@ -50,12 +74,12 @@ const { ready, pending, busy } = DeviceStatus; const CCT = 'CCT'; const HSL = 'HSL'; -const BUFFER_MS = 100; +const BUFFER_MS = 0; const FINAL_COMMAND_TIMEOUT = 100; const QUEUE_INTERVAL = 150; -const SLOW_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 20, bufferMS: 10, timeoutMS: 2000 }; -const MEDIUM_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 10, bufferMS: 10, timeoutMS: 200 }; +const SLOW_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 20, bufferMS: 0, timeoutMS: 2000 }; +const MEDIUM_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 20, bufferMS: 0, timeoutMS: 1000 }; const FAST_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 0, bufferMS: 0, timeoutMS: 20 }; /** @@ -217,8 +241,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { // for (const interval of this.intervals) { - this.controller.clearAnimations(); - clearInterval(this.animationInterval); + this.controller.clearAnimations(); + clearInterval(this.animationInterval); //} @@ -251,15 +275,16 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; } - - this.deviceWriteStatus = ready; - - return this.prepareCommand(sanitizedAcessoryCommand); + resolve(this.prepareCommand(sanitizedAcessoryCommand)); }, BUFFER_MS); }); } protected async prepareCommand(accessoryCommand: IAccessoryCommand, options: ICommandOptions = MEDIUM_COMMAND_OPTIONS) { + // if(accessoryCommand.HSL.saturation < 10){ + // this.animateMe(); + // return; + // } const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); this.latestDeviceCommand = deviceCommand; @@ -462,16 +487,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } - protected async animateMe() { + protected animateMe() { this.logs.warn('animating thunderstruck'); - clearInterval(this.animationInterval); - //this.controller.animateIndividual(thunderstruck); - - - this.controller.animateIndividual(thunderstruck).then(() => this.animateMe()); - // this.animationInterval = setInterval(() => { - // this.controller.animateIndividual(thunderstruck); - // }, 1000); + this.controller.animateIndividual(thunderstruck); } } // ZackneticMagichomePlatformAccessory class \ No newline at end of file From 93c625c1c40ea841f2f44b93a5463a569d623939 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Mon, 15 Nov 2021 08:53:43 -0500 Subject: [PATCH 25/42] additional accessory generation logic --- package-lock.json | 3436 ++++++++++++++++++++++++++++++++++++- src/AccessoryGenerator.ts | 59 +- src/platformAccessory.ts | 93 +- tsconfig.json | 1 + 4 files changed, 3554 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 09144d3..410b9da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,3439 @@ { "name": "homebridge-magichome-dynamic-platform", "version": "1.9.3-beta.4", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "homebridge-magichome-dynamic-platform", + "version": "1.9.3-beta.4", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Zacknetic" + }, + { + "type": "paypal", + "url": "https://www.paypal.com/paypalme/ZacharyAvino" + } + ], + "license": "Apache-2.0", + "dependencies": { + "color-convert": "^2.0.1", + "homebridge-lib": "^5.1.14", + "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", + "node-color-log": "^6.0.0", + "promise-queue": "^2.2.5", + "queue-promise": "^2.2.1" + }, + "devDependencies": { + "@types/node": "^14.17.19", + "@types/promise-queue": "^2.2.0", + "@typescript-eslint/eslint-plugin": "^3.10.1", + "@typescript-eslint/parser": "^3.10.1", + "eslint": "^7.32.0", + "homebridge": "^1.3.4", + "nodemon": "^2.0.13", + "rimraf": "^3.0.2", + "ts-node": "^8.10.2", + "typescript": "^3.9.10" + }, + "engines": { + "homebridge": ">=1.0.0", + "node": ">=10.17.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@homebridge/ciao": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.2.tgz", + "integrity": "sha512-31IfDKMqxfT+uVNXj0/TmYMou57gP8CUrh0vABzsc5QMsoCQ4Oo5uYQp0oJJyzxTBkF2pFvjR3XlWAapl0VyCg==", + "dev": true, + "dependencies": { + "debug": "^4.3.1", + "fast-deep-equal": "^3.1.3", + "source-map-support": "^0.5.19", + "tslib": "^2.0.3" + }, + "bin": { + "ciao-bcs": "lib/bonjour-conformance-testing.js" + } + }, + "node_modules/@homebridge/ciao/node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", + "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==" + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@types/eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.17.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.19.tgz", + "integrity": "sha512-jjYI6NkyfXykucU6ELEoT64QyKOdvaA6enOqKtP4xUsGY0X0ZUZz29fUmrTRo+7v7c6TgDu82q3GHHaCEkqZwA==", + "dev": true + }, + "node_modules/@types/promise-queue": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/promise-queue/-/promise-queue-2.2.0.tgz", + "integrity": "sha512-9QLtid6GxEWqpF+QImxBRG6bSVOHtpAm2kXuIyEvZBbSOupLvqhhJv8uaHbS8kUL8FDjzH3RWcSyC/52WOVtGw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.10.1.tgz", + "integrity": "sha512-PQg0emRtzZFWq6PxBcdxRH3QIQiyFO3WCVpRL3fgj5oQS3CDs3AeAKfv4DxNhzn8ITdNJGJ4D3Qw8eAJf3lXeQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "3.10.1", + "debug": "^4.1.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.0.0", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^3.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz", + "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.3", + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/typescript-estree": "3.10.1", + "eslint-scope": "^5.0.0", + "eslint-utils": "^2.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.10.1.tgz", + "integrity": "sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw==", + "dev": true, + "dependencies": { + "@types/eslint-visitor-keys": "^1.0.0", + "@typescript-eslint/experimental-utils": "3.10.1", + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/typescript-estree": "3.10.1", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz", + "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz", + "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "3.10.1", + "@typescript-eslint/visitor-keys": "3.10.1", + "debug": "^4.1.1", + "glob": "^7.1.6", + "is-glob": "^4.0.1", + "lodash": "^4.17.15", + "semver": "^7.3.2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz", + "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-styles/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/ansi-styles/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bonjour-hap": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.3.tgz", + "integrity": "sha512-qyLU96ICCYbpOFiMCjA3aNYH5Jc83XH1YX6+EXWukyyiNXzXH2LZv8AVmGW33FceF3gfUM4jYoKX2xChtNDUnA==", + "dependencies": { + "array-flatten": "^2.1.2", + "deep-equal": "^2.0.5", + "ip": "^1.1.5", + "multicast-dns": "^7.2.3", + "multicast-dns-service-types": "^1.1.0" + } + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-equal": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", + "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", + "dependencies": { + "call-bind": "^1.0.0", + "es-get-iterator": "^1.1.1", + "get-intrinsic": "^1.0.1", + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.2", + "is-regex": "^1.1.1", + "isarray": "^2.0.5", + "object-is": "^1.1.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.3", + "which-boxed-primitive": "^1.0.1", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dns-packet": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.0.tgz", + "integrity": "sha512-Nce7YLu6YCgWRvOmDBsJMo9M5/jV3lEZ5vUWnWXYmwURvPylHvq7nkDWhNmk1ZQoZZOP7oQh/S0lSxbisKOfHg==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/es-abstract": { + "version": "1.18.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", + "integrity": "sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-string": "^1.0.7", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fast-srp-hap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.3.tgz", + "integrity": "sha512-4P8TBD0all202L9FbeSsWc9qDlpaYp065VbUwbuNYZDYdOJ02UlWaDkai6d/+6/I8/sdtVYAVd17PEZDKbqopQ==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "dev": true + }, + "node_modules/foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/futoin-hkdf": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.3.3.tgz", + "integrity": "sha512-oR75fYk3B3X9/B02Y6vusrBKucrpC6VjxhRL+C6B7FwUpuSRHbhBNG3AZbcE/xPyJmEQWsyqUFp3VeNNbA3S7A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "dev": true + }, + "node_modules/hap-nodejs": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.9.4.tgz", + "integrity": "sha512-wGYq6nQ8c5+V7iLr9Fa7XpOGAntmB0ejfOsjoIhXe/WHOXX9gGDwYgQTHg+dwmJZjW7RBoOyRRdB7/oa/NYovw==", + "dev": true, + "dependencies": { + "@homebridge/ciao": "~1.1.2", + "bonjour-hap": "~3.6.2", + "debug": "^4.3.1", + "fast-srp-hap": "2.0.3", + "futoin-hkdf": "~1.3.2", + "ip": "^1.1.3", + "node-persist": "^0.0.11", + "source-map-support": "^0.5.19", + "tslib": "^2.1.0", + "tweetnacl": "^1.0.3" + }, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/hap-nodejs/node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/homebridge": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.3.4.tgz", + "integrity": "sha512-I2vxabWpKHly3htXvOgnJbO79pXzrorz6/htRUCD3UTWXnzURqUFhevv9c/Mji3YeKxluIXCyXyiGAuDfx1m3A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "commander": "5.1.0", + "fs-extra": "^9.1.0", + "hap-nodejs": "0.9.4", + "qrcode-terminal": "^0.12.0", + "semver": "^7.3.4", + "source-map-support": "^0.5.19" + }, + "bin": { + "homebridge": "bin/homebridge" + }, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/homebridge-lib": { + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.1.14.tgz", + "integrity": "sha512-ZtGssTd9uoKv169ChDoiMmCLdzHGtHtlAJ7zM8JM9u8Sxgm/X8LtoV+OB78m9TuHEuvmv5wdJqguYYSFycclgw==", + "dependencies": { + "bonjour-hap": "^3.6.3", + "chalk": "^4.1.2", + "semver": "^7.3.5" + }, + "bin": { + "hap": "cli/hap.js", + "json": "cli/json.js", + "upnp": "cli/upnp.js" + }, + "engines": { + "homebridge": "^1.3.4", + "node": "^14.18.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", + "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", + "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.3.tgz", + "integrity": "sha512-TzxgGSLRLB7tqAlzjgd2x2ZE0cDsGFq4rs9W4yE5xp+7hlRXeUQGtXZsTGfGw2FwWB45rfe8DtXMYBpZGMLUng==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-color-log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/node-color-log/-/node-color-log-6.0.0.tgz", + "integrity": "sha512-zaDIxwDZWCwjcndvyXY30sT+h6pcviEvIpuSGZx2kBKVPloMU5xcFgHK85cnAmMeaDyL4xQmbSsGzp3fwOt3Bg==" + }, + "node_modules/node-persist": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", + "integrity": "sha1-1m66Pr72IPB5Uw+nsTB2qQZmWHQ=", + "dev": true, + "dependencies": { + "mkdirp": "~0.5.1", + "q": "~1.1.1" + } + }, + "node_modules/nodemon": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.13.tgz", + "integrity": "sha512-UMXMpsZsv1UXUttCn6gv8eQPhn6DR4BW+txnL3IN5IHqrCwcrT/yWHfL35UsClGXknTH79r5xbu+6J1zNHuSyA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^5.1.0" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-queue": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", + "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/q": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", + "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qrcode-terminal": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", + "dev": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/queue-promise": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/queue-promise/-/queue-promise-2.2.1.tgz", + "integrity": "sha512-C3eyRwLF9m6dPV4MtqMVFX+Xmc7keZ9Ievm3jJ/wWM5t3uVbFnGsJXwpYzZ4LaIEcX9bss/mdaKzyrO6xheRuA==", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", + "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.6.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", + "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-node": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "typescript": ">=2.7" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "dependencies": { + "debug": "^2.2.0" + } + }, + "node_modules/undefsafe/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/undefsafe/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", + "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.5", + "foreach": "^2.0.5", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.12.11", @@ -234,7 +3665,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "ajv": { "version": "6.12.6", diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index a1e14f9..cc27373 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -36,7 +36,7 @@ export class AccessoryGenerator { public async generateAccessories() { this.logs.info('Scanning network for MagicHome accessories.'); return await this.controllerGenerator.discoverControllers().then(async controllers => { - this.discoverAccessories(controllers); + await this.discoverAccessories(controllers); this.registerOfflineAccessories(); }).catch(error => { this.logs.error(error); @@ -76,45 +76,51 @@ export class AccessoryGenerator { }); } - discoverAccessories(controllers: Map) { + async discoverAccessories(controllers: Map) { const newAccessoriesList: MagicHomeAccessory[] = []; const existingAccessoriesList: MagicHomeAccessory[] = []; + for (const [uniqueId, controller] of controllers.entries()) { - const homebridgeUUID = this.hap.uuid.generate(uniqueId); - let accessory; - if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { - - const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); - this.accessoriesFromDiskMap.delete(homebridgeUUID); - if (this.activeAccessoriesMap.has(homebridgeUUID)) { - this.logs.warn(`[${existingAccessory.context.displayName}] - Found existing accessory that was unseen previous scan. Updating...`); - continue; + new Promise((resolve, reject) => { + const homebridgeUUID = this.hap.uuid.generate(uniqueId); + let accessory; + if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { + + const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); + this.accessoriesFromDiskMap.delete(homebridgeUUID); + if (this.activeAccessoriesMap.has(homebridgeUUID)) { + this.logs.warn(`[${existingAccessory.context.displayName}] - Found existing accessory that was unseen previous scan. Updating...`); + reject; + } + accessory = this.processExistingAccessory(controller, existingAccessory); + this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); + if (accessory) { + existingAccessoriesList.push(accessory); + } else { + reject; + } + } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { + accessory = this.createNewAccessory(controller, homebridgeUUID); + console.log(accessory.context.displayName); + this.logs.info(`[${accessory.context.displayName}] - Found new accessory. Registering...`); + newAccessoriesList.push(accessory); //add it to new accessory list } - accessory = this.processExistingAccessory(controller, existingAccessory); - this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); - if (accessory) { - existingAccessoriesList.push(accessory); - } else { - continue; - } - } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { - accessory = this.createNewAccessory(controller, homebridgeUUID); - this.logs.info(`[${accessory.context.displayName}] - Found new accessory. Registering...`); - newAccessoriesList.push(accessory); //add it to new accessory list - } - this.activeAccessoriesMap.set(homebridgeUUID, accessory); + this.activeAccessoriesMap.set(homebridgeUUID, accessory); + }).catch(); } this.registerNewAccessories(newAccessoriesList); //register new accessories from scan this.updateExistingAccessories(existingAccessoriesList); + } - createNewAccessory(controller: BaseController, homebridgeUUID: string): MagicHomeAccessory { + createNewAccessory(controller: BaseController, homebridgeUUID: string)/*: Promise*/ { const cachedDeviceInformation = controller.getCachedDeviceInformation(); const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; + // console.log(description); if (!this.isAllowed(uniqueId)) { return; @@ -122,7 +128,7 @@ export class AccessoryGenerator { const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; newAccessory.context = { cachedDeviceInformation, displayName: description as string, restartsSinceSeen: 0 }; - + // console.log(newAccessory.context.displayName); try { new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger); } catch (error) { @@ -130,6 +136,7 @@ export class AccessoryGenerator { this.logs.error(error); } return newAccessory; + } registerOfflineAccessories() { diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index fc22c97..a5f23b2 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -43,6 +43,54 @@ const thunderstruck: IAnimationLoop = { 'durationAtTargetMS': [200, 300], 'chancePercent': 100, }, + { + 'colorStart': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + + }, + 'colorTarget': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + }, + 'transitionTimeMS': 50, + 'durationAtTargetMS': [50, 150], + 'chancePercent': 50, + }, + { + 'colorStart': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + + }, + 'colorTarget': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + }, + 'transitionTimeMS': 30, + 'durationAtTargetMS': [200, 300], + 'chancePercent': 100, + }, + { + 'colorStart': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + + }, + 'colorTarget': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + }, + 'transitionTimeMS': 50, + 'durationAtTargetMS': [50, 150], + 'chancePercent': 50, + }, + { + 'colorStart': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + + }, + 'colorTarget': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + }, + 'transitionTimeMS': 30, + 'durationAtTargetMS': [200, 300], + 'chancePercent': 100, + }, { 'colorStart': { RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, @@ -62,6 +110,36 @@ const thunderstruck: IAnimationLoop = { 'accessoryOffsetMS': 0, }; +const hell: IAnimationLoop = { + + 'name': 'hell', + 'pattern': [ + { + 'colorTarget': { + RGB: { red: [100, 255], green: [0, 25], blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + }, + 'transitionTimeMS': [100, 300], + 'durationAtTargetMS': [0, 5000], + 'chancePercent': 100, + }, + { + 'colorStart': { + RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, + }, + 'colorTarget': { + RGB: { red: [100, 255], green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, + }, + 'transitionTimeMS': 30, + 'durationAtTargetMS': [100, 150], + 'chancePercent': 10, + }, + ], + 'accessories': [ + 'Office Light', + ], + 'accessoryOffsetMS': 0, +}; + import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; @@ -242,8 +320,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { // for (const interval of this.intervals) { this.controller.clearAnimations(); - clearInterval(this.animationInterval); - //} const deviceWriteStatus = this.deviceWriteStatus; @@ -281,10 +357,13 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } protected async prepareCommand(accessoryCommand: IAccessoryCommand, options: ICommandOptions = MEDIUM_COMMAND_OPTIONS) { - // if(accessoryCommand.HSL.saturation < 10){ - // this.animateMe(); + // if (accessoryCommand.HSL.saturation < 5) { + // this.animateMe(thunderstruck); // return; // } + // if(accessoryCommand.HSL.hue < 5 || accessoryCommand.HSL.hue > 355){ + // this.animateMe(hell); + // } const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); this.latestDeviceCommand = deviceCommand; @@ -487,9 +566,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } - protected animateMe() { - this.logs.warn('animating thunderstruck'); - this.controller.animateIndividual(thunderstruck); + protected animateMe(animation) { + this.logs.warn('animating', animation.name); + this.controller.animateIndividual(animation); } } // ZackneticMagichomePlatformAccessory class \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 91df3bb..b6b18f1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,7 @@ "esModuleInterop": true, "strictNullChecks": false, "strict": false, + "downlevelIteration": true }, "include": [ "src/" From d4e010b3f040127d3a040f226dbdc7a1fead8193 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Wed, 3 Aug 2022 00:45:42 -0400 Subject: [PATCH 26/42] Updated Logic --- src/platform.ts | 222 ++++----- src/platformAccessory.ts | 938 +++++++++++++++------------------------ 2 files changed, 476 insertions(+), 684 deletions(-) diff --git a/src/platform.ts b/src/platform.ts index e5b10ea..40cf0a9 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -1,112 +1,112 @@ -import { join } from 'path'; -import { loadJson } from './misc/utils'; -import { cloneDeep } from 'lodash'; -import { Logs } from './logs'; -import { - API, - APIEvent, - DynamicPlatformPlugin, - HAP, - Logging, - PlatformConfig, -} from 'homebridge'; - -import { ControllerGenerator } from 'magichome-platform'; - -import { MagicHomeAccessory } from './misc/types'; -import { AccessoryGenerator } from './AccessoryGenerator'; -import logger from 'node-color-log'; -/** - */ - -const controllerGenerator = new ControllerGenerator(); -let hap: HAP; - -/** - * HomebridgePlatform - * This class is the main constructor for your plugin, this is where you should - * parse the user config and discover/register accessories with Homebridge. - */ -export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { - private log; - private readonly api: API; - // this is used to track restored cached accessories - - - public count = 1; - - private periodicDiscovery: NodeJS.Timeout | null = null; - - public readonly config: PlatformConfig; - public readonly accessoriesFromDiskMap: Map = new Map(); - private readonly hbLogger: Logging; - constructor( - logging: Logging, - config: PlatformConfig, - api: API, - ) { - this.hbLogger = logging; - hap = api.hap; - this.config = config; - this.log = new Logs(logging, config?.globalAccessoryOptions?.logLevel ?? 3); - this.api = api; - //this.logs = getLogger(); - this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); - logger.reverse().log('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); - - // When this event is fired it means Homebridge has restored all cached accessories from disk. - // Dynamic Platform plugins should only register new accessories after this event was fired, - // in order to ensure they weren't added to homebridge already. This event can also be used - // to start discovery of new accessories. - - api.on(APIEvent.DID_FINISH_LAUNCHING, () => { - this.log.debug('Homebridge Magichome Dynamic Platform didFinishLaunching'); - this.initializePlatform(); - }); - } - - - /** - * This function is invoked when homebridge restores cached accessories from disk at startup. - * It should be used to setup event handlers for characteristics and update respective values. - */ - configureAccessory(accessory: MagicHomeAccessory) { - // set cached accessory as not recently seen - // if found later to be a match with a discovered device, will change to true - // accessory.context.scansSinceSeen++; - // accessory.context.pendingRegistration = true; - // // add the restored accessory to the accessories cache so we can track if it has already been registered - - const homebridgeUUID = accessory.UUID; - this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); - this.log.debug(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); - - } - - /** - * Accessories are added by one of three Methods: - * Method One: New devices that were seen after scanning the network and are registered for the first time - * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies - * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user - */ - async initializePlatform() { - // const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; - // const pendingUpdate = new Set(); - // const recentlyRegisteredDevices = new Set(); - - // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - - - const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); - await accesssoryGenerator.generateAccessories(); - this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); - - } - - - // sanitizeConfig() { - // //recursive config sanitation - // } - - +import { join } from 'path'; +import { loadJson } from './misc/utils'; +import { cloneDeep } from 'lodash'; +import { Logs } from './logs'; +import { + API, + APIEvent, + DynamicPlatformPlugin, + HAP, + Logging, + PlatformConfig, +} from 'homebridge'; + +import { ControllerGenerator } from 'magichome-platform'; + +import { MagicHomeAccessory } from './misc/types'; +import { AccessoryGenerator } from './AccessoryGenerator'; +import logger from 'node-color-log'; +/** + */ + +const controllerGenerator = new ControllerGenerator(); +let hap: HAP; + +/** + * HomebridgePlatform + * This class is the main constructor for your plugin, this is where you should + * parse the user config and discover/register accessories with Homebridge. + */ +export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { + private log; + private readonly api: API; + // this is used to track restored cached accessories + + + public count = 1; + + private periodicDiscovery: NodeJS.Timeout | null = null; + + public readonly config: PlatformConfig; + public readonly accessoriesFromDiskMap: Map = new Map(); + private readonly hbLogger: Logging; + constructor( + logging: Logging, + config: PlatformConfig, + api: API, + ) { + this.hbLogger = logging; + hap = api.hap; + this.config = config; + this.log = new Logs(logging, config?.globalAccessoryOptions?.logLevel ?? 3); + this.api = api; + //this.logs = getLogger(); + this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); + logger.reverse().log('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); + + // When this event is fired it means Homebridge has restored all cached accessories from disk. + // Dynamic Platform plugins should only register new accessories after this event was fired, + // in order to ensure they weren't added to homebridge already. This event can also be used + // to start discovery of new accessories. + + api.on(APIEvent.DID_FINISH_LAUNCHING, () => { + this.log.debug('Homebridge Magichome Dynamic Platform didFinishLaunching'); + this.initializePlatform(); + }); + } + + + /** + * This function is invoked when homebridge restores cached accessories from disk at startup. + * It should be used to setup event handlers for characteristics and update respective values. + */ + configureAccessory(accessory: MagicHomeAccessory) { + // set cached accessory as not recently seen + // if found later to be a match with a discovered device, will change to true + // accessory.context.scansSinceSeen++; + // accessory.context.pendingRegistration = true; + // // add the restored accessory to the accessories cache so we can track if it has already been registered + + const homebridgeUUID = accessory.UUID; + this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); + this.log.debug(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); + + } + + /** + * Accessories are added by one of three Methods: + * Method One: New devices that were seen after scanning the network and are registered for the first time + * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies + * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user + */ + async initializePlatform() { + // const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; + // const pendingUpdate = new Set(); + // const recentlyRegisteredDevices = new Set(); + + // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; + + + const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); + await accesssoryGenerator.discoverDevices(); + this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); + + } + + + // sanitizeConfig() { + // //recursive config sanitation + // } + + }//ZackneticMagichomePlatform class \ No newline at end of file diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index a5f23b2..c16de81 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -1,574 +1,366 @@ -import type { - API, Service, PlatformConfig, CharacteristicValue, - CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, -} from 'homebridge'; - -const thunderstruck: IAnimationLoop = { - - 'name': 'ThunderStruck', - 'pattern': [ - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - - }, - 'colorTarget': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - }, - 'transitionTimeMS': 1000, - 'durationAtTargetMS': [10000, 30000], - 'chancePercent': 100, - }, - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - - }, - 'colorTarget': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - }, - 'transitionTimeMS': 50, - 'durationAtTargetMS': [50, 150], - 'chancePercent': 50, - }, - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - - }, - 'colorTarget': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - }, - 'transitionTimeMS': 30, - 'durationAtTargetMS': [200, 300], - 'chancePercent': 100, - }, - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - - }, - 'colorTarget': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - }, - 'transitionTimeMS': 50, - 'durationAtTargetMS': [50, 150], - 'chancePercent': 50, - }, - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - - }, - 'colorTarget': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - }, - 'transitionTimeMS': 30, - 'durationAtTargetMS': [200, 300], - 'chancePercent': 100, - }, - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - - }, - 'colorTarget': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - }, - 'transitionTimeMS': 50, - 'durationAtTargetMS': [50, 150], - 'chancePercent': 50, - }, - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - - }, - 'colorTarget': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - }, - 'transitionTimeMS': 30, - 'durationAtTargetMS': [200, 300], - 'chancePercent': 100, - }, - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - - }, - 'colorTarget': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - }, - 'transitionTimeMS': 30, - 'durationAtTargetMS': [50, 300], - 'chancePercent': 100, - }, - ], - 'accessories': [ - 'Office Light', - ], - 'accessoryOffsetMS': 0, -}; - -const hell: IAnimationLoop = { - - 'name': 'hell', - 'pattern': [ - { - 'colorTarget': { - RGB: { red: [100, 255], green: [0, 25], blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - }, - 'transitionTimeMS': [100, 300], - 'durationAtTargetMS': [0, 5000], - 'chancePercent': 100, - }, - { - 'colorStart': { - RGB: { red: 0, green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 255 }, - }, - 'colorTarget': { - RGB: { red: [100, 255], green: 0, blue: 0 }, CCT: { warmWhite: 0, coldWhite: 0 }, - }, - 'transitionTimeMS': 30, - 'durationAtTargetMS': [100, 150], - 'chancePercent': 10, - }, - ], - 'accessories': [ - 'Office Light', - ], - 'accessoryOffsetMS': 0, -}; - -import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; -import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; -import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, DeviceWriteStatus as DeviceStatus, IProtoDevice, IAnimationLoop } from 'magichome-platform'; -import { _ } from 'lodash'; -import Queue from 'queue-promise'; -import { Logs } from './logs'; - -const { ready, pending, busy } = DeviceStatus; - -const CCT = 'CCT'; -const HSL = 'HSL'; -const BUFFER_MS = 0; -const FINAL_COMMAND_TIMEOUT = 100; -const QUEUE_INTERVAL = 150; - -const SLOW_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 20, bufferMS: 0, timeoutMS: 2000 }; -const MEDIUM_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 20, bufferMS: 0, timeoutMS: 1000 }; -const FAST_COMMAND_OPTIONS: ICommandOptions = { maxRetries: 0, bufferMS: 0, timeoutMS: 20 }; - -/** - * 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 HomebridgeMagichomeDynamicPlatformAccessory { - - protected service: Service; - protected readonly hap: HAP; - - protected adaptiveLightingService; - protected animationInterval; - protected interruptInterval; - protected intervals; - - protected newAccessoryCommand: IAccessoryCommand; - protected latestDeviceCommand: IDeviceCommand; - protected latestAccessoryCommand: IAccessoryCommand; - - protected ColorCommandMode = HSL; - protected logs; - - protected colorWhiteSimultaniousSaturationLevel; - protected colorOffSaturationLevel; - protected simultaniousDevicesColorWhite; - - protected deviceWriteStatus = ready; - protected deviceReadStatus = ready; - protected readRequestLevel = 0; - - protected queue; - protected slowQueueRetry = false; - latestDeviceState: IDeviceState; - - //================================================= - // Start Constructor // - - constructor( - protected readonly api: API, - protected readonly accessory: MagicHomeAccessory, - public readonly config: PlatformConfig, - protected readonly controller: BaseController, - protected readonly hbLogger: Logging, - ) { - - this.setupMisc(); - - this.controller = controller; - this.hap = api.hap; - this.api = api; - this.config = config; - this.setupCommandQueue(); - this.initializeCharacteristics(); - this.fetchAndUpdateState(2); - } - - //================================================= - // End Constructor // - - //================================================= - // Start Setters // - async setOn(value: CharacteristicValue) { - const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; - this.processAccessoryCommand(accessoryCommand); - } - - setHue(value: CharacteristicValue) { - this.accessory.context.accessoryState.HSL.hue = value as number; - this.ColorCommandMode = HSL; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; - this.processAccessoryCommand(accessoryCommand); - } - - setSaturation(value: CharacteristicValue) { - - this.accessory.context.accessoryState.HSL.saturation = value as number; - - this.ColorCommandMode = HSL; - - const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { saturation: value as number } }; - this.processAccessoryCommand(accessoryCommand); - } - - async setBrightness(value: CharacteristicValue) { - - - this.accessory.context.accessoryState.brightness = value as number; - const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; - this.processAccessoryCommand(accessoryCommand); - } - - setColorTemperature(value: CharacteristicValue) { - - this.ColorCommandMode = CCT; - const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; - this.processAccessoryCommand(accessoryCommand); - } - - setConfiguredName(value: CharacteristicValue) { - - const name: string = value.toString(); - this.logs.warn('Renaming device to %o', name); - this.accessory.context.displayName = name; - this.api.updatePlatformAccessories([this.accessory]); - } - - identifyLight() { - - this.flashEffect(); - } - - //================================================= - // End Setters // - - //================================================= - // Start Getters // - - getHue() { - - const hue = this.accessory.context.accessoryState.HSL.hue; - this.fetchAndUpdateState(2); - return hue; - - } - - getColorTemperature() { - - const colorTemperature = this.accessory.context.accessoryState.colorTemperature; - this.fetchAndUpdateState(3); - return colorTemperature; - } - - getBrightness() { - const brightness = this.accessory.context.accessoryState.brightness; - this.fetchAndUpdateState(2); - return brightness; - } - - /** - ** @getOn - * instantly retrieve the current on/off state stored in our object - * next call this.getState() which will update all values asynchronously as they are ready - */ - async getOn() { - const isOn = this.accessory.context.accessoryState.isOn; - this.fetchAndUpdateState(2); - return isOn; - } - - flashEffect() { - // - } //flashEffect - - //================================================= - // End LightEffects // - - - protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { - // for (const interval of this.intervals) { - this.controller.clearAnimations(); - //} - - const deviceWriteStatus = this.deviceWriteStatus; - switch (deviceWriteStatus) { - case ready: - - this.deviceWriteStatus = pending; - await this.writeStateToDevice(accessoryCommand).then((msg) => { - //error logging - }).finally(() => { - this.deviceWriteStatus = ready; - }); - break; - - case pending: - _.merge(this.newAccessoryCommand, accessoryCommand); - break; - } - } - - protected async writeStateToDevice(accessoryCommand: IAccessoryCommand): Promise { - this.newAccessoryCommand = accessoryCommand; - return new Promise((resolve, reject) => { - return setTimeout(() => { - this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessory.context.accessoryState, '\n Received Command', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = _.merge({}, this.accessory.context.accessoryState, this.newAccessoryCommand); - - // eslint-disable-next-line no-prototype-builtins - if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { - sanitizedAcessoryCommand.isPowerCommand = true; - } - resolve(this.prepareCommand(sanitizedAcessoryCommand)); - }, BUFFER_MS); - }); - } - - protected async prepareCommand(accessoryCommand: IAccessoryCommand, options: ICommandOptions = MEDIUM_COMMAND_OPTIONS) { - // if (accessoryCommand.HSL.saturation < 5) { - // this.animateMe(thunderstruck); - // return; - // } - // if(accessoryCommand.HSL.hue < 5 || accessoryCommand.HSL.hue > 355){ - // this.animateMe(hell); - // } - const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); - this.latestDeviceCommand = deviceCommand; - this.latestAccessoryCommand = accessoryCommand; - - this.queue.enqueue(async () => { - - if (this.queue.size > 0) { - this.slowQueueRetry = true; - options = FAST_COMMAND_OPTIONS; - } - - if (!(this.slowQueueRetry && this.queue.size < 1)) { - let response; - if (!accessoryCommand.isPowerCommand) { - response = await this.controller.setAllValues(deviceCommand, options); - } else { - response = await this.controller.setOn(deviceCommand.isOn, options); - } - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); - } - - }); - } - - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - - const RGB = convertHSLtoRGB(HSL); - RGB.red = Math.round((RGB.red / 100) * brightness); - RGB.green = Math.round((RGB.green / 100) * brightness); - RGB.blue = Math.round((RGB.blue / 100) * brightness); - - const deviceCommand: IDeviceCommand = { isOn, RGB }; - return deviceCommand; - } - - protected async updateLocalState(requestLevel, deviceState) { - if (!deviceState) { - deviceState = await this.controller?.fetchState() ?? this.accessory.context.cachedDeviceInformation.deviceState; - } - this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); - this.accessory.context.cachedDeviceInformation.deviceState = deviceState; - const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); - let accessoryState: IAccessoryState; - if (deviceState) { - switch (requestLevel) { - case 0: - accessoryState = { HSL: { luminance }, isOn }; - break; - case 1: - accessoryState = { HSL: { hue, luminance }, isOn }; - break; - case 2: - accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; - break; - case 3: - accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; - break; - } - _.merge(this.accessory.context.accessoryState, accessoryState); - - this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, this.accessory.context.accessoryState); - } else { - _.merge(this.accessory.context.accessoryState, { isOn: false }); - } - } - - updateHomekitState() { - this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessory.context.accessoryState.isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessory.context.accessoryState.HSL.hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessory.context.accessoryState.HSL.saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessory.context.accessoryState.brightness); - } - - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - - const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; - // eslint-disable-next-line prefer-const - let { hue, saturation, luminance } = convertRGBtoHSL(RGB); - let brightness = 0; - - if (luminance > 0 && isOn) { - brightness = luminance * 2; - } else if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - if (warmWhite > coldWhite) { - saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); - } else { - saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); - } - } - - const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; - return accessoryState; - } - - setupCommandQueue() { - let deviceState; - this.queue = new Queue({ - concurrent: 1, - interval: QUEUE_INTERVAL, - }); - - let timeout; - - this.queue.on('start', () => { - clearTimeout(timeout); - }); - - this.queue.on('end', async () => { - - if (!_.isEqual(_.omit(this.latestDeviceState?.LEDState ?? {}, ['colorMask']), _.omit(this.latestDeviceCommand, ['colorMask']))) { - if (this.slowQueueRetry) { - timeout = setTimeout(async () => { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Sending a slow write command to increase chance of success:\n`, this.latestDeviceCommand); - this.slowQueueRetry = false; - await this.prepareCommand(this.latestAccessoryCommand, SLOW_COMMAND_OPTIONS); - this.fetchAndUpdateState(2); - - }, FINAL_COMMAND_TIMEOUT); - } - deviceState = null; - } - }); - - this.queue.on('resolve', _deviceState => { - deviceState = _deviceState; - }); - this.queue.on('reject', error => { - this.logs.error(error); - }); - } - - initializeCharacteristics() { - - let cachedDeviceInformation = this.controller?.getCachedDeviceInformation(); - if (cachedDeviceInformation) { - this.accessory.context.cachedDeviceInformation = cachedDeviceInformation; - } else { - cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; - } - - const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; - - addAccessoryInformationCharacteristic(this); - - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); - this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); - - if (hasColor) { - addHueCharacteristic(this); - addSaturationCharacteristic(this); - } - - if (hasBrightness) { - addBrightnessCharacteristic(this); - } - - if (hasCCT) { - addColorTemperatureCharacteristic(this); - } - - if (!hasBrightness) { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Switch service to accessory.`); //device is switch, register it as such - this.service = this.accessory.getService(this.hap.Service.Switch) ?? this.accessory.addService(this.hap.Service.Switch); - } - addOnCharacteristic(this); - addConfiguredNameCharacteristic(this); - } - - setupMisc() { - this.accessory.context.accessoryState = this.accessory.context.accessoryState ?? DefaultAccessoryCommand; - - const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName); - const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = _.merge({}, this.config.globalAccessoryOptions, localAccessoryOptions); - - - this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; - this.colorOffSaturationLevel = colorOffSaturationLevel; - this.logs = new Logs(this.hbLogger, logLevel ?? 3); - - } - - async fetchAndUpdateState(requestLevel) { - switch (this.deviceReadStatus) { - case ready: - this.deviceReadStatus = pending; - this.readRequestLevel = requestLevel; - setTimeout(async () => { - await this.updateLocalState(this.readRequestLevel, null); - this.updateHomekitState(); - this.deviceReadStatus = ready; - }, BUFFER_MS); - break; - case pending: - this.readRequestLevel = Math.max(requestLevel, this.readRequestLevel); - break; - } - - } - - protected animateMe(animation) { - this.logs.warn('animating', animation.name); - this.controller.animateIndividual(animation); - } - +import type { + API, Service, PlatformConfig, CharacteristicValue, + CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, +} from 'homebridge'; + +import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; +import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; +import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop } from 'magichome-platform'; + +import { Logs } from './logs'; + +const CCT = 'CCT'; +const HSL = 'HSL'; +const BUFFER_MS = 0; +const FINAL_COMMAND_TIMEOUT = 100; +const QUEUE_INTERVAL = 150; + +/** + * 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 HomebridgeMagichomeDynamicPlatformAccessory { + + protected service: Service; + protected readonly hap: HAP; + + protected adaptiveLightingService; + protected newAccessoryCommand: IAccessoryCommand; + protected latestDeviceCommand: IDeviceCommand; + protected latestAccessoryCommand: IAccessoryCommand; + + protected ColorCommandMode = HSL; + protected logs; + + protected colorWhiteSimultaniousSaturationLevel; + protected colorOffSaturationLevel; + protected simultaniousDevicesColorWhite; + + protected deviceWriteStatus = 'ready'; + protected deviceReadStatus = 'ready'; + protected readRequestLevel = 0; + + protected queue; + protected slowQueueRetry = false; + latestDeviceState: IDeviceState; + + //================================================= + // Start Constructor // + + constructor( + protected readonly api: API, + protected readonly accessory: MagicHomeAccessory, + public readonly config: PlatformConfig, + protected readonly controller: BaseController, + protected readonly hbLogger: Logging, + ) { + + this.setupMisc(); + + this.controller = controller; + this.hap = api.hap; + this.api = api; + this.config = config; + this.initializeCharacteristics(); + this.fetchAndUpdateState(2); + } + + //================================================= + // End Constructor // + + //================================================= + // Start Setters // + async setOn(value: CharacteristicValue) { + const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; + this.processAccessoryCommand(accessoryCommand); + } + + setHue(value: CharacteristicValue) { + this.accessory.context.accessoryState.HSL.hue = value as number; + this.ColorCommandMode = HSL; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; + this.processAccessoryCommand(accessoryCommand); + } + + setSaturation(value: CharacteristicValue) { + + this.accessory.context.accessoryState.HSL.saturation = value as number; + + this.ColorCommandMode = HSL; + + const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { saturation: value as number } }; + this.processAccessoryCommand(accessoryCommand); + } + + async setBrightness(value: CharacteristicValue) { + + + this.accessory.context.accessoryState.brightness = value as number; + const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; + this.processAccessoryCommand(accessoryCommand); + } + + setColorTemperature(value: CharacteristicValue) { + + this.ColorCommandMode = CCT; + const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; + this.processAccessoryCommand(accessoryCommand); + } + + setConfiguredName(value: CharacteristicValue) { + + const name: string = value.toString(); + this.logs.warn('Renaming device to %o', name); + this.accessory.context.displayName = name; + this.api.updatePlatformAccessories([this.accessory]); + } + + identifyLight() { + + this.flashEffect(); + } + + //================================================= + // End Setters // + + //================================================= + // Start Getters // + + getHue() { + + const hue = this.accessory.context.accessoryState.HSL.hue; + this.fetchAndUpdateState(2); + return hue; + + } + + getColorTemperature() { + + const colorTemperature = this.accessory.context.accessoryState.colorTemperature; + this.fetchAndUpdateState(3); + return colorTemperature; + } + + getBrightness() { + const brightness = this.accessory.context.accessoryState.brightness; + this.fetchAndUpdateState(2); + return brightness; + } + + /** + ** @getOn + * instantly retrieve the current on/off state stored in our object + * next call this.getState() which will update all values asynchronously as they are ready + */ + async getOn() { + const isOn = this.accessory.context.accessoryState.isOn; + this.fetchAndUpdateState(2); + return isOn; + } + + flashEffect() { + // + } //flashEffect + + //================================================= + // End LightEffects // + + + protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { + // for (const interval of this.intervals) { + // this.controller.clearAnimations(); + //} + + const deviceWriteStatus = this.deviceWriteStatus; + switch (deviceWriteStatus) { + case 'ready': + + this.deviceWriteStatus = 'pending'; + await this.writeStateToDevice(accessoryCommand).then((msg) => { + //error logging + }).finally(() => { + this.deviceWriteStatus = 'ready'; + }); + break; + + case pending: + _.merge(this.newAccessoryCommand, accessoryCommand); + break; + } + } + + protected async writeStateToDevice(accessoryCommand: IAccessoryCommand): Promise { + this.newAccessoryCommand = accessoryCommand; + return new Promise((resolve, reject) => { + return setTimeout(() => { + this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessory.context.accessoryState, '\n Received Command', this.newAccessoryCommand); + const sanitizedAcessoryCommand: IAccessoryCommand = _.merge({}, this.accessory.context.accessoryState, this.newAccessoryCommand); + + // eslint-disable-next-line no-prototype-builtins + if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { + sanitizedAcessoryCommand.isPowerCommand = true; + } + resolve(this.prepareCommand(sanitizedAcessoryCommand)); + }, BUFFER_MS); + }); + } + + protected async prepareCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions) { + const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); + + let response; + if (!accessoryCommand.isPowerCommand) { + response = await this.controller.setAllValues(deviceCommand, commandOptions); + } else { + response = await this.controller.setOn(deviceCommand.isOn, commandOptions); + } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); + } + + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + + const RGB = convertHSLtoRGB(HSL); + RGB.red = Math.round((RGB.red / 100) * brightness); + RGB.green = Math.round((RGB.green / 100) * brightness); + RGB.blue = Math.round((RGB.blue / 100) * brightness); + + const deviceCommand: IDeviceCommand = { isOn, RGB }; + return deviceCommand; + } + + protected async updateLocalState(requestLevel, deviceState) { + if (!deviceState) { + deviceState = await this.controller?.fetchState() ?? this.accessory.context.cachedDeviceInformation.deviceState; + } + this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); + this.accessory.context.cachedDeviceInformation.deviceState = deviceState; + const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); + let accessoryState: IAccessoryState; + if (deviceState) { + switch (requestLevel) { + case 0: + accessoryState = { HSL: { luminance }, isOn }; + break; + case 1: + accessoryState = { HSL: { hue, luminance }, isOn }; + break; + case 2: + accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; + break; + case 3: + accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; + break; + } + _.merge(this.accessory.context.accessoryState, accessoryState); + + this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, this.accessory.context.accessoryState); + } else { + _.merge(this.accessory.context.accessoryState, { isOn: false }); + } + } + + updateHomekitState() { + this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessory.context.accessoryState.isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessory.context.accessoryState.HSL.hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessory.context.accessoryState.HSL.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessory.context.accessoryState.brightness); + } + + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + // eslint-disable-next-line prefer-const + let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let brightness = 0; + + if (luminance > 0 && isOn) { + brightness = luminance * 2; + } else if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + if (warmWhite > coldWhite) { + saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); + } else { + saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); + } + } + + const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; + return accessoryState; + } + + initializeCharacteristics() { + + let cachedDeviceInformation = this.controller?.getCachedDeviceInformation(); + if (cachedDeviceInformation) { + this.accessory.context.cachedDeviceInformation = cachedDeviceInformation; + } else { + cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; + } + + const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; + + addAccessoryInformationCharacteristic(this); + + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); + this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); + + if (hasColor) { + addHueCharacteristic(this); + addSaturationCharacteristic(this); + } + + if (hasBrightness) { + addBrightnessCharacteristic(this); + } + + if (hasCCT) { + addColorTemperatureCharacteristic(this); + } + + if (!hasBrightness) { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Switch service to accessory.`); //device is switch, register it as such + this.service = this.accessory.getService(this.hap.Service.Switch) ?? this.accessory.addService(this.hap.Service.Switch); + } + addOnCharacteristic(this); + addConfiguredNameCharacteristic(this); + } + + setupMisc() { + this.accessory.context.accessoryState = this.accessory.context.accessoryState ?? DefaultAccessoryCommand; + + const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName); + const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = _.merge({}, this.config.globalAccessoryOptions, localAccessoryOptions); + + + this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; + this.colorOffSaturationLevel = colorOffSaturationLevel; + this.logs = new Logs(this.hbLogger, logLevel ?? 3); + + } + + async fetchAndUpdateState(requestLevel) { + switch (this.deviceReadStatus) { + case ready: + this.deviceReadStatus = pending; + this.readRequestLevel = requestLevel; + await this.updateLocalState(this.readRequestLevel, null); + this.updateHomekitState(); + this.deviceReadStatus = ready; + break; + case pending: + this.readRequestLevel = Math.max(requestLevel, this.readRequestLevel); + break; + } + } + + getController() { + return this.controller; + } + + + } // ZackneticMagichomePlatformAccessory class \ No newline at end of file From 046475468c01a9e3572611794c4486afa4346079 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Thu, 4 Aug 2022 23:18:50 -0400 Subject: [PATCH 27/42] continued discovery rework --- .homebridge-dev/config.json | 2 +- package-lock.json | 4395 ++++++++++++---------------- package.json | 20 +- src/AccessoryGenerator.ts | 230 +- src/accessories/GRBStrip.ts | 6 +- src/accessories/RGBWBulb.ts | 6 +- src/accessories/RGBWStrip.ts | 6 +- src/accessories/RGBWWBulb.ts | 4 +- src/accessories/RGBWWStrip.ts | 8 +- src/accessories/Switch.ts | 10 +- src/misc/serviceCharacteristics.ts | 12 +- src/misc/types.ts | 15 +- src/misc/utils.ts | 6 +- src/platform.ts | 6 +- src/platformAccessory.ts | 171 +- 15 files changed, 2054 insertions(+), 2843 deletions(-) diff --git a/.homebridge-dev/config.json b/.homebridge-dev/config.json index c522a73..321799d 100644 --- a/.homebridge-dev/config.json +++ b/.homebridge-dev/config.json @@ -1,7 +1,7 @@ { "bridge": { "name": "HomebridgeDev", - "username": "CC:BB:DD:DD:FF:FF", + "username": "CC:BB:DD:DD:FF:GG", "manufacturer": "homebridge.io", "model": "homebridge", "port": 51826, diff --git a/package-lock.json b/package-lock.json index 410b9da..730acc1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,132 +21,88 @@ "dependencies": { "color-convert": "^2.0.1", "homebridge-lib": "^5.1.14", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "node-color-log": "^6.0.0", - "promise-queue": "^2.2.5", - "queue-promise": "^2.2.1" + "magichome-platform": "^0.0.18" }, "devDependencies": { - "@types/node": "^14.17.19", - "@types/promise-queue": "^2.2.0", - "@typescript-eslint/eslint-plugin": "^3.10.1", - "@typescript-eslint/parser": "^3.10.1", - "eslint": "^7.32.0", - "homebridge": "^1.3.4", + "@types/node": "^16.10.9", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^8.0.1", + "homebridge": "^1.3.9", "nodemon": "^2.0.13", "rimraf": "^3.0.2", - "ts-node": "^8.10.2", - "typescript": "^3.9.10" + "ts-node": "^10.3.0" }, "engines": { "homebridge": ">=1.0.0", "node": ">=10.17.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" + "node": ">=12" } }, "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, "dependencies": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@homebridge/ciao": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.2.tgz", - "integrity": "sha512-31IfDKMqxfT+uVNXj0/TmYMou57gP8CUrh0vABzsc5QMsoCQ4Oo5uYQp0oJJyzxTBkF2pFvjR3XlWAapl0VyCg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", + "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", "dev": true, "dependencies": { - "debug": "^4.3.1", + "debug": "^4.3.4", "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.19", - "tslib": "^2.0.3" + "source-map-support": "^0.5.21", + "tslib": "^2.4.0" }, "bin": { "ciao-bcs": "lib/bonjour-conformance-testing.js" } }, "node_modules/@homebridge/ciao/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, + "node_modules/@homebridge/plugin-ui-utils": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", + "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", + "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.4" }, @@ -154,85 +110,149 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", - "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "defer-to-connect": "^1.0.1" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", "dev": true }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true }, - "node_modules/@types/node": { - "version": "14.17.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.19.tgz", - "integrity": "sha512-jjYI6NkyfXykucU6ELEoT64QyKOdvaA6enOqKtP4xUsGY0X0ZUZz29fUmrTRo+7v7c6TgDu82q3GHHaCEkqZwA==", + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true }, - "node_modules/@types/promise-queue": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/promise-queue/-/promise-queue-2.2.0.tgz", - "integrity": "sha512-9QLtid6GxEWqpF+QImxBRG6bSVOHtpAm2kXuIyEvZBbSOupLvqhhJv8uaHbS8kUL8FDjzH3RWcSyC/52WOVtGw==", + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "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": "16.11.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.47.tgz", + "integrity": "sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.10.1.tgz", - "integrity": "sha512-PQg0emRtzZFWq6PxBcdxRH3QIQiyFO3WCVpRL3fgj5oQS3CDs3AeAKfv4DxNhzn8ITdNJGJ4D3Qw8eAJf3lXeQ==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.32.0.tgz", + "integrity": "sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew==", "dev": true, "dependencies": { - "@typescript-eslint/experimental-utils": "3.10.1", - "debug": "^4.1.1", + "@typescript-eslint/scope-manager": "5.32.0", + "@typescript-eslint/type-utils": "5.32.0", + "@typescript-eslint/utils": "5.32.0", + "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^3.0.0", - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -240,50 +260,69 @@ } } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz", - "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==", + "node_modules/@typescript-eslint/parser": { + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.32.0.tgz", + "integrity": "sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/types": "3.10.1", - "@typescript-eslint/typescript-estree": "3.10.1", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "@typescript-eslint/scope-manager": "5.32.0", + "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/typescript-estree": "5.32.0", + "debug": "^4.3.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@typescript-eslint/parser": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.10.1.tgz", - "integrity": "sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz", + "integrity": "sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg==", "dev": true, "dependencies": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "3.10.1", - "@typescript-eslint/types": "3.10.1", - "@typescript-eslint/typescript-estree": "3.10.1", - "eslint-visitor-keys": "^1.1.0" + "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/visitor-keys": "5.32.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.32.0.tgz", + "integrity": "sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.32.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + "eslint": "*" }, "peerDependenciesMeta": { "typescript": { @@ -292,12 +331,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz", - "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz", + "integrity": "sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ==", "dev": true, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -305,22 +344,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz", - "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz", + "integrity": "sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "3.10.1", - "@typescript-eslint/visitor-keys": "3.10.1", - "debug": "^4.1.1", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/visitor-keys": "5.32.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -332,16 +370,41 @@ } } }, + "node_modules/@typescript-eslint/utils": { + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz", + "integrity": "sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.32.0", + "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/typescript-estree": "5.32.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz", - "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz", + "integrity": "sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "@typescript-eslint/types": "5.32.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", @@ -355,9 +418,9 @@ "dev": true }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -375,6 +438,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -391,24 +463,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -419,32 +473,19 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-styles/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansi-styles/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, "node_modules/anymatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", @@ -465,37 +506,25 @@ "dev": true }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -508,9 +537,9 @@ } }, "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "node_modules/binary-extensions": { @@ -534,28 +563,6 @@ "multicast-dns-service-types": "^1.1.0" } }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -579,53 +586,11 @@ } }, "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -647,18 +612,6 @@ "node": ">=6" } }, - "node_modules/camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -674,44 +627,17 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -728,31 +654,16 @@ "fsevents": "~2.3.2" } }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { - "mimic-response": "^1.0.0" + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/color-convert": { @@ -783,25 +694,14 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -817,19 +717,10 @@ "node": ">= 8" } }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -843,18 +734,6 @@ } } }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/deep-equal": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", @@ -880,38 +759,33 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dependencies": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dgram": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dgram/-/dgram-1.0.1.tgz", + "integrity": "sha512-zJVFL1EWfKtE0z2VN6qfpn/a+qG1viEzcwJA0EjtzS76ONSE3sEyWBwEbo32hS4IFw/EWVuWN+8b89aPW6It2A==", + "deprecated": "npm is holding this package for security reasons. As it's a core Node module, we will not transfer it over to other users. You may safely remove the package from your dependencies." + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -921,10 +795,22 @@ "node": ">=0.3.1" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dns-packet": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.0.tgz", - "integrity": "sha512-Nce7YLu6YCgWRvOmDBsJMo9M5/jV3lEZ5vUWnWXYmwURvPylHvq7nkDWhNmk1ZQoZZOP7oQh/S0lSxbisKOfHg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -944,74 +830,39 @@ "node": ">=6.0.0" } }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" }, "node_modules/es-abstract": { - "version": "1.18.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", - "integrity": "sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "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.2", "is-string": "^1.0.7", - "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", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -1054,15 +905,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1076,49 +918,48 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", + "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", "dev": true, "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.3", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -1126,7 +967,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1146,30 +987,24 @@ } }, "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "engines": { - "node": ">=6" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" } }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", @@ -1178,31 +1013,52 @@ "node": ">=10" } }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", + "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { @@ -1218,9 +1074,9 @@ } }, "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -1239,9 +1095,9 @@ } }, "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { "node": ">=4.0" @@ -1262,15 +1118,43 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1280,18 +1164,27 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/fast-srp-hap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.3.tgz", - "integrity": "sha512-4P8TBD0all202L9FbeSsWc9qDlpaYp065VbUwbuNYZDYdOJ02UlWaDkai6d/+6/I8/sdtVYAVd17PEZDKbqopQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", + "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", "dev": true, "engines": { "node": ">=10.17.0" } }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -1316,6 +1209,22 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -1330,35 +1239,37 @@ } }, "node_modules/flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", "dev": true }, - "node_modules/foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } }, "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "dependencies": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { @@ -1380,46 +1291,59 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/futoin-hkdf": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.3.3.tgz", - "integrity": "sha512-oR75fYk3B3X9/B02Y6vusrBKucrpC6VjxhRL+C6B7FwUpuSRHbhBNG3AZbcE/xPyJmEQWsyqUFp3VeNNbA3S7A==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", + "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -1436,15 +1360,15 @@ } }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -1456,36 +1380,21 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "ini": "2.0.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10.13.0" } }, "node_modules/globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1497,49 +1406,53 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" }, "engines": { - "node": ">=8.6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, "node_modules/hap-nodejs": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.9.4.tgz", - "integrity": "sha512-wGYq6nQ8c5+V7iLr9Fa7XpOGAntmB0ejfOsjoIhXe/WHOXX9gGDwYgQTHg+dwmJZjW7RBoOyRRdB7/oa/NYovw==", + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.9.8.tgz", + "integrity": "sha512-+IENi8nFh/yOvVZEEIgY+nVppoXgY3mN8CfRh/I9tlhDbp3rXlsjdvHFVOgk7qJNa6cwzKu0KzNUs+n3XpO1Iw==", "dev": true, "dependencies": { - "@homebridge/ciao": "~1.1.2", - "bonjour-hap": "~3.6.2", - "debug": "^4.3.1", - "fast-srp-hap": "2.0.3", - "futoin-hkdf": "~1.3.2", - "ip": "^1.1.3", + "@homebridge/ciao": "~1.1.3", + "bonjour-hap": "~3.6.3", + "debug": "^4.3.2", + "fast-srp-hap": "2.0.4", + "futoin-hkdf": "~1.4.2", + "ip": "^1.1.5", "node-persist": "^0.0.11", - "source-map-support": "^0.5.19", - "tslib": "^2.1.0", + "source-map-support": "^0.5.20", + "tslib": "^2.3.1", "tweetnacl": "^1.0.3" }, "engines": { @@ -1547,9 +1460,9 @@ } }, "node_modules/hap-nodejs/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, "node_modules/has": { @@ -1564,26 +1477,36 @@ } }, "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "engines": { - "node": ">=4" + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { "node": ">= 0.4" }, @@ -1605,28 +1528,19 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/homebridge": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.3.4.tgz", - "integrity": "sha512-I2vxabWpKHly3htXvOgnJbO79pXzrorz6/htRUCD3UTWXnzURqUFhevv9c/Mji3YeKxluIXCyXyiGAuDfx1m3A==", + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.3.9.tgz", + "integrity": "sha512-/QYosrEmxao6EekPMU3la3j3qx0UWLcYQN01qbZ7s1ZrKp8aC+aShgNx1borFrY/0fHsZauGcbuNqFh+XSKNXw==", "dev": true, "dependencies": { - "chalk": "^4.1.0", + "chalk": "^4.1.2", "commander": "5.1.0", - "fs-extra": "^9.1.0", - "hap-nodejs": "0.9.4", + "fs-extra": "^10.0.0", + "hap-nodejs": "0.9.8", "qrcode-terminal": "^0.12.0", - "semver": "^7.3.4", - "source-map-support": "^0.5.19" + "semver": "^7.3.5", + "source-map-support": "^0.5.20" }, "bin": { "homebridge": "bin/homebridge" @@ -1636,34 +1550,30 @@ } }, "node_modules/homebridge-lib": { - "version": "5.1.14", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.1.14.tgz", - "integrity": "sha512-ZtGssTd9uoKv169ChDoiMmCLdzHGtHtlAJ7zM8JM9u8Sxgm/X8LtoV+OB78m9TuHEuvmv5wdJqguYYSFycclgw==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.3.tgz", + "integrity": "sha512-7X84aSayZd7YjboxoFsZ78ExfoRlZmo0t3Hasu4PL0XCILu6dqAG3Zzhqtsg/wqYTfqavvOleRInTMmFEGz6ew==", "dependencies": { + "@homebridge/plugin-ui-utils": "~0.0.19", "bonjour-hap": "^3.6.3", "chalk": "^4.1.2", - "semver": "^7.3.5" + "semver": "^7.3.7" }, "bin": { "hap": "cli/hap.js", "json": "cli/json.js", + "sysinfo": "cli/sysinfo.js", "upnp": "cli/upnp.js" }, "engines": { - "homebridge": "^1.3.4", - "node": "^14.18.0" + "homebridge": "^1.5.0", + "node": "^16.16.0" } }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, "engines": { "node": ">= 4" @@ -1672,7 +1582,7 @@ "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, "node_modules/import-fresh": { @@ -1691,19 +1601,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "engines": { "node": ">=0.8.19" @@ -1712,7 +1613,7 @@ "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -1725,15 +1626,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -1748,9 +1640,9 @@ } }, "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" }, "node_modules/is-arguments": { "version": "1.1.1", @@ -1816,18 +1708,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -1845,25 +1725,16 @@ "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" @@ -1872,22 +1743,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -1897,9 +1752,9 @@ } }, "node_modules/is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "engines": { "node": ">= 0.4" }, @@ -1907,18 +1762,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1929,9 +1772,9 @@ } }, "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -1942,24 +1785,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -1983,6 +1808,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -2012,14 +1848,14 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0" }, "engines": { @@ -2029,12 +1865,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "node_modules/is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -2043,19 +1873,28 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-weakset": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", - "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==", + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/isarray": { "version": "2.0.5", @@ -2065,34 +1904,21 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2102,7 +1928,7 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "node_modules/jsonfile": { @@ -2117,27 +1943,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "dependencies": { - "package-json": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2151,21 +1956,30 @@ "node": ">= 0.8.0" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -2173,21 +1987,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2199,28 +1998,30 @@ "node": ">=10" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, + "node_modules/magichome-core": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/magichome-core/-/magichome-core-0.0.19.tgz", + "integrity": "sha512-eb5mg1Lh6e+UEwfEgUhye5HkwrWggydR+rcvB9wGB7Tjn16qgzfEFYzn+sGUrTXsfH6++UCccW8PcdE/0ogHFw==", "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "color-convert": "^2.0.1", + "dgram": "^1.0.1", + "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", + "promise-queue": "^2.2.5" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node_modules/magichome-platform": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.18.tgz", + "integrity": "sha512-LeoNlHL7W3a9JZzJ/Gw4l4c0h9L4EoLTPpDqTCuuziRooEN8UEpUNxxtcwnxIHL1aqgruSROCjLRf7cHtDERVw==", + "dependencies": { + "dgram": "^1.0.1", + "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", + "magichome-core": ">0.0.12", + "promise-queue": "^2.2.5", + "promise-retry": "^2.0.1", + "uuid": "^8.3.2" } }, "node_modules/make-error": { @@ -2229,19 +2030,32 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "engines": { - "node": ">=4" + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "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.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -2251,18 +2065,18 @@ } }, "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/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" @@ -2275,9 +2089,9 @@ "dev": true }, "node_modules/multicast-dns": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.3.tgz", - "integrity": "sha512-TzxgGSLRLB7tqAlzjgd2x2ZE0cDsGFq4rs9W4yE5xp+7hlRXeUQGtXZsTGfGw2FwWB45rfe8DtXMYBpZGMLUng==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -2289,23 +2103,18 @@ "node_modules/multicast-dns-service-types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/node-color-log": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/node-color-log/-/node-color-log-6.0.0.tgz", - "integrity": "sha512-zaDIxwDZWCwjcndvyXY30sT+h6pcviEvIpuSGZx2kBKVPloMU5xcFgHK85cnAmMeaDyL4xQmbSsGzp3fwOt3Bg==" - }, "node_modules/node-persist": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", - "integrity": "sha1-1m66Pr72IPB5Uw+nsTB2qQZmWHQ=", + "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", "dev": true, "dependencies": { "mkdirp": "~0.5.1", @@ -2313,22 +2122,22 @@ } }, "node_modules/nodemon": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.13.tgz", - "integrity": "sha512-UMXMpsZsv1UXUttCn6gv8eQPhn6DR4BW+txnL3IN5IHqrCwcrT/yWHfL35UsClGXknTH79r5xbu+6J1zNHuSyA==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", + "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", "dev": true, "hasInstallScript": true, "dependencies": { - "chokidar": "^3.2.2", - "debug": "^3.2.6", + "chokidar": "^3.5.2", + "debug": "^3.2.7", "ignore-by-default": "^1.0.1", "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", + "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.3", - "update-notifier": "^5.1.0" + "undefsafe": "^2.0.5" }, "bin": { "nodemon": "bin/nodemon.js" @@ -2350,6 +2159,15 @@ "ms": "^2.1.1" } }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/nodemon/node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -2359,10 +2177,22 @@ "semver": "bin/semver" } }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "dependencies": { "abbrev": "1" @@ -2383,19 +2213,10 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2443,7 +2264,7 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" @@ -2466,37 +2287,34 @@ "node": ">= 0.8.0" } }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/parent-module": { @@ -2511,10 +2329,19 @@ "node": ">=6" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -2529,10 +2356,19 @@ "node": ">=8" } }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" @@ -2550,48 +2386,32 @@ "node": ">= 0.8.0" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/promise-queue": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", - "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=", + "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==", "engines": { "node": ">= 0.8.0" } }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -2601,22 +2421,10 @@ "node": ">=6" } }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/q": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", - "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=", + "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", "dev": true, "engines": { "node": ">=0.6.0", @@ -2632,43 +2440,25 @@ "qrcode-terminal": "bin/qrcode-terminal.js" } }, - "node_modules/queue-promise": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/queue-promise/-/queue-promise-2.2.1.tgz", - "integrity": "sha512-C3eyRwLF9m6dPV4MtqMVFX+Xmc7keZ9Ievm3jJ/wWM5t3uVbFnGsJXwpYzZ4LaIEcX9bss/mdaKzyrO6xheRuA==", - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/readdirp": { "version": "3.6.0", @@ -2683,12 +2473,13 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -2709,39 +2500,6 @@ "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2751,13 +2509,22 @@ "node": ">=4" } }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, - "dependencies": { - "lowercase-keys": "^1.0.0" + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, "node_modules/rimraf": { @@ -2775,10 +2542,33 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -2789,27 +2579,6 @@ "node": ">=10" } }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2844,42 +2613,34 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", - "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", - "dev": true - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "node_modules/simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "semver": "~7.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "node": ">=8.10.0" } }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/source-map": { @@ -2892,54 +2653,36 @@ } }, "node_modules/source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2965,65 +2708,25 @@ "engines": { "node": ">=8" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "has-flag": "^4.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=8" } }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "node_modules/thunky": { @@ -3031,15 +2734,6 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3065,28 +2759,46 @@ } }, "node_modules/ts-node": { - "version": "8.10.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", - "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", - "dev": true, - "dependencies": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", "arg": "^4.1.0", + "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.17", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "bin": { "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js", "ts-script": "dist/bin-script-deprecated.js" }, - "engines": { - "node": ">=6.0.0" - }, "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, "node_modules/tslib": { @@ -3140,20 +2852,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", "dev": true, + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3163,13 +2867,13 @@ } }, "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" }, "funding": { @@ -3177,41 +2881,11 @@ } }, "node_modules/undefsafe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", - "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", - "dev": true, - "dependencies": { - "debug": "^2.2.0" - } - }, - "node_modules/undefsafe/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/undefsafe/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -3221,34 +2895,6 @@ "node": ">= 10.0.0" } }, - "node_modules/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -3258,16 +2904,12 @@ "punycode": "^2.1.0" } }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" } }, "node_modules/v8-compile-cache": { @@ -3276,6 +2918,12 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3321,16 +2969,16 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" + "is-typed-array": "^1.1.9" }, "engines": { "node": ">= 0.4" @@ -3339,18 +2987,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -3360,65 +2996,12 @@ "node": ">=0.10.0" } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -3432,221 +3015,277 @@ "engines": { "node": ">=6" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", - "dev": true - }, - "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.5", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - } + "@jridgewell/trace-mapping": "0.3.9" } }, "@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "@homebridge/ciao": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.2.tgz", - "integrity": "sha512-31IfDKMqxfT+uVNXj0/TmYMou57gP8CUrh0vABzsc5QMsoCQ4Oo5uYQp0oJJyzxTBkF2pFvjR3XlWAapl0VyCg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", + "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", "dev": true, "requires": { - "debug": "^4.3.1", + "debug": "^4.3.4", "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.19", - "tslib": "^2.0.3" + "source-map-support": "^0.5.21", + "tslib": "^2.4.0" }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true } } }, + "@homebridge/plugin-ui-utils": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", + "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + }, "@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", + "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.0", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.4" } }, + "@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true + }, "@humanwhocodes/object-schema": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", - "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@leichtgewicht/ip-codec": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz", - "integrity": "sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { - "defer-to-connect": "^1.0.1" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" } }, - "@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", "dev": true }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true }, - "@types/node": { - "version": "14.17.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.19.tgz", - "integrity": "sha512-jjYI6NkyfXykucU6ELEoT64QyKOdvaA6enOqKtP4xUsGY0X0ZUZz29fUmrTRo+7v7c6TgDu82q3GHHaCEkqZwA==", + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true }, - "@types/promise-queue": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/promise-queue/-/promise-queue-2.2.0.tgz", - "integrity": "sha512-9QLtid6GxEWqpF+QImxBRG6bSVOHtpAm2kXuIyEvZBbSOupLvqhhJv8uaHbS8kUL8FDjzH3RWcSyC/52WOVtGw==", + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@types/json-schema": { + "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": "16.11.47", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.47.tgz", + "integrity": "sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.10.1.tgz", - "integrity": "sha512-PQg0emRtzZFWq6PxBcdxRH3QIQiyFO3WCVpRL3fgj5oQS3CDs3AeAKfv4DxNhzn8ITdNJGJ4D3Qw8eAJf3lXeQ==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.32.0.tgz", + "integrity": "sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "3.10.1", - "debug": "^4.1.1", + "@typescript-eslint/scope-manager": "5.32.0", + "@typescript-eslint/type-utils": "5.32.0", + "@typescript-eslint/utils": "5.32.0", + "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" } }, - "@typescript-eslint/experimental-utils": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz", - "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==", + "@typescript-eslint/parser": { + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.32.0.tgz", + "integrity": "sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A==", "dev": true, "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/types": "3.10.1", - "@typescript-eslint/typescript-estree": "3.10.1", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "@typescript-eslint/scope-manager": "5.32.0", + "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/typescript-estree": "5.32.0", + "debug": "^4.3.4" } }, - "@typescript-eslint/parser": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.10.1.tgz", - "integrity": "sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw==", + "@typescript-eslint/scope-manager": { + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz", + "integrity": "sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/visitor-keys": "5.32.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.32.0.tgz", + "integrity": "sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg==", "dev": true, "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "3.10.1", - "@typescript-eslint/types": "3.10.1", - "@typescript-eslint/typescript-estree": "3.10.1", - "eslint-visitor-keys": "^1.1.0" + "@typescript-eslint/utils": "5.32.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz", - "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz", + "integrity": "sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz", - "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz", + "integrity": "sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg==", "dev": true, "requires": { - "@typescript-eslint/types": "3.10.1", - "@typescript-eslint/visitor-keys": "3.10.1", - "debug": "^4.1.1", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/visitor-keys": "5.32.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz", + "integrity": "sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.32.0", + "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/typescript-estree": "5.32.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz", - "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==", + "version": "5.32.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz", + "integrity": "sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "@typescript-eslint/types": "5.32.0", + "eslint-visitor-keys": "^3.3.0" } }, "abbrev": { @@ -3656,9 +3295,9 @@ "dev": true }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true }, "acorn-jsx": { @@ -3668,6 +3307,12 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3680,21 +3325,6 @@ "uri-js": "^4.2.2" } }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -3702,29 +3332,11 @@ "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { - "color-convert": "^1.9.0" - }, - "dependencies": { - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - } + "color-convert": "^2.0.1" } }, "anymatch": { @@ -3744,29 +3356,20 @@ "dev": true }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, "available-typed-arrays": { @@ -3775,9 +3378,9 @@ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "binary-extensions": { @@ -3798,22 +3401,6 @@ "multicast-dns-service-types": "^1.1.0" } }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3833,44 +3420,12 @@ "fill-range": "^7.0.1" } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } - } - }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -3886,12 +3441,6 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, - "camelcase": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", - "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", - "dev": true - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3899,35 +3448,12 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } } }, "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "requires": { "anymatch": "~3.1.2", @@ -3938,27 +3464,17 @@ "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } } }, "color-convert": { @@ -3983,22 +3499,14 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true }, "cross-spawn": { "version": "7.0.3", @@ -4011,30 +3519,15 @@ "which": "^2.0.1" } }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" } }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, "deep-equal": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", @@ -4057,42 +3550,45 @@ "which-typed-array": "^1.1.2" } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "requires": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, + "dgram": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dgram/-/dgram-1.0.1.tgz", + "integrity": "sha512-zJVFL1EWfKtE0z2VN6qfpn/a+qG1viEzcwJA0EjtzS76ONSE3sEyWBwEbo32hS4IFw/EWVuWN+8b89aPW6It2A==" + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "dns-packet": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.0.tgz", - "integrity": "sha512-Nce7YLu6YCgWRvOmDBsJMo9M5/jV3lEZ5vUWnWXYmwURvPylHvq7nkDWhNmk1ZQoZZOP7oQh/S0lSxbisKOfHg==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", "requires": { "@leichtgewicht/ip-codec": "^2.0.1" } @@ -4106,68 +3602,39 @@ "esutils": "^2.0.2" } }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" }, "es-abstract": { - "version": "1.18.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.6.tgz", - "integrity": "sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "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.2", "is-string": "^1.0.7", - "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", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" } }, "es-get-iterator": { @@ -4195,12 +3662,6 @@ "is-symbol": "^1.0.2" } }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4208,57 +3669,66 @@ "dev": true }, "eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", + "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", "dev": true, "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.3", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -4274,37 +3744,39 @@ } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } } }, "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", + "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", "dev": true, "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, "esquery": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", @@ -4315,9 +3787,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -4332,9 +3804,9 @@ }, "dependencies": { "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } @@ -4357,6 +3829,30 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -4366,15 +3862,24 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fast-srp-hap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.3.tgz", - "integrity": "sha512-4P8TBD0all202L9FbeSsWc9qDlpaYp065VbUwbuNYZDYdOJ02UlWaDkai6d/+6/I8/sdtVYAVd17PEZDKbqopQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", + "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", "dev": true }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4393,6 +3898,16 @@ "to-regex-range": "^5.0.1" } }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -4404,23 +3919,25 @@ } }, "flatted": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", - "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", "dev": true }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } }, "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" @@ -4429,7 +3946,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "fsevents": { @@ -4444,35 +3961,42 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", "dev": true }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, "futoin-hkdf": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.3.3.tgz", - "integrity": "sha512-oR75fYk3B3X9/B02Y6vusrBKucrpC6VjxhRL+C6B7FwUpuSRHbhBNG3AZbcE/xPyJmEQWsyqUFp3VeNNbA3S7A==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", + "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", "dev": true }, "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" + "has-symbols": "^1.0.3" } }, "get-symbol-description": { @@ -4485,93 +4009,85 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { - "ini": "2.0.0" + "is-glob": "^4.0.3" } }, "globals": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", - "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" } }, "graceful-fs": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", - "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, "hap-nodejs": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.9.4.tgz", - "integrity": "sha512-wGYq6nQ8c5+V7iLr9Fa7XpOGAntmB0ejfOsjoIhXe/WHOXX9gGDwYgQTHg+dwmJZjW7RBoOyRRdB7/oa/NYovw==", + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.9.8.tgz", + "integrity": "sha512-+IENi8nFh/yOvVZEEIgY+nVppoXgY3mN8CfRh/I9tlhDbp3rXlsjdvHFVOgk7qJNa6cwzKu0KzNUs+n3XpO1Iw==", "dev": true, "requires": { - "@homebridge/ciao": "~1.1.2", - "bonjour-hap": "~3.6.2", - "debug": "^4.3.1", - "fast-srp-hap": "2.0.3", - "futoin-hkdf": "~1.3.2", - "ip": "^1.1.3", + "@homebridge/ciao": "~1.1.3", + "bonjour-hap": "~3.6.3", + "debug": "^4.3.2", + "fast-srp-hap": "2.0.4", + "futoin-hkdf": "~1.4.2", + "ip": "^1.1.5", "node-persist": "^0.0.11", - "source-map-support": "^0.5.19", - "tslib": "^2.1.0", + "source-map-support": "^0.5.20", + "tslib": "^2.3.1", "tweetnacl": "^1.0.3" }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true } } @@ -4585,20 +4101,27 @@ } }, "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } }, "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, "has-tostringtag": { "version": "1.0.0", @@ -4608,53 +4131,42 @@ "has-symbols": "^1.0.2" } }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, "homebridge": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.3.4.tgz", - "integrity": "sha512-I2vxabWpKHly3htXvOgnJbO79pXzrorz6/htRUCD3UTWXnzURqUFhevv9c/Mji3YeKxluIXCyXyiGAuDfx1m3A==", + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.3.9.tgz", + "integrity": "sha512-/QYosrEmxao6EekPMU3la3j3qx0UWLcYQN01qbZ7s1ZrKp8aC+aShgNx1borFrY/0fHsZauGcbuNqFh+XSKNXw==", "dev": true, "requires": { - "chalk": "^4.1.0", + "chalk": "^4.1.2", "commander": "5.1.0", - "fs-extra": "^9.1.0", - "hap-nodejs": "0.9.4", + "fs-extra": "^10.0.0", + "hap-nodejs": "0.9.8", "qrcode-terminal": "^0.12.0", - "semver": "^7.3.4", - "source-map-support": "^0.5.19" + "semver": "^7.3.5", + "source-map-support": "^0.5.20" } }, "homebridge-lib": { - "version": "5.1.14", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.1.14.tgz", - "integrity": "sha512-ZtGssTd9uoKv169ChDoiMmCLdzHGtHtlAJ7zM8JM9u8Sxgm/X8LtoV+OB78m9TuHEuvmv5wdJqguYYSFycclgw==", + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.3.tgz", + "integrity": "sha512-7X84aSayZd7YjboxoFsZ78ExfoRlZmo0t3Hasu4PL0XCILu6dqAG3Zzhqtsg/wqYTfqavvOleRInTMmFEGz6ew==", "requires": { + "@homebridge/plugin-ui-utils": "~0.0.19", "bonjour-hap": "^3.6.3", "chalk": "^4.1.2", - "semver": "^7.3.5" + "semver": "^7.3.7" } }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, "import-fresh": { @@ -4667,22 +4179,16 @@ "resolve-from": "^4.0.0" } }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -4695,12 +4201,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, "internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -4712,9 +4212,9 @@ } }, "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" }, "is-arguments": { "version": "1.1.1", @@ -4756,15 +4256,6 @@ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, "is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -4776,49 +4267,27 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, "is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" }, "is-negative-zero": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", - "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" }, "is-number": { "version": "7.0.0", @@ -4827,25 +4296,13 @@ "dev": true }, "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "requires": { "has-tostringtag": "^1.0.0" } }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -4860,6 +4317,14 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "requires": { + "call-bind": "^1.0.2" + } + }, "is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -4877,38 +4342,38 @@ } }, "is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" }, - "is-weakset": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", - "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==" + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "requires": { + "call-bind": "^1.0.2" + } }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } }, "isarray": { "version": "2.0.5", @@ -4918,31 +4383,18 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4952,7 +4404,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "jsonfile": { @@ -4962,25 +4414,7 @@ "dev": true, "requires": { "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.0" + "universalify": "^2.0.0" } }, "levn": { @@ -4993,21 +4427,24 @@ "type-check": "~0.4.0" } }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" }, "lodash.merge": { "version": "4.6.2", @@ -5015,18 +4452,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5035,21 +4460,30 @@ "yallist": "^4.0.0" } }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, + "magichome-core": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/magichome-core/-/magichome-core-0.0.19.tgz", + "integrity": "sha512-eb5mg1Lh6e+UEwfEgUhye5HkwrWggydR+rcvB9wGB7Tjn16qgzfEFYzn+sGUrTXsfH6++UCccW8PcdE/0ogHFw==", "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "color-convert": "^2.0.1", + "dgram": "^1.0.1", + "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", + "promise-queue": "^2.2.5" + } + }, + "magichome-platform": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.18.tgz", + "integrity": "sha512-LeoNlHL7W3a9JZzJ/Gw4l4c0h9L4EoLTPpDqTCuuziRooEN8UEpUNxxtcwnxIHL1aqgruSROCjLRf7cHtDERVw==", + "requires": { + "dgram": "^1.0.1", + "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", + "magichome-core": ">0.0.12", + "promise-queue": "^2.2.5", + "promise-retry": "^2.0.1", + "uuid": "^8.3.2" } }, "make-error": { @@ -5058,34 +4492,44 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, + "micromatch": { + "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.2", + "picomatch": "^2.3.1" + } + }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "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 }, "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": { @@ -5095,9 +4539,9 @@ "dev": true }, "multicast-dns": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.3.tgz", - "integrity": "sha512-TzxgGSLRLB7tqAlzjgd2x2ZE0cDsGFq4rs9W4yE5xp+7hlRXeUQGtXZsTGfGw2FwWB45rfe8DtXMYBpZGMLUng==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "requires": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -5106,23 +4550,18 @@ "multicast-dns-service-types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==" }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node-color-log": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/node-color-log/-/node-color-log-6.0.0.tgz", - "integrity": "sha512-zaDIxwDZWCwjcndvyXY30sT+h6pcviEvIpuSGZx2kBKVPloMU5xcFgHK85cnAmMeaDyL4xQmbSsGzp3fwOt3Bg==" - }, "node-persist": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", - "integrity": "sha1-1m66Pr72IPB5Uw+nsTB2qQZmWHQ=", + "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", "dev": true, "requires": { "mkdirp": "~0.5.1", @@ -5130,21 +4569,21 @@ } }, "nodemon": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.13.tgz", - "integrity": "sha512-UMXMpsZsv1UXUttCn6gv8eQPhn6DR4BW+txnL3IN5IHqrCwcrT/yWHfL35UsClGXknTH79r5xbu+6J1zNHuSyA==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", + "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", "dev": true, "requires": { - "chokidar": "^3.2.2", - "debug": "^3.2.6", + "chokidar": "^3.5.2", + "debug": "^3.2.7", "ignore-by-default": "^1.0.1", "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", + "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.3", - "update-notifier": "^5.1.0" + "undefsafe": "^2.0.5" }, "dependencies": { "debug": { @@ -5156,18 +4595,33 @@ "ms": "^2.1.1" } }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "requires": { "abbrev": "1" @@ -5179,16 +4633,10 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==" + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" }, "object-is": { "version": "1.1.5", @@ -5218,7 +4666,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -5238,30 +4686,22 @@ "word-wrap": "^1.2.3" } }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "p-limit": "^3.0.2" } }, "parent-module": { @@ -5273,10 +4713,16 @@ "callsites": "^3.0.0" } }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true }, "path-key": { @@ -5285,10 +4731,16 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, "prelude-ls": { @@ -5297,22 +4749,19 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, "promise-queue": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", - "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=" + "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==" + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } }, "pstree.remy": { "version": "1.1.8", @@ -5320,35 +4769,16 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "requires": { - "escape-goat": "^2.0.0" - } - }, "q": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", - "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=", + "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", "dev": true }, "qrcode-terminal": { @@ -5357,36 +4787,11 @@ "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", "dev": true }, - "queue-promise": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/queue-promise/-/queue-promise-2.2.1.tgz", - "integrity": "sha512-C3eyRwLF9m6dPV4MtqMVFX+Xmc7keZ9Ievm3jJ/wWM5t3uVbFnGsJXwpYzZ4LaIEcX9bss/mdaKzyrO6xheRuA==" - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - } - } + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true }, "readdirp": { "version": "3.6.0", @@ -5398,12 +4803,13 @@ } }, "regexp.prototype.flags": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", - "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" } }, "regexpp": { @@ -5412,44 +4818,22 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - } + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true }, "rimraf": { "version": "3.0.2", @@ -5460,29 +4844,21 @@ "glob": "^7.1.3" } }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "requires": { - "lru-cache": "^6.0.0" + "queue-microtask": "^1.2.2" } }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } + "lru-cache": "^6.0.0" } }, "shebang-command": { @@ -5510,34 +4886,29 @@ "object-inspect": "^1.9.0" } }, - "signal-exit": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz", - "integrity": "sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "semver": "~7.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true } } }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5545,48 +4916,33 @@ "dev": true }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "strip-ansi": { @@ -5605,52 +4961,17 @@ "dev": true }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.6.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz", - "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } + "has-flag": "^4.0.0" } }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "thunky": { @@ -5658,12 +4979,6 @@ "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -5683,15 +4998,23 @@ } }, "ts-node": { - "version": "8.10.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", - "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", - "dev": true, - "requires": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", "arg": "^4.1.0", + "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.17", + "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" } }, @@ -5731,66 +5054,29 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, "typescript": { - "version": "3.9.10", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", - "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", - "dev": true + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "peer": true }, "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, "undefsafe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", - "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", - "dev": true, - "requires": { - "debug": "^2.2.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true }, "universalify": { "version": "2.0.0", @@ -5798,28 +5084,6 @@ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - } - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -5829,14 +5093,10 @@ "punycode": "^2.1.0" } }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache": { "version": "2.3.0", @@ -5844,6 +5104,12 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5877,25 +5143,16 @@ } }, "which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" - } - }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" + "is-typed-array": "^1.1.9" } }, "word-wrap": { @@ -5904,50 +5161,10 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - } - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "yallist": { @@ -5960,6 +5177,12 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index 50607bd..7d3f8b4 100644 --- a/package.json +++ b/package.json @@ -63,22 +63,16 @@ "dependencies": { "color-convert": "^2.0.1", "homebridge-lib": "^5.1.14", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "node-color-log": "^6.0.0", - "promise-queue": "^2.2.5", - "queue-promise": "^2.2.1" + "magichome-platform": "^0.0.18" }, "devDependencies": { - "@types/node": "^14.17.19", - "@types/promise-queue": "^2.2.0", - "@typescript-eslint/eslint-plugin": "^3.10.1", - "@typescript-eslint/parser": "^3.10.1", - "eslint": "^7.32.0", - "homebridge": "^1.3.4", + "@types/node": "^16.10.9", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^8.0.1", + "homebridge": "^1.3.9", "nodemon": "^2.0.13", "rimraf": "^3.0.2", - "ts-node": "^8.10.2", - "typescript": "^3.9.10" + "ts-node": "^10.3.0" } } diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index cc27373..d53ff66 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -1,12 +1,7 @@ -import { BaseController, ControllerGenerator, ICustomProtoDevice, IDeviceAPI } from 'magichome-platform'; +import { BaseController, ControllerGenerator, ICustomProtoDevice, IDeviceAPI, ICompleteDevice, IProtoDevice, ICustomCompleteDevice } from 'magichome-platform'; import { IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; -import { - API, - HAP, - PlatformConfig, -} from 'homebridge'; +import { API, HAP, PlatformAccessory, PlatformConfig, } from 'homebridge'; -import { _ } from 'lodash'; import { homekitInterface } from './misc/types'; import { Logs } from './logs'; @@ -17,6 +12,8 @@ export class AccessoryGenerator { public readonly accessoriesFromDiskMap: Map = new Map(); public readonly activeAccessoriesMap: Map = new Map(); + public readonly cachedAccessoriesMap: Map = new Map(); + private hap: HAP; private api: API; private hbLogger; @@ -33,14 +30,23 @@ export class AccessoryGenerator { this.controllerGenerator = controllerGenerator; } - public async generateAccessories() { - this.logs.info('Scanning network for MagicHome accessories.'); - return await this.controllerGenerator.discoverControllers().then(async controllers => { - await this.discoverAccessories(controllers); + public async discoverDevices() { + this.logs.info('Scanning network for MagicHome accessories...'); + + try { + const completeDevices: ICompleteDevice[] = await this.controllerGenerator.discoverCompleteDevices(); + const controllers: BaseController[] = await this.controllerGenerator.generateControllers(completeDevices); + await this.generateActiveAccessories(controllers); this.registerOfflineAccessories(); - }).catch(error => { - this.logs.error(error); - }); + } catch (error) { + this.logs.error(error) + } + + } + + public async rediscoverDevices(timeoutMinutes: number) { + const completeDevices: ICompleteDevice[] = await this.controllerGenerator.discoverCompleteDevices(); + } /** @@ -67,120 +73,135 @@ export class AccessoryGenerator { * which is quite wasteful... */ - public async rescanAccessories() { - this.logs.trace('Re-scanning network for MagicHome accessories.'); - return await this.controllerGenerator.discoverControllers().then(async controllers => { - await this.discoverAccessories(controllers); - }).catch(error => { - this.logs.error(error); - }); - } - - async discoverAccessories(controllers: Map) { + async generateActiveAccessories(controllers: BaseController[]) { const newAccessoriesList: MagicHomeAccessory[] = []; const existingAccessoriesList: MagicHomeAccessory[] = []; - for (const [uniqueId, controller] of controllers.entries()) { - new Promise((resolve, reject) => { - const homebridgeUUID = this.hap.uuid.generate(uniqueId); - let accessory; - if (this.accessoriesFromDiskMap.has(homebridgeUUID)) { - - const existingAccessory = this.accessoriesFromDiskMap.get(homebridgeUUID); - this.accessoriesFromDiskMap.delete(homebridgeUUID); - if (this.activeAccessoriesMap.has(homebridgeUUID)) { - this.logs.warn(`[${existingAccessory.context.displayName}] - Found existing accessory that was unseen previous scan. Updating...`); - reject; - } - accessory = this.processExistingAccessory(controller, existingAccessory); - this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); - if (accessory) { - existingAccessoriesList.push(accessory); - } else { - reject; - } - } else if (!this.activeAccessoriesMap.has(homebridgeUUID)) { - accessory = this.createNewAccessory(controller, homebridgeUUID); - console.log(accessory.context.displayName); - this.logs.info(`[${accessory.context.displayName}] - Found new accessory. Registering...`); - newAccessoriesList.push(accessory); //add it to new accessory list + for (const controller of controllers) { + try { + // console.log(controller) + const { protoDevice: { uniqueId }, deviceState, deviceAPI } = controller.getCachedDeviceInformation(); + let currAccessory: MagicHomeAccessory; + + // if (this.accessoriesFromDiskMap.has(uniqueId)) { + // const existingAccessory = this.accessoriesFromDiskMap.get(uniqueId); + // this.accessoriesFromDiskMap.delete(uniqueId); + // this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); + // currAccessory = this.processOnlineAccessory(controller, existingAccessory); + // existingAccessoriesList.push(currAccessory); + + // } + // else + if (!this.activeAccessoriesMap.has(uniqueId)) { //if the accessory is not a duplicate active device + currAccessory = this.createNewAccessory(controller); + // this.logs.info(`[${currAccessory.context.displayName}] - Found new accessory. Registering...`); + newAccessoriesList.push(currAccessory); //add it to new accessory list } - this.activeAccessoriesMap.set(homebridgeUUID, accessory); - }).catch(); + this.activeAccessoriesMap.set(uniqueId, currAccessory); + } catch (error) { + this.logs.error(error) + } } this.registerNewAccessories(newAccessoriesList); //register new accessories from scan - this.updateExistingAccessories(existingAccessoriesList); + // this.updateExistingAccessories(existingAccessoriesList); } - createNewAccessory(controller: BaseController, homebridgeUUID: string)/*: Promise*/ { + // repairActiveAcessories(protoDevices: IProtoDevice[]) { + + // const { uniqueId, ipAddress } = protoDevice; + // if (this.activeAccessoriesMap.has(uniqueId)) { + // const activeAccessory = this.activeAccessoriesMap.get(uniqueId); + // this.logs.warn(`[${activeAccessory.context.displayName}] - Found existing accessory which was offline in previous scan. Testing...`); + // if (activeAccessory.context.cachedDeviceInformation.protoDevice.ipAddress === protoDevice.ipAddress) return; + // else { + + // } + + // } + // } + + createNewAccessory(controller: BaseController) { const cachedDeviceInformation = controller.getCachedDeviceInformation(); const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; // console.log(description); - + // console.log(uniqueId) if (!this.isAllowed(uniqueId)) { return; } - + const homebridgeUUID = this.hap.uuid.generate(uniqueId); + console.log(homebridgeUUID) const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; - newAccessory.context = { cachedDeviceInformation, displayName: description as string, restartsSinceSeen: 0 }; - // console.log(newAccessory.context.displayName); - try { - new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger); - } catch (error) { - this.logs.error('The controllerLogicType does not exist in accessoryType list.'); - this.logs.error(error); - } + // console.log(newAccessory) + newAccessory.context = { displayName: description as string, restartsSinceSeen: 0 }; + new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); + return newAccessory; } - registerOfflineAccessories() { - const existingAccessoriesList: MagicHomeAccessory[] = []; - this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { - const homebridgeUUID = this.hap.uuid.generate(offlineAccessory.context.cachedDeviceInformation.protoDevice.uniqueId); - await this.processOfflineAccessory(offlineAccessory); - existingAccessoriesList.push(offlineAccessory); - this.activeAccessoriesMap.set(homebridgeUUID, offlineAccessory); - }); - this.updateExistingAccessories(existingAccessoriesList); - } + processOnlineAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { - processExistingAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { - try { + const cachedDeviceInformation = controller.getCachedDeviceInformation(); + const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; + if (!this.isAllowed(uniqueId)) { + throw new Error(`[Error] [${existingAccessory.context.displayName}] - Accessory is not allowed. Skipping...`); + } - const cachedDeviceInformation = controller?.getCachedDeviceInformation() ?? existingAccessory.context.cachedDeviceInformation; - const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; - if (!this.isAllowed(uniqueId) || !this.isFresh(cachedDeviceInformation, existingAccessory)) { - return null; - } - _.merge(existingAccessory.context, { cachedDeviceInformation, restartsSinceSeen: 0 }); + existingAccessory.context = Object.assign({}, existingAccessory.context, { cachedDeviceInformation, restartsSinceSeen: 0 }); - try { - new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger); - } catch (error) { - this.logs.error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: `, error); - } - return existingAccessory; + try { + new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); } catch (error) { - this.logs.error(error); + throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); } + return existingAccessory; + } + + registerOfflineAccessories() { + // const offlineAccessoriesList: MagicHomeAccessory[] = []; + // const completeDevices: ICustomCompleteDevice[] = [] + // this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { + // const { deviceState, deviceAPI, deviceAPI: { description }, completeDevice } = offlineAccessory.context.cachedDeviceInformation; + // const { protoDevice, completeResponse, latestUpdate } = completeDevice; + // completeDevices.push({ customProtoDevice: protoDevice, completeResponse, latestUpdate }); + // }); + + // const controllers = this.controllerGenerator.generateCustomControllers(completeDevices); + + // for (const controller of controllers) { + // try { + // const { protoDevice: { uniqueId } } = controller.getCachedDeviceInformation(); + // if (this.accessoriesFromDiskMap.has(uniqueId)) { + // const offlineAccessory = this.accessoriesFromDiskMap.get(uniqueId); + // this.accessoriesFromDiskMap.delete(uniqueId); + // this.processOfflineAccessory(offlineAccessory, controller); + // offlineAccessoriesList.push(offlineAccessory); + // this.cachedAccessoriesMap.set(offlineAccessory.context.cachedDeviceInformation.protoDevice.uniqueId, offlineAccessory); + // } + // } catch (error) { + // this.logs.error(error); + // } + // } + + // this.updateExistingAccessories(offlineAccessoriesList); } - async processOfflineAccessory(offlineAccessory) { - offlineAccessory.context.restartsSinceSeen++; - const { deviceState, protoDevice, deviceAPI, deviceAPI: { description } } = offlineAccessory.context.cachedDeviceInformation; - this.logs.warn(`[${offlineAccessory.context.displayName}] [UID: ${protoDevice.uniqueId}] - Device Unreachable. Registering accessory with cached information.`); - this.logs.trace(deviceState); - const controller = await this.controllerGenerator.createCustomControllers({ protoDevice, deviceAPI, deviceState }); - new homekitInterface[description](this.api, offlineAccessory, this.config, controller, this.hbLogger); + processOfflineAccessory(offlineAccessory: MagicHomeAccessory, controller: BaseController) { + // offlineAccessory.context.restartsSinceSeen++; + // const { deviceState, protoDevice, deviceAPI, deviceAPI: { description }, completeDevice } = offlineAccessory.context.cachedDeviceInformation; + // this.logs.warn(`[${offlineAccessory.context.displayName}] [UID: ${protoDevice.uniqueId}] - Device Unreachable. Registering accessory with cached information.`); + // this.logs.trace(deviceState); + // new homekitInterface[description](this.api, offlineAccessory, this.config, controller, this.hbLogger); } + + registerNewAccessories(newAccessories: MagicHomeAccessory[]) { // link the accessory to your platform this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); @@ -191,26 +212,6 @@ export class AccessoryGenerator { this.api.updatePlatformAccessories(existingAccessories); } - isFresh(cachedInformation, existingAccessory: MagicHomeAccessory): boolean { - let isFresh = true; - if (existingAccessory.context.displayName?.toString().toLowerCase().includes('delete')) { - this.logs.warn('should be deleting...'); - this.unregisterAccessory(existingAccessory, - `Successfully pruned accessory: ${existingAccessory.context.displayName} due to being marked for deletion\n`); - isFresh = false; - } - - // else if (this.config.pruning?.pruneRestarts ?? false) { - // if (existingAccessory.context.restartsSinceSeen >= this.config.pruning.pruneRestarts) { - // this.unregisterAccessory(existingAccessory, `Successfully pruned accessory: ${existingAccessory.context.displayName} - // which had not being seen for ${existingAccessory.context.restartsSinceSeen} restart(s).\n`); - // isFresh = false; - // } - // } - - return isFresh; - } - isAllowed(uniqueId: string): boolean { const blacklistedUniqueIDs = this.config.deviceManagement?.blacklistedUniqueIDs ?? []; @@ -220,7 +221,6 @@ export class AccessoryGenerator { const isAllowed = isWhitelist ? onList : !onList; return isAllowed; - return true; } unregisterAccessory(existingAccessory: MagicHomeAccessory, reason: string) { diff --git a/src/accessories/GRBStrip.ts b/src/accessories/GRBStrip.ts index 4e8b2e7..f9186f7 100644 --- a/src/accessories/GRBStrip.ts +++ b/src/accessories/GRBStrip.ts @@ -1,4 +1,4 @@ -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -22,13 +22,13 @@ export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { const _blue = Math.round((blue / 100) * brightness); - const deviceCommand: IDeviceCommand = { isOn, RGB: {red: _red, green: _green, blue: _blue } }; + const deviceCommand: IDeviceCommand = { isOn, RGB: { red: _red, green: _green, blue: _blue }, CCT: { warmWhite: 0, coldWhite: 0 }, colorMask: 0xF0 }; return deviceCommand; }//setColor deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LEDState: { RGB: { red, green, blue }, isOn } } = deviceState; + const { RGB: { red, green, blue }, isOn } = deviceState; const RGB: IColorRGB = { red: green, green: red, blue }; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index d6b589b..13903f9 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -1,4 +1,4 @@ -import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -42,14 +42,14 @@ export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { warmWhite = 0; } - const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite }, colorMask }; + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; return deviceCommand; }//setColor deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index b244ad3..5a4ffa1 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -1,4 +1,4 @@ -import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp, convertMiredColorTemperatureToHueSat, whiteTemperatureToCCT } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -52,13 +52,13 @@ export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { warmWhite = 0; } - const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite }, colorMask }; + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; return deviceCommand; } deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index 668042d..48b7450 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -1,4 +1,4 @@ -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -67,7 +67,7 @@ export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { }//setColor deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index 62af9cd..915295c 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -1,4 +1,4 @@ -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; import { IAccessoryCommand, IAccessoryState } from '../misc/types'; import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; @@ -75,8 +75,8 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { }//setColor deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - - const { LEDState: { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + + const { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); @@ -100,7 +100,7 @@ export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { hue = hueSat[0]; saturation = 10; } - } + } const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; return accessoryState; diff --git a/src/accessories/Switch.ts b/src/accessories/Switch.ts index ec2188b..e487e2c 100644 --- a/src/accessories/Switch.ts +++ b/src/accessories/Switch.ts @@ -1,18 +1,18 @@ import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; export class Switch extends HomebridgeMagichomeDynamicPlatformAccessory { - + // /** // ** @updateHomekitState // * send state to homekit // */ // async updateHomekitState() { - + // // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); // } - - - + + + } \ No newline at end of file diff --git a/src/misc/serviceCharacteristics.ts b/src/misc/serviceCharacteristics.ts index 86b43ae..6d58778 100644 --- a/src/misc/serviceCharacteristics.ts +++ b/src/misc/serviceCharacteristics.ts @@ -47,15 +47,15 @@ export function addColorTemperatureCharacteristic(_this) { export function addAccessoryInformationCharacteristic(_this) { - const { - protoDevice: { uniqueId, modelNumber }, - // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, - } = _this.accessory.context.cachedDeviceInformation; + // const { + // protoDevice: { uniqueId, modelNumber }, + // // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, + // } = _this.accessory.context.cachedDeviceInformation; // set accessory information _this.accessory.getService(_this.hap.Service.AccessoryInformation)! .setCharacteristic(_this.hap.Characteristic.Manufacturer, 'MagicHome') - .setCharacteristic(_this.hap.Characteristic.SerialNumber, uniqueId) - .setCharacteristic(_this.hap.Characteristic.Model, modelNumber) + // .setCharacteristic(_this.hap.Characteristic.SerialNumber, uniqueId) + // .setCharacteristic(_this.hap.Characteristic.Model, modelNumber) // .setCharacteristic(_this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') // .setCharacteristic(_this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') .getCharacteristic(_this.hap.Characteristic.Identify) diff --git a/src/misc/types.ts b/src/misc/types.ts index be90ec3..45a6f6a 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -1,5 +1,5 @@ import type { PlatformAccessory } from 'homebridge'; -import { BaseController } from 'magichome-platform'; +import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation } from 'magichome-platform'; import { Switch } from '../accessories/Switch'; import { DimmerStrip } from '../accessories/DimmerStrip'; @@ -10,19 +10,18 @@ import { RGBWWBulb } from '../accessories/RGBWWBulb'; import { RGBWStrip } from '../accessories/RGBWStrip'; import { RGBWWStrip } from '../accessories/RGBWWStrip'; import { CCTStrip } from '../accessories/CCTStrip'; -import { IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation } from 'magichome-platform/dist/types'; export const homekitInterface = { - 'Power Socket': Switch, - 'Dimmer': DimmerStrip, - 'GRB Strip': GRBStrip, - 'RGB Strip': RGBStrip, + // 'Power Socket': Switch, + // 'Dimmer': DimmerStrip, + // 'GRB Strip': GRBStrip, + // 'RGB Strip': RGBStrip, 'RGBW Non-Simultaneous': RGBWBulb, 'RGBWW Non-Simultaneous': RGBWWBulb, 'RGBW Simultaneous': RGBWStrip, 'RGBWW Simultaneous': RGBWWStrip, - 'CCT Strip': CCTStrip, + // 'CCT Strip': CCTStrip, }; export interface MagicHomeAccessory extends PlatformAccessory { @@ -33,7 +32,7 @@ export interface IAccessoryContext { displayName?: string; restartsSinceSeen: number, accessoryState?: IAccessoryState; - cachedDeviceInformation: IDeviceInformation; + // cachedDeviceInformation: IDeviceInformation; } export interface IAccessoryState { diff --git a/src/misc/utils.ts b/src/misc/utils.ts index 4dc7812..7289aeb 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -1,5 +1,5 @@ import { existsSync, readFileSync } from 'fs'; -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform/dist/types'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; import { IAccessoryCommand, IAccessoryState, IColorHSL } from './types'; @@ -79,7 +79,7 @@ export function convertRGBtoHSL(RGB: IColorRGB) { //================================================= // Start Convert HSLtoRGB // -export function convertHSLtoRGB(HSL: IColorHSL): IColorRGB { +export function convertHSLtoRGB(HSL: IColorHSL) { const { hue, saturation, luminance } = HSL; @@ -125,7 +125,7 @@ export function convertHSLtoRGB(HSL: IColorHSL): IColorRGB { g = Math.floor(g); b = Math.floor(b); - const RGB = { red: r, green: g, blue: b }; + let RGB = Object.assign({}, { red: r, green: g, blue: b }); return RGB; } //================================================= diff --git a/src/platform.ts b/src/platform.ts index 40cf0a9..8719bd9 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -1,6 +1,5 @@ import { join } from 'path'; import { loadJson } from './misc/utils'; -import { cloneDeep } from 'lodash'; import { Logs } from './logs'; import { API, @@ -15,7 +14,6 @@ import { ControllerGenerator } from 'magichome-platform'; import { MagicHomeAccessory } from './misc/types'; import { AccessoryGenerator } from './AccessoryGenerator'; -import logger from 'node-color-log'; /** */ @@ -52,7 +50,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin this.api = api; //this.logs = getLogger(); this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); - logger.reverse().log('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); + this.log.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); // When this event is fired it means Homebridge has restored all cached accessories from disk. // Dynamic Platform plugins should only register new accessories after this event was fired, @@ -99,7 +97,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); await accesssoryGenerator.discoverDevices(); - this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); + // this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); } diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index c16de81..bfd2b16 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -6,7 +6,7 @@ import type { import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop } from 'magichome-platform'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse } from 'magichome-platform'; import { Logs } from './logs'; @@ -32,7 +32,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected latestAccessoryCommand: IAccessoryCommand; protected ColorCommandMode = HSL; - protected logs; protected colorWhiteSimultaniousSaturationLevel; protected colorOffSaturationLevel; @@ -55,10 +54,11 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { public readonly config: PlatformConfig, protected readonly controller: BaseController, protected readonly hbLogger: Logging, + protected readonly logs, ) { this.setupMisc(); - + this.logs = logs; this.controller = controller; this.hap = api.hap; this.api = api; @@ -102,12 +102,12 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.processAccessoryCommand(accessoryCommand); } - setColorTemperature(value: CharacteristicValue) { + // setColorTemperature(value: CharacteristicValue) { - this.ColorCommandMode = CCT; - const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; - this.processAccessoryCommand(accessoryCommand); - } + // this.ColorCommandMode = CCT; + // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; + // this.processAccessoryCommand(accessoryCommand); + // } setConfiguredName(value: CharacteristicValue) { @@ -129,22 +129,24 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start Getters // getHue() { + const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - const hue = this.accessory.context.accessoryState.HSL.hue; this.fetchAndUpdateState(2); return hue; } - getColorTemperature() { + // getColorTemperature() { + // const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - const colorTemperature = this.accessory.context.accessoryState.colorTemperature; - this.fetchAndUpdateState(3); - return colorTemperature; - } + // const colorTemperature = this.accessory.context.accessoryState.colorTemperature; + // this.fetchAndUpdateState(3); + // return colorTemperature; + // } getBrightness() { - const brightness = this.accessory.context.accessoryState.brightness; + const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) + this.fetchAndUpdateState(2); return brightness; } @@ -155,7 +157,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { * next call this.getState() which will update all values asynchronously as they are ready */ async getOn() { - const isOn = this.accessory.context.accessoryState.isOn; + const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) + this.fetchAndUpdateState(2); return isOn; } @@ -173,51 +176,47 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // this.controller.clearAnimations(); //} - const deviceWriteStatus = this.deviceWriteStatus; - switch (deviceWriteStatus) { - case 'ready': - - this.deviceWriteStatus = 'pending'; - await this.writeStateToDevice(accessoryCommand).then((msg) => { - //error logging - }).finally(() => { - this.deviceWriteStatus = 'ready'; - }); - break; - - case pending: - _.merge(this.newAccessoryCommand, accessoryCommand); - break; - } + await this.prepareCommand(accessoryCommand); } - protected async writeStateToDevice(accessoryCommand: IAccessoryCommand): Promise { - this.newAccessoryCommand = accessoryCommand; - return new Promise((resolve, reject) => { - return setTimeout(() => { - this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessory.context.accessoryState, '\n Received Command', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = _.merge({}, this.accessory.context.accessoryState, this.newAccessoryCommand); - - // eslint-disable-next-line no-prototype-builtins - if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { - sanitizedAcessoryCommand.isPowerCommand = true; - } - resolve(this.prepareCommand(sanitizedAcessoryCommand)); - }, BUFFER_MS); - }); + protected async prepareCommand(accessoryCommand: IAccessoryCommand): Promise { + try { + + + this.newAccessoryCommand = accessoryCommand; + + this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessory.context.accessoryState, '\n Received Command', this.newAccessoryCommand); + const sanitizedAcessoryCommand: IAccessoryCommand = Object.assign({}, this.accessory.context.accessoryState, this.newAccessoryCommand); + + // eslint-disable-next-line no-prototype-builtins + if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { + sanitizedAcessoryCommand.isPowerCommand = true; + } + const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand); + return completeResponse; + } catch (error) { + + } } - protected async prepareCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions) { - const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); + protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions?: ICommandOptions): Promise { + try { + + + const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); + + let response; + if (!accessoryCommand.isPowerCommand) { + response = await this.controller.setAllValues(deviceCommand, commandOptions); + } else { + response = await this.controller.setOn(deviceCommand.isOn, commandOptions); + } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); + return response; + } catch (error) { - let response; - if (!accessoryCommand.isPowerCommand) { - response = await this.controller.setAllValues(deviceCommand, commandOptions); - } else { - response = await this.controller.setOn(deviceCommand.isOn, commandOptions); } - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); } protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { @@ -228,16 +227,18 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { RGB.green = Math.round((RGB.green / 100) * brightness); RGB.blue = Math.round((RGB.blue / 100) * brightness); - const deviceCommand: IDeviceCommand = { isOn, RGB }; + + const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; return deviceCommand; } protected async updateLocalState(requestLevel, deviceState) { if (!deviceState) { - deviceState = await this.controller?.fetchState() ?? this.accessory.context.cachedDeviceInformation.deviceState; + deviceState = await this.controller?.fetchState() + // ?? this.accessory.context.cachedDeviceInformation.deviceState; } this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); - this.accessory.context.cachedDeviceInformation.deviceState = deviceState; + // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); let accessoryState: IAccessoryState; if (deviceState) { @@ -255,24 +256,22 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; break; } - _.merge(this.accessory.context.accessoryState, accessoryState); - this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, this.accessory.context.accessoryState); - } else { - _.merge(this.accessory.context.accessoryState, { isOn: false }); + this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); } } updateHomekitState() { - this.service.updateCharacteristic(this.hap.Characteristic.On, this.accessory.context.accessoryState.isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, this.accessory.context.accessoryState.HSL.hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessory.context.accessoryState.HSL.saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, this.accessory.context.accessoryState.brightness); + const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) + this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, brightness); } deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { LEDState: { RGB, CCT: { coldWhite, warmWhite }, isOn } } = deviceState; + const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; // eslint-disable-next-line prefer-const let { hue, saturation, luminance } = convertRGBtoHSL(RGB); let brightness = 0; @@ -296,9 +295,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { let cachedDeviceInformation = this.controller?.getCachedDeviceInformation(); if (cachedDeviceInformation) { - this.accessory.context.cachedDeviceInformation = cachedDeviceInformation; + // this.accessory.context.cachedDeviceInformation = cachedDeviceInformation; } else { - cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; + // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; } const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; @@ -318,7 +317,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } if (hasCCT) { - addColorTemperatureCharacteristic(this); + // addColorTemperatureCharacteristic(this); } if (!hasBrightness) { @@ -330,30 +329,28 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setupMisc() { - this.accessory.context.accessoryState = this.accessory.context.accessoryState ?? DefaultAccessoryCommand; + // this.accessory.context.accessoryState = this.accessory.context.accessoryState ?? DefaultAccessoryCommand; - const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName); - const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = _.merge({}, this.config.globalAccessoryOptions, localAccessoryOptions); + // const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName?? "unknown"); + // const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = Object.assign({}, this.config.globalAccessoryOptions, localAccessoryOptions); - this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; - this.colorOffSaturationLevel = colorOffSaturationLevel; - this.logs = new Logs(this.hbLogger, logLevel ?? 3); + // this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; + // this.colorOffSaturationLevel = colorOffSaturationLevel; + // this.logs = new Logs(this.hbLogger, logLevel ?? 3); } async fetchAndUpdateState(requestLevel) { - switch (this.deviceReadStatus) { - case ready: - this.deviceReadStatus = pending; - this.readRequestLevel = requestLevel; - await this.updateLocalState(this.readRequestLevel, null); - this.updateHomekitState(); - this.deviceReadStatus = ready; - break; - case pending: - this.readRequestLevel = Math.max(requestLevel, this.readRequestLevel); - break; + try { + + + this.readRequestLevel = requestLevel; + await this.updateLocalState(this.readRequestLevel, null); + this.updateHomekitState(); + + } catch (error) { + } } From de60f02eae758b02a8ef7c7147364686a7d4d9ca Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 13 Aug 2022 14:59:41 -0400 Subject: [PATCH 28/42] update to device controller logic --- package-lock.json | 809 +++++++++++++++++------------ package.json | 5 +- src/misc/serviceCharacteristics.ts | 8 +- src/misc/types.ts | 2 +- src/platformAccessory.ts | 8 +- 5 files changed, 500 insertions(+), 332 deletions(-) diff --git a/package-lock.json b/package-lock.json index 730acc1..0b44153 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,15 +20,14 @@ "license": "Apache-2.0", "dependencies": { "color-convert": "^2.0.1", - "homebridge-lib": "^5.1.14", - "magichome-platform": "^0.0.18" + "homebridge-lib": "^5.1.14" }, "devDependencies": { "@types/node": "^16.10.9", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", "eslint": "^8.0.1", - "homebridge": "^1.3.9", + "homebridge": "^1.5.0", "nodemon": "^2.0.13", "rimraf": "^3.0.2", "ts-node": "^10.3.0" @@ -85,10 +84,28 @@ "ciao-bcs": "lib/bonjour-conformance-testing.js" } }, - "node_modules/@homebridge/ciao/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "node_modules/@homebridge/dbus-native": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.4.1.tgz", + "integrity": "sha512-8h6MkoJykY37THOyRXWCIKpzbhIn4WWKZBunlXTH75Cb6vBcmhyIhZ3SvzqJAjJCEdhLg7wawfn7/Mpko7eREQ==", + "dev": true, + "dependencies": { + "@homebridge/long": "^5.2.1", + "event-stream": "^4.0.0", + "hexy": "^0.2.10", + "optimist": "^0.6.1", + "put": "0.0.6", + "safe-buffer": "^5.1.1", + "xml2js": "^0.4.17" + }, + "bin": { + "dbus2js": "bin/dbus2js.js" + } + }, + "node_modules/@homebridge/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", + "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", "dev": true }, "node_modules/@homebridge/plugin-ui-utils": { @@ -222,20 +239,20 @@ "dev": true }, "node_modules/@types/node": { - "version": "16.11.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.47.tgz", - "integrity": "sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g==", + "version": "16.11.48", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.48.tgz", + "integrity": "sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.32.0.tgz", - "integrity": "sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz", + "integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.32.0", - "@typescript-eslint/type-utils": "5.32.0", - "@typescript-eslint/utils": "5.32.0", + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/type-utils": "5.33.0", + "@typescript-eslint/utils": "5.33.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -261,14 +278,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.32.0.tgz", - "integrity": "sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz", + "integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.32.0", - "@typescript-eslint/types": "5.32.0", - "@typescript-eslint/typescript-estree": "5.32.0", + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/typescript-estree": "5.33.0", "debug": "^4.3.4" }, "engines": { @@ -288,13 +305,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz", - "integrity": "sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz", + "integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.32.0", - "@typescript-eslint/visitor-keys": "5.32.0" + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/visitor-keys": "5.33.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -305,12 +322,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.32.0.tgz", - "integrity": "sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz", + "integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.32.0", + "@typescript-eslint/utils": "5.33.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -331,9 +348,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz", - "integrity": "sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz", + "integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -344,13 +361,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz", - "integrity": "sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz", + "integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.32.0", - "@typescript-eslint/visitor-keys": "5.32.0", + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/visitor-keys": "5.33.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -371,15 +388,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz", - "integrity": "sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz", + "integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.32.0", - "@typescript-eslint/types": "5.32.0", - "@typescript-eslint/typescript-estree": "5.32.0", + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/typescript-estree": "5.33.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -395,12 +412,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz", - "integrity": "sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz", + "integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/types": "5.33.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -780,12 +797,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/dgram": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dgram/-/dgram-1.0.1.tgz", - "integrity": "sha512-zJVFL1EWfKtE0z2VN6qfpn/a+qG1viEzcwJA0EjtzS76ONSE3sEyWBwEbo32hS4IFw/EWVuWN+8b89aPW6It2A==", - "deprecated": "npm is holding this package for security reasons. As it's a core Node module, we will not transfer it over to other users. You may safely remove the package from your dependencies." - }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -830,10 +841,11 @@ "node": ">=6.0.0" } }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true }, "node_modules/es-abstract": { "version": "1.20.1", @@ -1121,6 +1133,21 @@ "node": ">=0.10.0" } }, + "node_modules/event-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -1252,6 +1279,12 @@ "is-callable": "^1.1.3" } }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -1439,32 +1472,26 @@ "dev": true }, "node_modules/hap-nodejs": { - "version": "0.9.8", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.9.8.tgz", - "integrity": "sha512-+IENi8nFh/yOvVZEEIgY+nVppoXgY3mN8CfRh/I9tlhDbp3rXlsjdvHFVOgk7qJNa6cwzKu0KzNUs+n3XpO1Iw==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.10.2.tgz", + "integrity": "sha512-rmCKoNoBqpcOz/wG5iTtS7JIkLjobEZj+oXGW/Z4I4eJGk14VfKjITA8plaAm6gWIZEAajASzzUdEZnIKEvzdg==", "dev": true, "dependencies": { - "@homebridge/ciao": "~1.1.3", + "@homebridge/ciao": "^1.1.4", + "@homebridge/dbus-native": "^0.4.1", "bonjour-hap": "~3.6.3", - "debug": "^4.3.2", + "debug": "^4.3.4", "fast-srp-hap": "2.0.4", - "futoin-hkdf": "~1.4.2", - "ip": "^1.1.5", + "futoin-hkdf": "~1.4.3", "node-persist": "^0.0.11", - "source-map-support": "^0.5.20", - "tslib": "^2.3.1", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0", "tweetnacl": "^1.0.3" }, "engines": { "node": ">=10.17.0" } }, - "node_modules/hap-nodejs/node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1528,19 +1555,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "dev": true, + "bin": { + "hexy": "bin/hexy_cmd.js" + } + }, "node_modules/homebridge": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.3.9.tgz", - "integrity": "sha512-/QYosrEmxao6EekPMU3la3j3qx0UWLcYQN01qbZ7s1ZrKp8aC+aShgNx1borFrY/0fHsZauGcbuNqFh+XSKNXw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.5.0.tgz", + "integrity": "sha512-0t8WNBKz9NFCab5obBfJMnxFgkg4uJZqON+iM/uZpIyiMRWH9ycCHd1pYAPMk9vDdfDu8/VpxYafWsYx6luHtg==", "dev": true, "dependencies": { "chalk": "^4.1.2", "commander": "5.1.0", - "fs-extra": "^10.0.0", - "hap-nodejs": "0.9.8", + "fs-extra": "^10.1.0", + "hap-nodejs": "^0.10.2", "qrcode-terminal": "^0.12.0", - "semver": "^7.3.5", - "source-map-support": "^0.5.20" + "semver": "^7.3.7", + "source-map-support": "^0.5.21" }, "bin": { "homebridge": "bin/homebridge" @@ -1550,9 +1586,9 @@ } }, "node_modules/homebridge-lib": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.3.tgz", - "integrity": "sha512-7X84aSayZd7YjboxoFsZ78ExfoRlZmo0t3Hasu4PL0XCILu6dqAG3Zzhqtsg/wqYTfqavvOleRInTMmFEGz6ew==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.4.tgz", + "integrity": "sha512-R0/Kv2sgXThbAZogvB/H3O2Lqqi4n8T7gCXVq8Nx5UB4gXSjkOd/+8oc9l/U9EhoD19OSXFrE8VGKZcERal+yQ==", "dependencies": { "@homebridge/plugin-ui-utils": "~0.0.19", "bonjour-hap": "^3.6.3", @@ -1971,16 +2007,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -1998,38 +2024,18 @@ "node": ">=10" } }, - "node_modules/magichome-core": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/magichome-core/-/magichome-core-0.0.19.tgz", - "integrity": "sha512-eb5mg1Lh6e+UEwfEgUhye5HkwrWggydR+rcvB9wGB7Tjn16qgzfEFYzn+sGUrTXsfH6++UCccW8PcdE/0ogHFw==", - "dependencies": { - "color-convert": "^2.0.1", - "dgram": "^1.0.1", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "promise-queue": "^2.2.5" - } - }, - "node_modules/magichome-platform": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.18.tgz", - "integrity": "sha512-LeoNlHL7W3a9JZzJ/Gw4l4c0h9L4EoLTPpDqTCuuziRooEN8UEpUNxxtcwnxIHL1aqgruSROCjLRf7cHtDERVw==", - "dependencies": { - "dgram": "^1.0.1", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "magichome-core": ">0.0.12", - "promise-queue": "^2.2.5", - "promise-retry": "^2.0.1", - "uuid": "^8.3.2" - } - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", + "dev": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2245,13 +2251,13 @@ } }, "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", + "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" }, "engines": { @@ -2270,6 +2276,22 @@ "wrappy": "1" } }, + "node_modules/optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", + "dev": true, + "dependencies": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "node_modules/optimist/node_modules/minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", + "dev": true + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -2365,6 +2387,15 @@ "node": ">=8" } }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "dependencies": { + "through": "~2.3" + } + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -2386,26 +2417,6 @@ "node": ">= 0.8.0" } }, - "node_modules/promise-queue": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", - "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -2421,6 +2432,15 @@ "node": ">=6" } }, + "node_modules/put": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz", + "integrity": "sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, "node_modules/q": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", @@ -2509,14 +2529,6 @@ "node": ">=4" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "engines": { - "node": ">= 4" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -2565,6 +2577,32 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "node_modules/semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -2662,6 +2700,28 @@ "source-map": "^0.6.0" } }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", + "dev": true, + "dependencies": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, "node_modules/string.prototype.trimend": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", @@ -2729,6 +2789,12 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -2802,9 +2868,9 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, "node_modules/tsutils": { @@ -2822,6 +2888,12 @@ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "node_modules/tweetnacl": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", @@ -2904,14 +2976,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -2996,12 +3060,43 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -3066,16 +3161,29 @@ "fast-deep-equal": "^3.1.3", "source-map-support": "^0.5.21", "tslib": "^2.4.0" - }, - "dependencies": { - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - } } }, + "@homebridge/dbus-native": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.4.1.tgz", + "integrity": "sha512-8h6MkoJykY37THOyRXWCIKpzbhIn4WWKZBunlXTH75Cb6vBcmhyIhZ3SvzqJAjJCEdhLg7wawfn7/Mpko7eREQ==", + "dev": true, + "requires": { + "@homebridge/long": "^5.2.1", + "event-stream": "^4.0.0", + "hexy": "^0.2.10", + "optimist": "^0.6.1", + "put": "0.0.6", + "safe-buffer": "^5.1.1", + "xml2js": "^0.4.17" + } + }, + "@homebridge/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", + "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", + "dev": true + }, "@homebridge/plugin-ui-utils": { "version": "0.0.19", "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", @@ -3188,20 +3296,20 @@ "dev": true }, "@types/node": { - "version": "16.11.47", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.47.tgz", - "integrity": "sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g==", + "version": "16.11.48", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.48.tgz", + "integrity": "sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.32.0.tgz", - "integrity": "sha512-CHLuz5Uz7bHP2WgVlvoZGhf0BvFakBJKAD/43Ty0emn4wXWv5k01ND0C0fHcl/Im8Td2y/7h44E9pca9qAu2ew==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz", + "integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.32.0", - "@typescript-eslint/type-utils": "5.32.0", - "@typescript-eslint/utils": "5.32.0", + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/type-utils": "5.33.0", + "@typescript-eslint/utils": "5.33.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -3211,52 +3319,52 @@ } }, "@typescript-eslint/parser": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.32.0.tgz", - "integrity": "sha512-IxRtsehdGV9GFQ35IGm5oKKR2OGcazUoiNBxhRV160iF9FoyuXxjY+rIqs1gfnd+4eL98OjeGnMpE7RF/NBb3A==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz", + "integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.32.0", - "@typescript-eslint/types": "5.32.0", - "@typescript-eslint/typescript-estree": "5.32.0", + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/typescript-estree": "5.33.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.32.0.tgz", - "integrity": "sha512-KyAE+tUON0D7tNz92p1uetRqVJiiAkeluvwvZOqBmW9z2XApmk5WSMV9FrzOroAcVxJZB3GfUwVKr98Dr/OjOg==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz", + "integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.32.0", - "@typescript-eslint/visitor-keys": "5.32.0" + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/visitor-keys": "5.33.0" } }, "@typescript-eslint/type-utils": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.32.0.tgz", - "integrity": "sha512-0gSsIhFDduBz3QcHJIp3qRCvVYbqzHg8D6bHFsDMrm0rURYDj+skBK2zmYebdCp+4nrd9VWd13egvhYFJj/wZg==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz", + "integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==", "dev": true, "requires": { - "@typescript-eslint/utils": "5.32.0", + "@typescript-eslint/utils": "5.33.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.32.0.tgz", - "integrity": "sha512-EBUKs68DOcT/EjGfzywp+f8wG9Zw6gj6BjWu7KV/IYllqKJFPlZlLSYw/PTvVyiRw50t6wVbgv4p9uE2h6sZrQ==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz", + "integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.32.0.tgz", - "integrity": "sha512-ZVAUkvPk3ITGtCLU5J4atCw9RTxK+SRc6hXqLtllC2sGSeMFWN+YwbiJR9CFrSFJ3w4SJfcWtDwNb/DmUIHdhg==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz", + "integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.32.0", - "@typescript-eslint/visitor-keys": "5.32.0", + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/visitor-keys": "5.33.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3265,26 +3373,26 @@ } }, "@typescript-eslint/utils": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.32.0.tgz", - "integrity": "sha512-W7lYIAI5Zlc5K082dGR27Fczjb3Q57ECcXefKU/f0ajM5ToM0P+N9NmJWip8GmGu/g6QISNT+K6KYB+iSHjXCQ==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz", + "integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.32.0", - "@typescript-eslint/types": "5.32.0", - "@typescript-eslint/typescript-estree": "5.32.0", + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/typescript-estree": "5.33.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "5.32.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.32.0.tgz", - "integrity": "sha512-S54xOHZgfThiZ38/ZGTgB2rqx51CMJ5MCfVT2IplK4Q7hgzGfe0nLzLCcenDnc/cSjP568hdeKfeDcBgqNHD/g==", + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz", + "integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.32.0", + "@typescript-eslint/types": "5.33.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -3565,11 +3673,6 @@ "object-keys": "^1.1.1" } }, - "dgram": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dgram/-/dgram-1.0.1.tgz", - "integrity": "sha512-zJVFL1EWfKtE0z2VN6qfpn/a+qG1viEzcwJA0EjtzS76ONSE3sEyWBwEbo32hS4IFw/EWVuWN+8b89aPW6It2A==" - }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -3602,10 +3705,11 @@ "esutils": "^2.0.2" } }, - "err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true }, "es-abstract": { "version": "1.20.1", @@ -3823,6 +3927,21 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "event-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3932,6 +4051,12 @@ "is-callable": "^1.1.3" } }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true + }, "fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -4067,29 +4192,21 @@ "dev": true }, "hap-nodejs": { - "version": "0.9.8", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.9.8.tgz", - "integrity": "sha512-+IENi8nFh/yOvVZEEIgY+nVppoXgY3mN8CfRh/I9tlhDbp3rXlsjdvHFVOgk7qJNa6cwzKu0KzNUs+n3XpO1Iw==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.10.2.tgz", + "integrity": "sha512-rmCKoNoBqpcOz/wG5iTtS7JIkLjobEZj+oXGW/Z4I4eJGk14VfKjITA8plaAm6gWIZEAajASzzUdEZnIKEvzdg==", "dev": true, "requires": { - "@homebridge/ciao": "~1.1.3", + "@homebridge/ciao": "^1.1.4", + "@homebridge/dbus-native": "^0.4.1", "bonjour-hap": "~3.6.3", - "debug": "^4.3.2", + "debug": "^4.3.4", "fast-srp-hap": "2.0.4", - "futoin-hkdf": "~1.4.2", - "ip": "^1.1.5", + "futoin-hkdf": "~1.4.3", "node-persist": "^0.0.11", - "source-map-support": "^0.5.20", - "tslib": "^2.3.1", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0", "tweetnacl": "^1.0.3" - }, - "dependencies": { - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - } } }, "has": { @@ -4131,25 +4248,31 @@ "has-symbols": "^1.0.2" } }, + "hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "dev": true + }, "homebridge": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.3.9.tgz", - "integrity": "sha512-/QYosrEmxao6EekPMU3la3j3qx0UWLcYQN01qbZ7s1ZrKp8aC+aShgNx1borFrY/0fHsZauGcbuNqFh+XSKNXw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.5.0.tgz", + "integrity": "sha512-0t8WNBKz9NFCab5obBfJMnxFgkg4uJZqON+iM/uZpIyiMRWH9ycCHd1pYAPMk9vDdfDu8/VpxYafWsYx6luHtg==", "dev": true, "requires": { "chalk": "^4.1.2", "commander": "5.1.0", - "fs-extra": "^10.0.0", - "hap-nodejs": "0.9.8", + "fs-extra": "^10.1.0", + "hap-nodejs": "^0.10.2", "qrcode-terminal": "^0.12.0", - "semver": "^7.3.5", - "source-map-support": "^0.5.20" + "semver": "^7.3.7", + "source-map-support": "^0.5.21" } }, "homebridge-lib": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.3.tgz", - "integrity": "sha512-7X84aSayZd7YjboxoFsZ78ExfoRlZmo0t3Hasu4PL0XCILu6dqAG3Zzhqtsg/wqYTfqavvOleRInTMmFEGz6ew==", + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.4.tgz", + "integrity": "sha512-R0/Kv2sgXThbAZogvB/H3O2Lqqi4n8T7gCXVq8Nx5UB4gXSjkOd/+8oc9l/U9EhoD19OSXFrE8VGKZcERal+yQ==", "requires": { "@homebridge/plugin-ui-utils": "~0.0.19", "bonjour-hap": "^3.6.3", @@ -4436,16 +4559,6 @@ "p-locate": "^5.0.0" } }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4460,38 +4573,18 @@ "yallist": "^4.0.0" } }, - "magichome-core": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/magichome-core/-/magichome-core-0.0.19.tgz", - "integrity": "sha512-eb5mg1Lh6e+UEwfEgUhye5HkwrWggydR+rcvB9wGB7Tjn16qgzfEFYzn+sGUrTXsfH6++UCccW8PcdE/0ogHFw==", - "requires": { - "color-convert": "^2.0.1", - "dgram": "^1.0.1", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "promise-queue": "^2.2.5" - } - }, - "magichome-platform": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/magichome-platform/-/magichome-platform-0.0.18.tgz", - "integrity": "sha512-LeoNlHL7W3a9JZzJ/Gw4l4c0h9L4EoLTPpDqTCuuziRooEN8UEpUNxxtcwnxIHL1aqgruSROCjLRf7cHtDERVw==", - "requires": { - "dgram": "^1.0.1", - "lodash": "^4.17.21", - "lodash.debounce": "^4.0.8", - "magichome-core": ">0.0.12", - "promise-queue": "^2.2.5", - "promise-retry": "^2.0.1", - "uuid": "^8.3.2" - } - }, "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4653,13 +4746,13 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", + "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", "object-keys": "^1.1.1" } }, @@ -4672,6 +4765,24 @@ "wrappy": "1" } }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", + "dev": true + } + } + }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -4737,6 +4848,15 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "requires": { + "through": "~2.3" + } + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -4749,20 +4869,6 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, - "promise-queue": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", - "integrity": "sha512-p/iXrPSVfnqPft24ZdNNLECw/UrtLTpT3jpAAMzl/o5/rDsGCPo3/CQS2611flL6LkoEJ3oQZw7C8Q80ZISXRQ==" - }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, "pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -4775,6 +4881,12 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, + "put": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz", + "integrity": "sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==", + "dev": true + }, "q": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", @@ -4824,11 +4936,6 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" - }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -4853,6 +4960,18 @@ "queue-microtask": "^1.2.2" } }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "semver": { "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", @@ -4925,6 +5044,25 @@ "source-map": "^0.6.0" } }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "requires": { + "through": "2" + } + }, + "stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", + "dev": true, + "requires": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, "string.prototype.trimend": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", @@ -4974,6 +5112,12 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", @@ -5019,9 +5163,9 @@ } }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", "dev": true }, "tsutils": { @@ -5031,6 +5175,14 @@ "dev": true, "requires": { "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "tweetnacl": { @@ -5093,11 +5245,6 @@ "punycode": "^2.1.0" } }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -5161,12 +5308,34 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "dev": true + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 7d3f8b4..ca4d661 100644 --- a/package.json +++ b/package.json @@ -62,15 +62,14 @@ ], "dependencies": { "color-convert": "^2.0.1", - "homebridge-lib": "^5.1.14", - "magichome-platform": "^0.0.18" + "homebridge-lib": "^5.1.14" }, "devDependencies": { "@types/node": "^16.10.9", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", "eslint": "^8.0.1", - "homebridge": "^1.3.9", + "homebridge": "^1.5.0", "nodemon": "^2.0.13", "rimraf": "^3.0.2", "ts-node": "^10.3.0" diff --git a/src/misc/serviceCharacteristics.ts b/src/misc/serviceCharacteristics.ts index 6d58778..a8b78b2 100644 --- a/src/misc/serviceCharacteristics.ts +++ b/src/misc/serviceCharacteristics.ts @@ -47,10 +47,10 @@ export function addColorTemperatureCharacteristic(_this) { export function addAccessoryInformationCharacteristic(_this) { - // const { - // protoDevice: { uniqueId, modelNumber }, - // // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, - // } = _this.accessory.context.cachedDeviceInformation; + const { + protoDevice: { uniqueId, modelNumber }, + deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, + } = _this.accessory.context.cachedDeviceInformation; // set accessory information _this.accessory.getService(_this.hap.Service.AccessoryInformation)! .setCharacteristic(_this.hap.Characteristic.Manufacturer, 'MagicHome') diff --git a/src/misc/types.ts b/src/misc/types.ts index 45a6f6a..35b3321 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -32,7 +32,7 @@ export interface IAccessoryContext { displayName?: string; restartsSinceSeen: number, accessoryState?: IAccessoryState; - // cachedDeviceInformation: IDeviceInformation; + cachedDeviceInformation: IDeviceInformation; } export interface IAccessoryState { diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index bfd2b16..5de92d2 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -234,7 +234,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async updateLocalState(requestLevel, deviceState) { if (!deviceState) { - deviceState = await this.controller?.fetchState() + deviceState = await this.controller?.fetchState() // ?? this.accessory.context.cachedDeviceInformation.deviceState; } this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); @@ -295,9 +295,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { let cachedDeviceInformation = this.controller?.getCachedDeviceInformation(); if (cachedDeviceInformation) { - // this.accessory.context.cachedDeviceInformation = cachedDeviceInformation; + this.accessory.context.cachedDeviceInformation = cachedDeviceInformation; } else { - // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; + cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; } const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; @@ -329,7 +329,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setupMisc() { - // this.accessory.context.accessoryState = this.accessory.context.accessoryState ?? DefaultAccessoryCommand; + this.accessory.context.accessoryState = this.accessory.context.accessoryState ?? DefaultAccessoryCommand; // const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName?? "unknown"); // const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = Object.assign({}, this.config.globalAccessoryOptions, localAccessoryOptions); From 4f0d3cd730a2183fa88bf1cd5a4a0e52f7af13ed Mon Sep 17 00:00:00 2001 From: Chocotapi Date: Sun, 14 Aug 2022 10:36:35 -0400 Subject: [PATCH 29/42] updating generator --- package-lock.json | 3185 +------------------------------------ package.json | 3 +- src/AccessoryGenerator.ts | 64 +- src/misc/types.ts | 10 +- 4 files changed, 71 insertions(+), 3191 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0b44153..72ed01c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,3129 +1,8 @@ { "name": "homebridge-magichome-dynamic-platform", "version": "1.9.3-beta.4", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "homebridge-magichome-dynamic-platform", - "version": "1.9.3-beta.4", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/Zacknetic" - }, - { - "type": "paypal", - "url": "https://www.paypal.com/paypalme/ZacharyAvino" - } - ], - "license": "Apache-2.0", - "dependencies": { - "color-convert": "^2.0.1", - "homebridge-lib": "^5.1.14" - }, - "devDependencies": { - "@types/node": "^16.10.9", - "@typescript-eslint/eslint-plugin": "^5.0.0", - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^8.0.1", - "homebridge": "^1.5.0", - "nodemon": "^2.0.13", - "rimraf": "^3.0.2", - "ts-node": "^10.3.0" - }, - "engines": { - "homebridge": ">=1.0.0", - "node": ">=10.17.0" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.3.2", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@homebridge/ciao": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", - "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0" - }, - "bin": { - "ciao-bcs": "lib/bonjour-conformance-testing.js" - } - }, - "node_modules/@homebridge/dbus-native": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.4.1.tgz", - "integrity": "sha512-8h6MkoJykY37THOyRXWCIKpzbhIn4WWKZBunlXTH75Cb6vBcmhyIhZ3SvzqJAjJCEdhLg7wawfn7/Mpko7eREQ==", - "dev": true, - "dependencies": { - "@homebridge/long": "^5.2.1", - "event-stream": "^4.0.0", - "hexy": "^0.2.10", - "optimist": "^0.6.1", - "put": "0.0.6", - "safe-buffer": "^5.1.1", - "xml2js": "^0.4.17" - }, - "bin": { - "dbus2js": "bin/dbus2js.js" - } - }, - "node_modules/@homebridge/long": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", - "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", - "dev": true - }, - "node_modules/@homebridge/plugin-ui-utils": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", - "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/json-schema": { - "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": "16.11.48", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.48.tgz", - "integrity": "sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz", - "integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/type-utils": "5.33.0", - "@typescript-eslint/utils": "5.33.0", - "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz", - "integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/typescript-estree": "5.33.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz", - "integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/visitor-keys": "5.33.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz", - "integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "5.33.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz", - "integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz", - "integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/visitor-keys": "5.33.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz", - "integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/typescript-estree": "5.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz", - "integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.33.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bonjour-hap": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.3.tgz", - "integrity": "sha512-qyLU96ICCYbpOFiMCjA3aNYH5Jc83XH1YX6+EXWukyyiNXzXH2LZv8AVmGW33FceF3gfUM4jYoKX2xChtNDUnA==", - "dependencies": { - "array-flatten": "^2.1.2", - "deep-equal": "^2.0.5", - "ip": "^1.1.5", - "multicast-dns": "^7.2.3", - "multicast-dns-service-types": "^1.1.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-equal": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", - "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", - "dependencies": { - "call-bind": "^1.0.0", - "es-get-iterator": "^1.1.1", - "get-intrinsic": "^1.0.1", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.1.1", - "isarray": "^2.0.5", - "object-is": "^1.1.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3", - "which-boxed-primitive": "^1.0.1", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-packet": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", - "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", - "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", - "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", - "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-srp-hap": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", - "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/futoin-hkdf": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", - "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/hap-nodejs": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.10.2.tgz", - "integrity": "sha512-rmCKoNoBqpcOz/wG5iTtS7JIkLjobEZj+oXGW/Z4I4eJGk14VfKjITA8plaAm6gWIZEAajASzzUdEZnIKEvzdg==", - "dev": true, - "dependencies": { - "@homebridge/ciao": "^1.1.4", - "@homebridge/dbus-native": "^0.4.1", - "bonjour-hap": "~3.6.3", - "debug": "^4.3.4", - "fast-srp-hap": "2.0.4", - "futoin-hkdf": "~1.4.3", - "node-persist": "^0.0.11", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0", - "tweetnacl": "^1.0.3" - }, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hexy": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", - "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", - "dev": true, - "bin": { - "hexy": "bin/hexy_cmd.js" - } - }, - "node_modules/homebridge": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.5.0.tgz", - "integrity": "sha512-0t8WNBKz9NFCab5obBfJMnxFgkg4uJZqON+iM/uZpIyiMRWH9ycCHd1pYAPMk9vDdfDu8/VpxYafWsYx6luHtg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "commander": "5.1.0", - "fs-extra": "^10.1.0", - "hap-nodejs": "^0.10.2", - "qrcode-terminal": "^0.12.0", - "semver": "^7.3.7", - "source-map-support": "^0.5.21" - }, - "bin": { - "homebridge": "bin/homebridge" - }, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/homebridge-lib": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.4.tgz", - "integrity": "sha512-R0/Kv2sgXThbAZogvB/H3O2Lqqi4n8T7gCXVq8Nx5UB4gXSjkOd/+8oc9l/U9EhoD19OSXFrE8VGKZcERal+yQ==", - "dependencies": { - "@homebridge/plugin-ui-utils": "~0.0.19", - "bonjour-hap": "^3.6.3", - "chalk": "^4.1.2", - "semver": "^7.3.7" - }, - "bin": { - "hap": "cli/hap.js", - "json": "cli/json.js", - "sysinfo": "cli/sysinfo.js", - "upnp": "cli/upnp.js" - }, - "engines": { - "homebridge": "^1.5.0", - "node": "^16.16.0" - } - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", - "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "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.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/mkdirp": { - "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.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-persist": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", - "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", - "dev": true, - "dependencies": { - "mkdirp": "~0.5.1", - "q": "~1.1.1" - } - }, - "node_modules/nodemon": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", - "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", - "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", - "dev": true, - "dependencies": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "node_modules/optimist/node_modules/minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "dev": true, - "dependencies": { - "through": "~2.3" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/put": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz", - "integrity": "sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==", - "dev": true, - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/q": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", - "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qrcode-terminal": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", - "dev": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-update-notifier": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", - "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", - "dev": true, - "dependencies": { - "semver": "~7.0.0" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", - "dev": true, - "dependencies": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true, - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", - "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, "dependencies": { "@cspotcode/source-map-support": { "version": "0.8.1", @@ -3412,8 +291,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "8.2.0", @@ -3607,7 +485,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "create-require": { @@ -3981,7 +859,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, "fast-srp-hap": { @@ -4071,7 +949,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "fsevents": { @@ -4100,7 +978,7 @@ "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, "functions-have-names": { @@ -4289,7 +1167,7 @@ "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, "import-fresh": { @@ -4305,13 +1183,13 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "^1.3.0", @@ -4390,7 +1268,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, "is-glob": { @@ -4506,7 +1384,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "js-yaml": { @@ -4527,7 +1405,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, "jsonfile": { @@ -4611,9 +1489,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", "dev": true }, "mkdirp": { @@ -4623,6 +1501,14 @@ "dev": true, "requires": { "minimist": "^1.2.6" + }, + "dependencies": { + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + } } }, "ms": { @@ -4643,12 +1529,12 @@ "multicast-dns-service-types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==" + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, "node-persist": { @@ -4714,7 +1600,7 @@ "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, "requires": { "abbrev": "1" @@ -4759,7 +1645,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1" @@ -4773,14 +1659,6 @@ "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true - } } }, "optionator": { @@ -4833,7 +1711,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { @@ -5109,7 +1987,7 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, "through": { @@ -5210,8 +2088,7 @@ "version": "4.7.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true, - "peer": true + "dev": true }, "unbox-primitive": { "version": "1.0.2", @@ -5317,7 +2194,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "xml2js": { diff --git a/package.json b/package.json index ca4d661..be5518c 100644 --- a/package.json +++ b/package.json @@ -72,6 +72,7 @@ "homebridge": "^1.5.0", "nodemon": "^2.0.13", "rimraf": "^3.0.2", - "ts-node": "^10.3.0" + "ts-node": "^10.3.0", + "typescript": "^4.4.4" } } diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index d53ff66..fa2f406 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -1,6 +1,6 @@ import { BaseController, ControllerGenerator, ICustomProtoDevice, IDeviceAPI, ICompleteDevice, IProtoDevice, ICustomCompleteDevice } from 'magichome-platform'; import { IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; -import { API, HAP, PlatformAccessory, PlatformConfig, } from 'homebridge'; +import { API, HAP, PlatformAccessory, PlatformConfig } from 'homebridge'; import { homekitInterface } from './misc/types'; import { Logs } from './logs'; @@ -39,7 +39,7 @@ export class AccessoryGenerator { await this.generateActiveAccessories(controllers); this.registerOfflineAccessories(); } catch (error) { - this.logs.error(error) + this.logs.error(error); } } @@ -101,7 +101,7 @@ export class AccessoryGenerator { this.activeAccessoriesMap.set(uniqueId, currAccessory); } catch (error) { - this.logs.error(error) + this.logs.error(error); } } @@ -127,17 +127,17 @@ export class AccessoryGenerator { createNewAccessory(controller: BaseController) { const cachedDeviceInformation = controller.getCachedDeviceInformation(); - const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; + const { protoDevice: { uniqueId }, protoDevice, deviceAPI: { description }, completeDevice: { completeResponse: { deviceMetaData } } } = cachedDeviceInformation; // console.log(description); // console.log(uniqueId) if (!this.isAllowed(uniqueId)) { return; } const homebridgeUUID = this.hap.uuid.generate(uniqueId); - console.log(homebridgeUUID) + // console.log(homebridgeUUID); const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; // console.log(newAccessory) - newAccessory.context = { displayName: description as string, restartsSinceSeen: 0 }; + newAccessory.context = { displayName: description as string, restartsSinceSeen: 0, deviceMetaData, protoDevice, latestUpdate: Date.now() }; new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); return newAccessory; @@ -163,32 +163,32 @@ export class AccessoryGenerator { } registerOfflineAccessories() { - // const offlineAccessoriesList: MagicHomeAccessory[] = []; - // const completeDevices: ICustomCompleteDevice[] = [] - // this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { - // const { deviceState, deviceAPI, deviceAPI: { description }, completeDevice } = offlineAccessory.context.cachedDeviceInformation; - // const { protoDevice, completeResponse, latestUpdate } = completeDevice; - // completeDevices.push({ customProtoDevice: protoDevice, completeResponse, latestUpdate }); - // }); - - // const controllers = this.controllerGenerator.generateCustomControllers(completeDevices); - - // for (const controller of controllers) { - // try { - // const { protoDevice: { uniqueId } } = controller.getCachedDeviceInformation(); - // if (this.accessoriesFromDiskMap.has(uniqueId)) { - // const offlineAccessory = this.accessoriesFromDiskMap.get(uniqueId); - // this.accessoriesFromDiskMap.delete(uniqueId); - // this.processOfflineAccessory(offlineAccessory, controller); - // offlineAccessoriesList.push(offlineAccessory); - // this.cachedAccessoriesMap.set(offlineAccessory.context.cachedDeviceInformation.protoDevice.uniqueId, offlineAccessory); - // } - // } catch (error) { - // this.logs.error(error); - // } - // } - - // this.updateExistingAccessories(offlineAccessoriesList); + const offlineAccessoriesList: MagicHomeAccessory[] = []; + const completeDevices: ICustomCompleteDevice[] = []; + this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { + const { displayName, deviceMetaData, protoDevice, latestUpdate} = offlineAccessory.context; + const customCompleteDevice: ICustomCompleteDevice = {customProtoDevice: protoDevice }; + completeDevices.push({ customProtoDevice: protoDevice, latestUpdate }); + }); + + const controllers = this.controllerGenerator.generateCustomControllers(completeDevices); + + for (const controller of controllers) { + try { + const { protoDevice: { uniqueId } } = controller.getCachedDeviceInformation(); + if (this.accessoriesFromDiskMap.has(uniqueId)) { + const offlineAccessory = this.accessoriesFromDiskMap.get(uniqueId); + this.accessoriesFromDiskMap.delete(uniqueId); + this.processOfflineAccessory(offlineAccessory, controller); + offlineAccessoriesList.push(offlineAccessory); + this.cachedAccessoriesMap.set(offlineAccessory.context.cachedDeviceInformation.protoDevice.uniqueId, offlineAccessory); + } + } catch (error) { + this.logs.error(error); + } + } + + this.updateExistingAccessories(offlineAccessoriesList); } processOfflineAccessory(offlineAccessory: MagicHomeAccessory, controller: BaseController) { diff --git a/src/misc/types.ts b/src/misc/types.ts index 35b3321..f412d57 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -1,5 +1,5 @@ import type { PlatformAccessory } from 'homebridge'; -import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation } from 'magichome-platform'; +import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation, IDeviceMetaData, IProtoDevice } from 'magichome-platform'; import { Switch } from '../accessories/Switch'; import { DimmerStrip } from '../accessories/DimmerStrip'; @@ -30,9 +30,11 @@ export interface MagicHomeAccessory extends PlatformAccessory { export interface IAccessoryContext { displayName?: string; - restartsSinceSeen: number, - accessoryState?: IAccessoryState; - cachedDeviceInformation: IDeviceInformation; + restartsSinceSeen: number; + accessoryState?: IAccessoryState; //--todo REMOVE and ReLogic + deviceMetaData: IDeviceMetaData; + protoDevice: IProtoDevice; + latestUpdate: number; } export interface IAccessoryState { From 270dbf689ef9a9aaff89208cdf651ea0452d7210 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Thu, 18 Aug 2022 19:22:36 -0400 Subject: [PATCH 30/42] logic shift to platform and core --- .homebridge-dev/config.json | 2 +- src/AccessoryGenerator.ts | 61 ++- src/logs.ts | 2 +- src/misc/serviceCharacteristics.ts | 120 ----- src/misc/types.ts | 4 +- src/platform.ts | 218 ++++---- src/platformAccessory.ts | 839 ++++++++++++++++------------- src/settings.ts | 1 + 8 files changed, 622 insertions(+), 625 deletions(-) diff --git a/.homebridge-dev/config.json b/.homebridge-dev/config.json index 321799d..8f0b928 100644 --- a/.homebridge-dev/config.json +++ b/.homebridge-dev/config.json @@ -1,7 +1,7 @@ { "bridge": { "name": "HomebridgeDev", - "username": "CC:BB:DD:DD:FF:GG", + "username": "DD:BB:DD:DD:FF:GG", "manufacturer": "homebridge.io", "model": "homebridge", "port": 51826, diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index fa2f406..d740c5b 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -1,9 +1,10 @@ -import { BaseController, ControllerGenerator, ICustomProtoDevice, IDeviceAPI, ICompleteDevice, IProtoDevice, ICustomCompleteDevice } from 'magichome-platform'; +import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep } from 'magichome-platform'; import { IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; import { API, HAP, PlatformAccessory, PlatformConfig } from 'homebridge'; import { homekitInterface } from './misc/types'; import { Logs } from './logs'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; @@ -35,9 +36,11 @@ export class AccessoryGenerator { try { const completeDevices: ICompleteDevice[] = await this.controllerGenerator.discoverCompleteDevices(); + + const controllers: BaseController[] = await this.controllerGenerator.generateControllers(completeDevices); await this.generateActiveAccessories(controllers); - this.registerOfflineAccessories(); + // this.registerOfflineAccessories(); } catch (error) { this.logs.error(error); } @@ -84,16 +87,14 @@ export class AccessoryGenerator { const { protoDevice: { uniqueId }, deviceState, deviceAPI } = controller.getCachedDeviceInformation(); let currAccessory: MagicHomeAccessory; - // if (this.accessoriesFromDiskMap.has(uniqueId)) { - // const existingAccessory = this.accessoriesFromDiskMap.get(uniqueId); - // this.accessoriesFromDiskMap.delete(uniqueId); - // this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); - // currAccessory = this.processOnlineAccessory(controller, existingAccessory); - // existingAccessoriesList.push(currAccessory); + if (this.accessoriesFromDiskMap.has(uniqueId)) { + const existingAccessory = this.accessoriesFromDiskMap.get(uniqueId); + this.accessoriesFromDiskMap.delete(uniqueId); + this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); + currAccessory = this.processOnlineAccessory(controller, existingAccessory); + existingAccessoriesList.push(currAccessory); - // } - // else - if (!this.activeAccessoriesMap.has(uniqueId)) { //if the accessory is not a duplicate active device + } else if (!this.activeAccessoriesMap.has(uniqueId)) { //if the accessory is not a duplicate active device currAccessory = this.createNewAccessory(controller); // this.logs.info(`[${currAccessory.context.displayName}] - Found new accessory. Registering...`); newAccessoriesList.push(currAccessory); //add it to new accessory list @@ -106,7 +107,7 @@ export class AccessoryGenerator { } this.registerNewAccessories(newAccessoriesList); //register new accessories from scan - // this.updateExistingAccessories(existingAccessoriesList); + this.updateExistingAccessories(existingAccessoriesList); } @@ -127,7 +128,7 @@ export class AccessoryGenerator { createNewAccessory(controller: BaseController) { const cachedDeviceInformation = controller.getCachedDeviceInformation(); - const { protoDevice: { uniqueId }, protoDevice, deviceAPI: { description }, completeDevice: { completeResponse: { deviceMetaData } } } = cachedDeviceInformation; + const { protoDevice: { uniqueId }, protoDevice, deviceAPI: { description }, deviceMetaData } = cachedDeviceInformation; // console.log(description); // console.log(uniqueId) if (!this.isAllowed(uniqueId)) { @@ -137,8 +138,9 @@ export class AccessoryGenerator { // console.log(homebridgeUUID); const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; // console.log(newAccessory) - newAccessory.context = { displayName: description as string, restartsSinceSeen: 0, deviceMetaData, protoDevice, latestUpdate: Date.now() }; - new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); + newAccessory.context = { displayName: description as string, deviceMetaData, protoDevice, latestUpdate: Date.now() }; + // new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); + new HomebridgeMagichomeDynamicPlatformAccessory(this.api, newAccessory, this.config, controller, this.hbLogger, this.logs) return newAccessory; @@ -146,32 +148,33 @@ export class AccessoryGenerator { processOnlineAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { - const cachedDeviceInformation = controller.getCachedDeviceInformation(); - const { protoDevice: { uniqueId }, deviceAPI: { description } } = cachedDeviceInformation; - if (!this.isAllowed(uniqueId)) { - throw new Error(`[Error] [${existingAccessory.context.displayName}] - Accessory is not allowed. Skipping...`); - } + const { protoDevice, deviceAPI: { description }, deviceMetaData } = controller.getCachedDeviceInformation(); + + // if (!this.isAllowed(uniqueId)) { + // // throw new Error(`[Error] [${existingAccessory.context.displayName}] - Accessory is not allowed. Skipping...`); + // } - existingAccessory.context = Object.assign({}, existingAccessory.context, { cachedDeviceInformation, restartsSinceSeen: 0 }); + overwriteDeep(existingAccessory.context, { protoDevice, deviceMetaData, latestUpdate: Date.now()}); try { - new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); + new HomebridgeMagichomeDynamicPlatformAccessory(this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs) + // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); } catch (error) { - throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); + // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); } return existingAccessory; } registerOfflineAccessories() { const offlineAccessoriesList: MagicHomeAccessory[] = []; - const completeDevices: ICustomCompleteDevice[] = []; + const completeDevicesInfo: ICompleteDeviceInfo[] = []; this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { - const { displayName, deviceMetaData, protoDevice, latestUpdate} = offlineAccessory.context; - const customCompleteDevice: ICustomCompleteDevice = {customProtoDevice: protoDevice }; - completeDevices.push({ customProtoDevice: protoDevice, latestUpdate }); + const { displayName, deviceMetaData, protoDevice, latestUpdate } = offlineAccessory.context; + const completeDeviceInfo: ICompleteDeviceInfo = { protoDevice, deviceMetaData, latestUpdate }; + completeDevicesInfo.push(completeDeviceInfo); }); - const controllers = this.controllerGenerator.generateCustomControllers(completeDevices); + const controllers = this.controllerGenerator.generateCustomControllers(completeDevicesInfo); for (const controller of controllers) { try { @@ -181,7 +184,7 @@ export class AccessoryGenerator { this.accessoriesFromDiskMap.delete(uniqueId); this.processOfflineAccessory(offlineAccessory, controller); offlineAccessoriesList.push(offlineAccessory); - this.cachedAccessoriesMap.set(offlineAccessory.context.cachedDeviceInformation.protoDevice.uniqueId, offlineAccessory); + this.cachedAccessoriesMap.set(uniqueId, offlineAccessory); } } catch (error) { this.logs.error(error); diff --git a/src/logs.ts b/src/logs.ts index aebc78b..53075c2 100644 --- a/src/logs.ts +++ b/src/logs.ts @@ -2,7 +2,7 @@ import { Logging } from 'homebridge'; export class Logs { constructor(private hbLogger: Logging, private readonly level = 3) { - logs = this; + // logs = this; this.level = level; } diff --git a/src/misc/serviceCharacteristics.ts b/src/misc/serviceCharacteristics.ts index a8b78b2..e69de29 100644 --- a/src/misc/serviceCharacteristics.ts +++ b/src/misc/serviceCharacteristics.ts @@ -1,120 +0,0 @@ -import { CharacteristicEventTypes } from 'homebridge'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -/*-------------------------- Characteristics -------------------------------------*/ - -export function addOnCharacteristic(_this) { - _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding On characteristic to service.`); - _this.service.getCharacteristic(_this.hap.Characteristic.On) - .onSet(_this.setOn.bind(_this)) - .onGet(_this.getOn.bind(_this)); -} - -export function addHueCharacteristic(_this) { - _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Hue characteristic to service.`); - _this.service.getCharacteristic(_this.hap.Characteristic.Hue) - .onSet(_this.setHue.bind(_this)) - .onGet(_this.getHue.bind(_this)); -} - -export function addSaturationCharacteristic(_this) { - _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); - _this.service.getCharacteristic(_this.hap.Characteristic.Saturation) - .onSet(_this.setSaturation.bind(_this)); - // .onGet(_this.CHANGE_ME.bind(_this)); - -} - -export function addBrightnessCharacteristic(_this) { - _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); - _this.service.getCharacteristic(_this.hap.Characteristic.Brightness) - .onSet(_this.setBrightness.bind(_this)) - .onGet(_this.getBrightness.bind(_this)); -} - -export function addColorTemperatureCharacteristic(_this) { - _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); - _this.service.getCharacteristic(_this.hap.Characteristic.ColorTemperature) - .onSet(_this.setColorTemperature.bind(_this)) - .onGet(_this.getColorTemperature.bind(_this)); - - if (_this.api.versionGreaterOrEqual && _this.api.versionGreaterOrEqual('1.3.0-beta.46')) { - _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); - _this.adaptiveLightingService = new _this.api.hap.AdaptiveLightingController(_this.service); - _this.accessory.configureController(_this.adaptiveLightingService); - } -} - -export function addAccessoryInformationCharacteristic(_this) { - - const { - protoDevice: { uniqueId, modelNumber }, - deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, - } = _this.accessory.context.cachedDeviceInformation; - // set accessory information - _this.accessory.getService(_this.hap.Service.AccessoryInformation)! - .setCharacteristic(_this.hap.Characteristic.Manufacturer, 'MagicHome') - // .setCharacteristic(_this.hap.Characteristic.SerialNumber, uniqueId) - // .setCharacteristic(_this.hap.Characteristic.Model, modelNumber) - // .setCharacteristic(_this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') - // .setCharacteristic(_this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') - .getCharacteristic(_this.hap.Characteristic.Identify) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, _this.identifyLight.bind(_this)); // SET - bind to the 'Identify` method below - - - _this.accessory.getService(_this.hap.Service.AccessoryInformation)! - .addOptionalCharacteristic(_this.hap.Characteristic.ConfiguredName); -} - -export function addConfiguredNameCharacteristic(_this) { - if (!_this.service.testCharacteristic(_this.hap.Characteristic.ConfiguredName)) { - _this.service.addCharacteristic(_this.hap.Characteristic.ConfiguredName) - .onSet(_this.setConfiguredName.bind(_this)); - } else { - _this.service.getCharacteristic(_this.hap.Characteristic.ConfiguredName) - .onSet(_this.setConfiguredName.bind(_this)); - } - _this.logs.trace(`[Trace] [${_this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); - -} - - -/* - // Add the garage door service if it doesn't already exist - this.service = - this.accessory.getService(this.hapServ.GarageDoorOpener) || - this.accessory.addService(this.hapServ.GarageDoorOpener) - - // Add some extra Eve characteristics - if (!this.service.testCharacteristic(this.eveChar.LastActivation)) { - this.service.addCharacteristic(this.eveChar.LastActivation) - } - if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) { - this.service.addCharacteristic(this.eveChar.ResetTotal) - } - if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) { - this.service.addCharacteristic(this.eveChar.TimesOpened) - } - - // Add the set handler to the garage door target state characteristic - this.service - .getCharacteristic(this.hapChar.TargetDoorState) - .onSet(value => this.internalTargetUpdate(value)) - this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value - this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value - - // Add the set handler to the garage door reset total characteristic - this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { - this.service.updateCharacteristic(this.eveChar.TimesOpened, 0) - }) - - // Update the obstruction detected to false on plugin load - this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false) - - // Pass the accessory to Fakegato to set up with Eve - this.accessory.eveService = new platform.eveService('door', this.accessory, { - log: platform.config.debugFakegato ? this.log : () => {} - }) - */ \ No newline at end of file diff --git a/src/misc/types.ts b/src/misc/types.ts index f412d57..8512664 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -30,8 +30,6 @@ export interface MagicHomeAccessory extends PlatformAccessory { export interface IAccessoryContext { displayName?: string; - restartsSinceSeen: number; - accessoryState?: IAccessoryState; //--todo REMOVE and ReLogic deviceMetaData: IDeviceMetaData; protoDevice: IProtoDevice; latestUpdate: number; @@ -41,7 +39,7 @@ export interface IAccessoryState { isOn: boolean, HSL: IColorHSL, colorTemperature?: number, - brightness?: number, + brightness: number, } export interface IAccessoryCommand { diff --git a/src/platform.ts b/src/platform.ts index 8719bd9..43bc386 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -1,110 +1,110 @@ -import { join } from 'path'; -import { loadJson } from './misc/utils'; -import { Logs } from './logs'; -import { - API, - APIEvent, - DynamicPlatformPlugin, - HAP, - Logging, - PlatformConfig, -} from 'homebridge'; - -import { ControllerGenerator } from 'magichome-platform'; - -import { MagicHomeAccessory } from './misc/types'; -import { AccessoryGenerator } from './AccessoryGenerator'; -/** - */ - -const controllerGenerator = new ControllerGenerator(); -let hap: HAP; - -/** - * HomebridgePlatform - * This class is the main constructor for your plugin, this is where you should - * parse the user config and discover/register accessories with Homebridge. - */ -export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { - private log; - private readonly api: API; - // this is used to track restored cached accessories - - - public count = 1; - - private periodicDiscovery: NodeJS.Timeout | null = null; - - public readonly config: PlatformConfig; - public readonly accessoriesFromDiskMap: Map = new Map(); - private readonly hbLogger: Logging; - constructor( - logging: Logging, - config: PlatformConfig, - api: API, - ) { - this.hbLogger = logging; - hap = api.hap; - this.config = config; - this.log = new Logs(logging, config?.globalAccessoryOptions?.logLevel ?? 3); - this.api = api; - //this.logs = getLogger(); - this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); - this.log.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); - - // When this event is fired it means Homebridge has restored all cached accessories from disk. - // Dynamic Platform plugins should only register new accessories after this event was fired, - // in order to ensure they weren't added to homebridge already. This event can also be used - // to start discovery of new accessories. - - api.on(APIEvent.DID_FINISH_LAUNCHING, () => { - this.log.debug('Homebridge Magichome Dynamic Platform didFinishLaunching'); - this.initializePlatform(); - }); - } - - - /** - * This function is invoked when homebridge restores cached accessories from disk at startup. - * It should be used to setup event handlers for characteristics and update respective values. - */ - configureAccessory(accessory: MagicHomeAccessory) { - // set cached accessory as not recently seen - // if found later to be a match with a discovered device, will change to true - // accessory.context.scansSinceSeen++; - // accessory.context.pendingRegistration = true; - // // add the restored accessory to the accessories cache so we can track if it has already been registered - - const homebridgeUUID = accessory.UUID; - this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); - this.log.debug(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); - - } - - /** - * Accessories are added by one of three Methods: - * Method One: New devices that were seen after scanning the network and are registered for the first time - * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies - * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user - */ - async initializePlatform() { - // const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; - // const pendingUpdate = new Set(); - // const recentlyRegisteredDevices = new Set(); - - // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - - - const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); - await accesssoryGenerator.discoverDevices(); - // this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); - - } - - - // sanitizeConfig() { - // //recursive config sanitation - // } - - +import { join } from 'path'; +import { loadJson } from './misc/utils'; +import { Logs } from './logs'; +import { + API, + APIEvent, + DynamicPlatformPlugin, + HAP, + Logging, + PlatformConfig, +} from 'homebridge'; + +import { ControllerGenerator } from 'magichome-platform'; + +import { MagicHomeAccessory } from './misc/types'; +import { AccessoryGenerator } from './AccessoryGenerator'; +/** + */ + +const controllerGenerator = new ControllerGenerator(); +let hap: HAP; + +/** + * HomebridgePlatform + * This class is the main constructor for your plugin, this is where you should + * parse the user config and discover/register accessories with Homebridge. + */ +export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { + private readonly api: API; + // this is used to track restored cached accessories + + + public count = 1; + + private periodicDiscovery: NodeJS.Timeout | null = null; + + public readonly config: PlatformConfig; + public readonly accessoriesFromDiskMap: Map = new Map(); + private readonly hbLogger: Logging; + private readonly log: Logs; + constructor( + logging: Logging, + config: PlatformConfig, + api: API, + ) { + this.hbLogger = logging; + hap = api.hap; + this.config = config; + this.log = new Logs(logging, config?.globalAccessoryOptions?.logLevel ?? 3); + this.api = api; + //this.logs = getLogger(); + this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); + this.log.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); + + // When this event is fired it means Homebridge has restored all cached accessories from disk. + // Dynamic Platform plugins should only register new accessories after this event was fired, + // in order to ensure they weren't added to homebridge already. This event can also be used + // to start discovery of new accessories. + + api.on(APIEvent.DID_FINISH_LAUNCHING, () => { + this.log.debug('Homebridge Magichome Dynamic Platform didFinishLaunching'); + this.initializePlatform(); + }); + } + + + /** + * This function is invoked when homebridge restores cached accessories from disk at startup. + * It should be used to setup event handlers for characteristics and update respective values. + */ + configureAccessory(accessory: MagicHomeAccessory) { + // set cached accessory as not recently seen + // if found later to be a match with a discovered device, will change to true + // accessory.context.scansSinceSeen++; + // accessory.context.pendingRegistration = true; + // // add the restored accessory to the accessories cache so we can track if it has already been registered + + const homebridgeUUID = accessory.context.protoDevice.uniqueId; + this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); + this.log.info(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); + + } + + /** + * Accessories are added by one of three Methods: + * Method One: New devices that were seen after scanning the network and are registered for the first time + * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies + * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user + */ + async initializePlatform() { + // const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; + // const pendingUpdate = new Set(); + // const recentlyRegisteredDevices = new Set(); + + // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; + + + const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); + await accesssoryGenerator.discoverDevices(); + // this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); + + } + + + // sanitizeConfig() { + // //recursive config sanitation + // } + + }//ZackneticMagichomePlatform class \ No newline at end of file diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 5de92d2..433bdeb 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -1,363 +1,478 @@ -import type { - API, Service, PlatformConfig, CharacteristicValue, - CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, -} from 'homebridge'; - -import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; -import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; -import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse } from 'magichome-platform'; - -import { Logs } from './logs'; - -const CCT = 'CCT'; -const HSL = 'HSL'; -const BUFFER_MS = 0; -const FINAL_COMMAND_TIMEOUT = 100; -const QUEUE_INTERVAL = 150; - -/** - * 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 HomebridgeMagichomeDynamicPlatformAccessory { - - protected service: Service; - protected readonly hap: HAP; - - protected adaptiveLightingService; - protected newAccessoryCommand: IAccessoryCommand; - protected latestDeviceCommand: IDeviceCommand; - protected latestAccessoryCommand: IAccessoryCommand; - - protected ColorCommandMode = HSL; - - protected colorWhiteSimultaniousSaturationLevel; - protected colorOffSaturationLevel; - protected simultaniousDevicesColorWhite; - - protected deviceWriteStatus = 'ready'; - protected deviceReadStatus = 'ready'; - protected readRequestLevel = 0; - - protected queue; - protected slowQueueRetry = false; - latestDeviceState: IDeviceState; - - //================================================= - // Start Constructor // - - constructor( - protected readonly api: API, - protected readonly accessory: MagicHomeAccessory, - public readonly config: PlatformConfig, - protected readonly controller: BaseController, - protected readonly hbLogger: Logging, - protected readonly logs, - ) { - - this.setupMisc(); - this.logs = logs; - this.controller = controller; - this.hap = api.hap; - this.api = api; - this.config = config; - this.initializeCharacteristics(); - this.fetchAndUpdateState(2); - } - - //================================================= - // End Constructor // - - //================================================= - // Start Setters // - async setOn(value: CharacteristicValue) { - const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; - this.processAccessoryCommand(accessoryCommand); - } - - setHue(value: CharacteristicValue) { - this.accessory.context.accessoryState.HSL.hue = value as number; - this.ColorCommandMode = HSL; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; - this.processAccessoryCommand(accessoryCommand); - } - - setSaturation(value: CharacteristicValue) { - - this.accessory.context.accessoryState.HSL.saturation = value as number; - - this.ColorCommandMode = HSL; - - const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { saturation: value as number } }; - this.processAccessoryCommand(accessoryCommand); - } - - async setBrightness(value: CharacteristicValue) { - - - this.accessory.context.accessoryState.brightness = value as number; - const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; - this.processAccessoryCommand(accessoryCommand); - } - - // setColorTemperature(value: CharacteristicValue) { - - // this.ColorCommandMode = CCT; - // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; - // this.processAccessoryCommand(accessoryCommand); - // } - - setConfiguredName(value: CharacteristicValue) { - - const name: string = value.toString(); - this.logs.warn('Renaming device to %o', name); - this.accessory.context.displayName = name; - this.api.updatePlatformAccessories([this.accessory]); - } - - identifyLight() { - - this.flashEffect(); - } - - //================================================= - // End Setters // - - //================================================= - // Start Getters // - - getHue() { - const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - - this.fetchAndUpdateState(2); - return hue; - - } - - // getColorTemperature() { - // const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - - // const colorTemperature = this.accessory.context.accessoryState.colorTemperature; - // this.fetchAndUpdateState(3); - // return colorTemperature; - // } - - getBrightness() { - const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - - this.fetchAndUpdateState(2); - return brightness; - } - - /** - ** @getOn - * instantly retrieve the current on/off state stored in our object - * next call this.getState() which will update all values asynchronously as they are ready - */ - async getOn() { - const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - - this.fetchAndUpdateState(2); - return isOn; - } - - flashEffect() { - // - } //flashEffect - - //================================================= - // End LightEffects // - - - protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { - // for (const interval of this.intervals) { - // this.controller.clearAnimations(); - //} - - await this.prepareCommand(accessoryCommand); - } - - protected async prepareCommand(accessoryCommand: IAccessoryCommand): Promise { - try { - - - this.newAccessoryCommand = accessoryCommand; - - this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessory.context.accessoryState, '\n Received Command', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = Object.assign({}, this.accessory.context.accessoryState, this.newAccessoryCommand); - - // eslint-disable-next-line no-prototype-builtins - if (this.newAccessoryCommand.hasOwnProperty('isOn') && !(this.newAccessoryCommand.hasOwnProperty('HSL') || this.newAccessoryCommand.hasOwnProperty('brightness'))) { - sanitizedAcessoryCommand.isPowerCommand = true; - } - const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand); - return completeResponse; - } catch (error) { - - } - } - - protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions?: ICommandOptions): Promise { - try { - - - const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); - - let response; - if (!accessoryCommand.isPowerCommand) { - response = await this.controller.setAllValues(deviceCommand, commandOptions); - } else { - response = await this.controller.setOn(deviceCommand.isOn, commandOptions); - } - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); - return response; - } catch (error) { - - } - } - - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - - const RGB = convertHSLtoRGB(HSL); - RGB.red = Math.round((RGB.red / 100) * brightness); - RGB.green = Math.round((RGB.green / 100) * brightness); - RGB.blue = Math.round((RGB.blue / 100) * brightness); - - - const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; - return deviceCommand; - } - - protected async updateLocalState(requestLevel, deviceState) { - if (!deviceState) { - deviceState = await this.controller?.fetchState() - // ?? this.accessory.context.cachedDeviceInformation.deviceState; - } - this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); - // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; - const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); - let accessoryState: IAccessoryState; - if (deviceState) { - switch (requestLevel) { - case 0: - accessoryState = { HSL: { luminance }, isOn }; - break; - case 1: - accessoryState = { HSL: { hue, luminance }, isOn }; - break; - case 2: - accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; - break; - case 3: - accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; - break; - } - - this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); - } - } - - updateHomekitState() { - const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, brightness); - } - - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - - const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - // eslint-disable-next-line prefer-const - let { hue, saturation, luminance } = convertRGBtoHSL(RGB); - let brightness = 0; - - if (luminance > 0 && isOn) { - brightness = luminance * 2; - } else if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - if (warmWhite > coldWhite) { - saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); - } else { - saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); - } - } - - const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; - return accessoryState; - } - - initializeCharacteristics() { - - let cachedDeviceInformation = this.controller?.getCachedDeviceInformation(); - if (cachedDeviceInformation) { - this.accessory.context.cachedDeviceInformation = cachedDeviceInformation; - } else { - cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; - } - - const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; - - addAccessoryInformationCharacteristic(this); - - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); - this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); - - if (hasColor) { - addHueCharacteristic(this); - addSaturationCharacteristic(this); - } - - if (hasBrightness) { - addBrightnessCharacteristic(this); - } - - if (hasCCT) { - // addColorTemperatureCharacteristic(this); - } - - if (!hasBrightness) { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Switch service to accessory.`); //device is switch, register it as such - this.service = this.accessory.getService(this.hap.Service.Switch) ?? this.accessory.addService(this.hap.Service.Switch); - } - addOnCharacteristic(this); - addConfiguredNameCharacteristic(this); - } - - setupMisc() { - this.accessory.context.accessoryState = this.accessory.context.accessoryState ?? DefaultAccessoryCommand; - - // const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName?? "unknown"); - // const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = Object.assign({}, this.config.globalAccessoryOptions, localAccessoryOptions); - - - // this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; - // this.colorOffSaturationLevel = colorOffSaturationLevel; - // this.logs = new Logs(this.hbLogger, logLevel ?? 3); - - } - - async fetchAndUpdateState(requestLevel) { - try { - - - this.readRequestLevel = requestLevel; - await this.updateLocalState(this.readRequestLevel, null); - this.updateHomekitState(); - - } catch (error) { - - } - } - - getController() { - return this.controller; - } - - - +import type { + API, Service, PlatformConfig, CharacteristicValue, + CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, +} from 'homebridge'; +import { CharacteristicEventTypes } from 'homebridge'; + +import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; +import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; +// import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep } from 'magichome-platform'; +import { Logs } from './logs'; + +const CCT = 'CCT'; +const HSL = 'HSL'; +const DEFAULT_ACCESSORY_STATE: IAccessoryState = { isOn: false, HSL: { hue: 0, saturation: 0, luminance: 50 }, brightness: 100 } +/** + * 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 HomebridgeMagichomeDynamicPlatformAccessory { + + protected service: Service; + protected readonly hap: HAP; + + protected adaptiveLightingService; + protected newAccessoryCommand: IAccessoryCommand; + protected latestAccessoryCommand: IAccessoryCommand; + + protected accessoryState: IAccessoryState; + + protected ColorCommandMode = HSL; + + protected colorWhiteSimultaniousSaturationLevel; + protected colorOffSaturationLevel; + protected simultaniousDevicesColorWhite; + + protected deviceWriteStatus = 'ready'; + protected deviceReadStatus = 'ready'; + protected readRequestLevel = 0; + + protected queue; + protected slowQueueRetry = false; + + //================================================= + // Start Constructor // + + constructor( + protected readonly api: API, + protected readonly accessory: MagicHomeAccessory, + public readonly config: PlatformConfig, + protected readonly controller: BaseController, + protected readonly hbLogger: Logging, + protected readonly logs, + ) { + + this.setupMisc(); + this.accessoryState = DEFAULT_ACCESSORY_STATE; + this.logs = logs; + this.controller = controller; + this.hap = api.hap; + this.api = api; + this.config = config; + this.initializeCharacteristics(); + this.fetchAndUpdateState(2); + } + + //================================================= + // End Constructor // + + //================================================= + // Start Setters // + async setOn(value: CharacteristicValue) { + const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; + this.processAccessoryCommand(accessoryCommand); + } + + setHue(value: CharacteristicValue) { + this.accessoryState.HSL.hue = value as number; + this.ColorCommandMode = HSL; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; + this.processAccessoryCommand(accessoryCommand); + } + + setSaturation(value: CharacteristicValue) { + + this.accessoryState.HSL.saturation = value as number; + + this.ColorCommandMode = HSL; + + const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { saturation: value as number } }; + this.processAccessoryCommand(accessoryCommand); + } + + async setBrightness(value: CharacteristicValue) { + + + this.accessoryState.brightness = value as number; + const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; + this.processAccessoryCommand(accessoryCommand); + } + + // setColorTemperature(value: CharacteristicValue) { + + // this.ColorCommandMode = CCT; + // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; + // this.processAccessoryCommand(accessoryCommand); + // } + + setConfiguredName(value: CharacteristicValue) { + + const name: string = value.toString(); + this.logs.warn('Renaming device to %o', name); + this.accessory.context.displayName = name; + this.api.updatePlatformAccessories([this.accessory]); + } + + identifyLight() { + + this.flashEffect(); + } + + //================================================= + // End Setters // + + //================================================= + // Start Getters // + + getHue() { + const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + + this.fetchAndUpdateState(2); + return hue; + + } + + // getColorTemperature() { + // const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) + + // const colorTemperature = this.accessory.context.accessoryState.colorTemperature; + // this.fetchAndUpdateState(3); + // return colorTemperature; + // } + + getBrightness() { + const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + + this.fetchAndUpdateState(2); + return brightness; + } + + /** + ** @getOn + * instantly retrieve the current on/off state stored in our object + * next call this.getState() which will update all values asynchronously as they are ready + */ + async getOn() { + const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + + this.fetchAndUpdateState(2); + return isOn; + } + + flashEffect() { + // + } //flashEffect + + //================================================= + // End LightEffects // + + + protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { + // for (const interval of this.intervals) { + // this.controller.clearAnimations(); + //} + + await this.prepareCommand(accessoryCommand); + } + + protected async prepareCommand(accessoryCommand: IAccessoryCommand): Promise { + try { + + this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); + const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState ); + console.log(accessoryCommand) + console.log(sanitizedAcessoryCommand) + if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSL') || accessoryCommand.hasOwnProperty('brightness'))) { + sanitizedAcessoryCommand.isPowerCommand = true; + } + const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand); + return completeResponse; + } catch (error) { + this.hbLogger.error(error); + } + } + + protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions?: ICommandOptions): Promise { + try { + + + const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); + + let response; + if (!accessoryCommand.isPowerCommand) { + response = await this.controller.setAllValues(deviceCommand); + } else { + response = await this.controller.setOn(deviceCommand.isOn); + } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); + return response; + } catch (error) { + this.hbLogger.error(error); + + } + } + + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + + const RGB = convertHSLtoRGB(HSL); + RGB.red = Math.round((RGB.red / 100) * brightness); + RGB.green = Math.round((RGB.green / 100) * brightness); + RGB.blue = Math.round((RGB.blue / 100) * brightness); + + + const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; + return deviceCommand; + } + + protected async updateLocalState(requestLevel, deviceState) { + try { + if (!deviceState) { + deviceState = await this.controller?.fetchState(); + // ?? this.accessory.context.cachedDeviceInformation.deviceState; + } + this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); + // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; + const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); + let accessoryState: IAccessoryState; + if (deviceState) { + switch (requestLevel) { + case 0: + // accessoryState = { HSL: { luminance }, isOn }; + break; + case 1: + // accessoryState = { HSL: { hue, luminance }, isOn }; + break; + case 2: + accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; + break; + case 3: + accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; + break; + } + + this.accessoryState = accessoryState; + + this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); + } + + } catch (error) { + + } + } + + updateHomekitState() { + const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, brightness); + } + + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; + //TODO - REPLACE HSL WITH HSV + // eslint-disable-next-line prefer-const + let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let brightness = 0; + + if (luminance > 0 && isOn) { + brightness = luminance * 2; + } else if (isOn) { + brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); + if (warmWhite > coldWhite) { + saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); + } else { + saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); + } + } + + const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; + return accessoryState; + } + + initializeCharacteristics() { + + const cachedDeviceInformation = this.controller.getCachedDeviceInformation(); + // if (cachedDeviceInformation) { + // this.accessory.context.accessoryState = accessoryState; + // } else { + // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; + // } + const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; + + this.addAccessoryInformationCharacteristic(); + + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); + this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); + + if (hasColor) { + this.addHueCharacteristic(); + this.addSaturationCharacteristic(); + } + + if (hasBrightness) { + this.addBrightnessCharacteristic(); + } + + if (hasCCT) { + // addColorTemperatureCharacteristic(); + } + + if (!hasBrightness) { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Switch service to accessory.`); //device is switch, register it as such + this.service = this.accessory.getService(this.hap.Service.Switch) ?? this.accessory.addService(this.hap.Service.Switch); + } + this.addOnCharacteristic(); + this.addConfiguredNameCharacteristic(); + } + + setupMisc() { + + // const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName?? "unknown"); + // const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = Object.assign({}, this.config.globalAccessoryOptions, localAccessoryOptions); + + + // this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; + // this.colorOffSaturationLevel = colorOffSaturationLevel; + // this.logs = new Logs(this.hbLogger, logLevel ?? 3); + + } + + async fetchAndUpdateState(requestLevel) { + try { + this.readRequestLevel = requestLevel; + await this.updateLocalState(this.readRequestLevel, null); + this.updateHomekitState(); + } catch (error) { + this.hbLogger.error(error); + } + } + + getController() { + return this.controller; + } + + addOnCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.On) + .onSet(this.setOn.bind(this)) + .onGet(this.getOn.bind(this)); + } + + addHueCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.Hue) + .onSet(this.setHue.bind(this)) + .onGet(this.getHue.bind(this)); + } + + addSaturationCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.Saturation) + .onSet(this.setSaturation.bind(this)); + // .onGet(this.CHANGE_ME.bind(this)); + + } + + addBrightnessCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.Brightness) + .onSet(this.setBrightness.bind(this)) + .onGet(this.getBrightness.bind(this)); + } + + addColorTemperatureCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.ColorTemperature); + // .onSet(this.setColorTemperature.bind(this)) + // .onGet(this.getColorTemperature.bind(this)); + + if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); + this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service); + this.accessory.configureController(this.adaptiveLightingService); + } + } + + addAccessoryInformationCharacteristic() { + + // const { + // protoDevice: { uniqueId, modelNumber }, + // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, + // } = this.accessory.context.cachedDeviceInformation; + // set accessory information + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .setCharacteristic(this.hap.Characteristic.Manufacturer, 'MagicHome') + // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) + // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) + // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') + // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') + .getCharacteristic(this.hap.Characteristic.Identify) + .removeAllListeners(CharacteristicEventTypes.SET) + .removeAllListeners(CharacteristicEventTypes.GET) + .on(CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below + + + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); + } + + addConfiguredNameCharacteristic() { + if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { + this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } else { + this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + + } + + + /* + // Add the garage door service if it doesn't already exist + this.service = + this.accessory.getService(this.hapServ.GarageDoorOpener) || + this.accessory.addService(this.hapServ.GarageDoorOpener) + + // Add some extra Eve characteristics + if (!this.service.testCharacteristic(this.eveChar.LastActivation)) { + this.service.addCharacteristic(this.eveChar.LastActivation) + } + if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) { + this.service.addCharacteristic(this.eveChar.ResetTotal) + } + if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) { + this.service.addCharacteristic(this.eveChar.TimesOpened) + } + + // Add the set handler to the garage door target state characteristic + this.service + .getCharacteristic(this.hapChar.TargetDoorState) + .onSet(value => this.internalTargetUpdate(value)) + this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value + this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value + + // Add the set handler to the garage door reset total characteristic + this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { + this.service.updateCharacteristic(this.eveChar.TimesOpened, 0) + }) + + // Update the obstruction detected to false on plugin load + this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false) + + // Pass the accessory to Fakegato to set up with Eve + this.accessory.eveService = new platform.eveService('door', this.accessory, { + log: platform.config.debugFakegato ? this.log : () => {} + }) + */ + + + } // ZackneticMagichomePlatformAccessory class \ No newline at end of file diff --git a/src/settings.ts b/src/settings.ts index 8e9f5da..e4c42f2 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,3 +1,4 @@ + /** * This is the name of the platform that users will use to register the plugin in the Homebridge config.json */ From b32be74e7574a57aabad0e685fab0eb1360ae021 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Fri, 19 Aug 2022 15:53:50 -0400 Subject: [PATCH 31/42] logic shift and HSL conversion to HSV --- package-lock.json | 4757 +++++++++++++++++++++++++++++++- package.json | 7 +- src/AccessoryGenerator.ts | 15 +- src/accessories/CCTStrip.ts | 52 +- src/accessories/DimmerStrip.ts | 38 +- src/accessories/GRBStrip.ts | 62 +- src/accessories/RGBStrip.ts | 56 +- src/accessories/RGBWBulb.ts | 116 +- src/accessories/RGBWStrip.ts | 172 +- src/accessories/RGBWWBulb.ts | 182 +- src/accessories/RGBWWStrip.ts | 216 +- src/misc/types.ts | 68 +- src/misc/utils.ts | 372 ++- src/platformAccessory.ts | 143 +- 14 files changed, 5541 insertions(+), 715 deletions(-) diff --git a/package-lock.json b/package-lock.json index 72ed01c..af78405 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,4127 @@ { "name": "homebridge-magichome-dynamic-platform", "version": "1.9.3-beta.4", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "homebridge-magichome-dynamic-platform", + "version": "1.9.3-beta.4", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Zacknetic" + }, + { + "type": "paypal", + "url": "https://www.paypal.com/paypalme/ZacharyAvino" + } + ], + "license": "Apache-2.0", + "dependencies": { + "color-convert": "^2.0.1", + "homebridge-lib": "^5.1.14" + }, + "devDependencies": { + "@types/expect": "^24.3.0", + "@types/mocha": "^9.1.1", + "@types/node": "^16.10.9", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^8.0.1", + "homebridge": "^1.5.0", + "mocha": "^10.0.0", + "nodemon": "^2.0.13", + "rimraf": "^3.0.2", + "ts-mocha": "^10.0.0", + "ts-node": "^10.3.0", + "typescript": "^4.4.4" + }, + "engines": { + "homebridge": ">=1.0.0", + "node": ">=10.17.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@homebridge/ciao": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", + "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "fast-deep-equal": "^3.1.3", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0" + }, + "bin": { + "ciao-bcs": "lib/bonjour-conformance-testing.js" + } + }, + "node_modules/@homebridge/dbus-native": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.4.1.tgz", + "integrity": "sha512-8h6MkoJykY37THOyRXWCIKpzbhIn4WWKZBunlXTH75Cb6vBcmhyIhZ3SvzqJAjJCEdhLg7wawfn7/Mpko7eREQ==", + "dev": true, + "dependencies": { + "@homebridge/long": "^5.2.1", + "event-stream": "^4.0.0", + "hexy": "^0.2.10", + "optimist": "^0.6.1", + "put": "0.0.6", + "safe-buffer": "^5.1.1", + "xml2js": "^0.4.17" + }, + "bin": { + "dbus2js": "bin/dbus2js.js" + } + }, + "node_modules/@homebridge/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", + "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", + "dev": true + }, + "node_modules/@homebridge/plugin-ui-utils": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", + "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", + "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.28", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz", + "integrity": "sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/expect": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", + "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", + "deprecated": "This is a stub types definition. expect provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "expect": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "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/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "optional": true + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.11.48", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.48.tgz", + "integrity": "sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.11.tgz", + "integrity": "sha512-aB4y9UDUXTSMxmM4MH+YnuR0g5Cph3FLQBoWoMB21DSvFVAxRVEHEMx3TLh+zUZYMCQtKiqazz0Q4Rre31f/OA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz", + "integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/type-utils": "5.33.0", + "@typescript-eslint/utils": "5.33.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz", + "integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/typescript-estree": "5.33.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz", + "integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/visitor-keys": "5.33.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz", + "integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.33.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz", + "integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz", + "integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/visitor-keys": "5.33.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz", + "integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.33.0", + "@typescript-eslint/types": "5.33.0", + "@typescript-eslint/typescript-estree": "5.33.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.33.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz", + "integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.33.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bonjour-hap": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.3.tgz", + "integrity": "sha512-qyLU96ICCYbpOFiMCjA3aNYH5Jc83XH1YX6+EXWukyyiNXzXH2LZv8AVmGW33FceF3gfUM4jYoKX2xChtNDUnA==", + "dependencies": { + "array-flatten": "^2.1.2", + "deep-equal": "^2.0.5", + "ip": "^1.1.5", + "multicast-dns": "^7.2.3", + "multicast-dns-service-types": "^1.1.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", + "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", + "dev": true + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-equal": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", + "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", + "dependencies": { + "call-bind": "^1.0.0", + "es-get-iterator": "^1.1.1", + "get-intrinsic": "^1.0.1", + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.2", + "is-regex": "^1.1.1", + "isarray": "^2.0.5", + "object-is": "^1.1.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.3", + "which-boxed-primitive": "^1.0.1", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/es-abstract": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", + "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.3", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", + "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, + "node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fast-srp-hap": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", + "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", + "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/futoin-hkdf": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", + "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", + "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/hap-nodejs": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.10.2.tgz", + "integrity": "sha512-rmCKoNoBqpcOz/wG5iTtS7JIkLjobEZj+oXGW/Z4I4eJGk14VfKjITA8plaAm6gWIZEAajASzzUdEZnIKEvzdg==", + "dev": true, + "dependencies": { + "@homebridge/ciao": "^1.1.4", + "@homebridge/dbus-native": "^0.4.1", + "bonjour-hap": "~3.6.3", + "debug": "^4.3.4", + "fast-srp-hap": "2.0.4", + "futoin-hkdf": "~1.4.3", + "node-persist": "^0.0.11", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0", + "tweetnacl": "^1.0.3" + }, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "dev": true, + "bin": { + "hexy": "bin/hexy_cmd.js" + } + }, + "node_modules/homebridge": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.5.0.tgz", + "integrity": "sha512-0t8WNBKz9NFCab5obBfJMnxFgkg4uJZqON+iM/uZpIyiMRWH9ycCHd1pYAPMk9vDdfDu8/VpxYafWsYx6luHtg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "commander": "5.1.0", + "fs-extra": "^10.1.0", + "hap-nodejs": "^0.10.2", + "qrcode-terminal": "^0.12.0", + "semver": "^7.3.7", + "source-map-support": "^0.5.21" + }, + "bin": { + "homebridge": "bin/homebridge" + }, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/homebridge-lib": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.4.tgz", + "integrity": "sha512-R0/Kv2sgXThbAZogvB/H3O2Lqqi4n8T7gCXVq8Nx5UB4gXSjkOd/+8oc9l/U9EhoD19OSXFrE8VGKZcERal+yQ==", + "dependencies": { + "@homebridge/plugin-ui-utils": "~0.0.19", + "bonjour-hap": "^3.6.3", + "chalk": "^4.1.2", + "semver": "^7.3.7" + }, + "bin": { + "hap": "cli/hap.js", + "json": "cli/json.js", + "sysinfo": "cli/sysinfo.js", + "upnp": "cli/upnp.js" + }, + "engines": { + "homebridge": "^1.5.0", + "node": "^16.16.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", + "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/json5/node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true, + "optional": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "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.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", + "dev": true + }, + "node_modules/mkdirp": { + "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.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp/node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-persist": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", + "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", + "dev": true, + "dependencies": { + "mkdirp": "~0.5.1", + "q": "~1.1.1" + } + }, + "node_modules/nodemon": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", + "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", + "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", + "dev": true, + "dependencies": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "dependencies": { + "through": "~2.3" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/put": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz", + "integrity": "sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/q": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", + "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qrcode-terminal": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", + "dev": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", + "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", + "dev": true, + "dependencies": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", + "dev": true, + "dependencies": { + "ts-node": "7.0.1" + }, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "optionalDependencies": { + "tsconfig-paths": "^3.5.0" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X" + } + }, + "node_modules/ts-mocha/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ts-mocha/node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/ts-mocha/node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-mocha/node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "optional": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true, + "optional": true + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", + "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-abstract": "^1.20.0", + "for-each": "^0.3.3", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -91,6 +4209,38 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2" + } + }, + "@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dev": true, + "requires": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, "@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", @@ -144,6 +4294,12 @@ "fastq": "^1.6.0" } }, + "@sinclair/typebox": { + "version": "0.24.28", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz", + "integrity": "sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow==", + "dev": true + }, "@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -168,18 +4324,85 @@ "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, + "@types/expect": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", + "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", + "dev": true, + "requires": { + "expect": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, "@types/json-schema": { "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/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "optional": true + }, + "@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, "@types/node": { "version": "16.11.48", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.48.tgz", "integrity": "sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw==", "dev": true }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.11.tgz", + "integrity": "sha512-aB4y9UDUXTSMxmM4MH+YnuR0g5Cph3FLQBoWoMB21DSvFVAxRVEHEMx3TLh+zUZYMCQtKiqazz0Q4Rre31f/OA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "5.33.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz", @@ -275,6 +4498,12 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -291,7 +4520,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "acorn-walk": { "version": "8.2.0", @@ -311,6 +4541,12 @@ "uri-js": "^4.2.2" } }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -358,6 +4594,12 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -406,6 +4648,12 @@ "fill-range": "^7.0.1" } }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -427,6 +4675,12 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -463,6 +4717,23 @@ } } }, + "ci-info": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", + "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -514,6 +4785,12 @@ "ms": "2.1.2" } }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, "deep-equal": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", @@ -557,6 +4834,12 @@ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, + "diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true + }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -589,6 +4872,12 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "es-abstract": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", @@ -644,6 +4933,12 @@ "is-symbol": "^1.0.2" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -820,6 +5115,19 @@ "through": "^2.3.8" } }, + "expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "requires": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + } + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -905,6 +5213,12 @@ "path-exists": "^4.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -992,6 +5306,12 @@ "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", "dev": true }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, "get-intrinsic": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", @@ -1126,6 +5446,12 @@ "has-symbols": "^1.0.2" } }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, "hexy": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", @@ -1271,6 +5597,12 @@ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1304,6 +5636,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -1354,6 +5692,12 @@ "has-tostringtag": "^1.0.0" } }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, "is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", @@ -1387,6 +5731,73 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, + "jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -1408,6 +5819,25 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true, + "optional": true + } + } + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -1443,6 +5873,16 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1511,6 +5951,104 @@ } } }, + "mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1531,6 +6069,12 @@ "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -1747,6 +6291,26 @@ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true }, + "pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, "pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -1783,6 +6347,21 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1808,6 +6387,12 @@ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1858,6 +6443,15 @@ "lru-cache": "^6.0.0" } }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1931,6 +6525,23 @@ "through": "2" } }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, "stream-combiner": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", @@ -1941,6 +6552,17 @@ "through": "~2.3.4" } }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "string.prototype.trimend": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", @@ -1970,6 +6592,13 @@ "ansi-regex": "^5.0.1" } }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "optional": true + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2019,6 +6648,52 @@ "nopt": "~1.0.10" } }, + "ts-mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", + "dev": true, + "requires": { + "ts-node": "7.0.1", + "tsconfig-paths": "^3.5.0" + }, + "dependencies": { + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + } + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true + } + } + }, "ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -2040,6 +6715,28 @@ "yn": "3.1.1" } }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "optional": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true, + "optional": true + } + } + }, "tslib": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", @@ -2191,6 +6888,23 @@ "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", "dev": true }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2213,11 +6927,50 @@ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index be5518c..fe284c3 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "lint": "eslint src/**.ts", "watch": "npm run build && nodemon", "build": "rimraf ./dist && tsc", - "prepublishOnly": "npm run lint && npm run build" + "prepublishOnly": "npm run lint && npm run build", + "test:watch": "ts-mocha --timeout 10000 --watch-extensions ts --watch --watch-files src 'src/specs/*.spec.ts'" }, "keywords": [ "homebridge-plugin", @@ -65,13 +66,17 @@ "homebridge-lib": "^5.1.14" }, "devDependencies": { + "@types/expect": "^24.3.0", + "@types/mocha": "^9.1.1", "@types/node": "^16.10.9", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.0.0", "eslint": "^8.0.1", "homebridge": "^1.5.0", + "mocha": "^10.0.0", "nodemon": "^2.0.13", "rimraf": "^3.0.2", + "ts-mocha": "^10.0.0", "ts-node": "^10.3.0", "typescript": "^4.4.4" } diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index d740c5b..2d8ec68 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -2,9 +2,10 @@ import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProt import { IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; import { API, HAP, PlatformAccessory, PlatformConfig } from 'homebridge'; -import { homekitInterface } from './misc/types'; +// import { homekitInterface } from './misc/types'; import { Logs } from './logs'; import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +import { Console } from 'console'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; @@ -86,9 +87,15 @@ export class AccessoryGenerator { // console.log(controller) const { protoDevice: { uniqueId }, deviceState, deviceAPI } = controller.getCachedDeviceInformation(); let currAccessory: MagicHomeAccessory; - if (this.accessoriesFromDiskMap.has(uniqueId)) { const existingAccessory = this.accessoriesFromDiskMap.get(uniqueId); + console.log(existingAccessory.context.displayName) + console.log(existingAccessory.context.displayName.toLocaleLowerCase().includes('zack')); + + if (!existingAccessory.context.displayName.includes('Zacks')) { + // console.log("NOT ZACK") + continue; + } this.accessoriesFromDiskMap.delete(uniqueId); this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); currAccessory = this.processOnlineAccessory(controller, existingAccessory); @@ -149,12 +156,12 @@ export class AccessoryGenerator { processOnlineAccessory(controller: BaseController, existingAccessory: MagicHomeAccessory) { const { protoDevice, deviceAPI: { description }, deviceMetaData } = controller.getCachedDeviceInformation(); - + // if (!this.isAllowed(uniqueId)) { // // throw new Error(`[Error] [${existingAccessory.context.displayName}] - Accessory is not allowed. Skipping...`); // } - overwriteDeep(existingAccessory.context, { protoDevice, deviceMetaData, latestUpdate: Date.now()}); + overwriteDeep(existingAccessory.context, { protoDevice, deviceMetaData, latestUpdate: Date.now() }); try { new HomebridgeMagichomeDynamicPlatformAccessory(this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs) diff --git a/src/accessories/CCTStrip.ts b/src/accessories/CCTStrip.ts index 19e2a2f..3f73ac8 100644 --- a/src/accessories/CCTStrip.ts +++ b/src/accessories/CCTStrip.ts @@ -1,39 +1,39 @@ -import { clamp } from '../misc/utils'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; +// import { clamp } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; -export class CCTStrip extends HomebridgeMagichomeDynamicPlatformAccessory { +// export class CCTStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - async updateDeviceState(_timeout = 200) { +// async updateDeviceState(_timeout = 200) { - // //**** local variables ****\\ - // const CCT = this.lightState.CCT; +// // //**** local variables ****\\ +// // const CCT = this.lightState.CCT; - //we default the mask to turn on color. Other values can still be set, they just wont turn on +// //we default the mask to turn on color. Other values can still be set, they just wont turn on - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - //const ww = Math.round(((clamp(whites.warmWhite, 0, 127) / 100) * brightness)); - //const cw = Math.round(((clamp(whites.coldWhite, 0, 127) / 100) * brightness)); +// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// //const ww = Math.round(((clamp(whites.warmWhite, 0, 127) / 100) * brightness)); +// //const cw = Math.round(((clamp(whites.coldWhite, 0, 127) / 100) * brightness)); - //await this.send([0x31, 0x00, 0x00, 0x00, ww, cw, 0xFF, 0x0F], true, _timeout); //9th byte checksum calculated later in send() - // await this.send([0x35, 0xb1, ww, cw, 0x00, 0x00, 0x00, 0x03], true, _timeout); //9th byte checksum calculated later in send() +// //await this.send([0x31, 0x00, 0x00, 0x00, ww, cw, 0xFF, 0x0F], true, _timeout); //9th byte checksum calculated later in send() +// // await this.send([0x35, 0xb1, ww, cw, 0x00, 0x00, 0x00, 0x03], true, _timeout); //9th byte checksum calculated later in send() - }//setColor +// }//setColor - async updateHomekitState() { - // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); - //this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); - // if (this.lightState.isOn){ - // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(( - // (this.lightState.whiteValues.coldWhite/1.27) - // + (this.lightState.whiteValues.warmWhite/1.27)), 0, 100)); - // } +// async updateHomekitState() { +// // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); +// // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); +// //this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); +// // if (this.lightState.isOn){ +// // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(( +// // (this.lightState.whiteValues.coldWhite/1.27) +// // + (this.lightState.whiteValues.warmWhite/1.27)), 0, 100)); +// // } - //this.cacheCurrentLightState(); - } +// //this.cacheCurrentLightState(); +// } -} \ No newline at end of file +// } \ No newline at end of file diff --git a/src/accessories/DimmerStrip.ts b/src/accessories/DimmerStrip.ts index 81e32bb..d541467 100644 --- a/src/accessories/DimmerStrip.ts +++ b/src/accessories/DimmerStrip.ts @@ -1,31 +1,31 @@ -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; -export class DimmerStrip extends HomebridgeMagichomeDynamicPlatformAccessory { +// export class DimmerStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - // /** - // ** @updateHomekitState - // * send state to homekit - // */ - // async updateHomekitState() { +// // /** +// // ** @updateHomekitState +// // * send state to homekit +// // */ +// // async updateHomekitState() { - // this.lightState.brightness = this.lightState.RGB.red / 2.5; //create local constant for brightness - // //this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); +// // this.lightState.brightness = this.lightState.RGB.red / 2.5; //create local constant for brightness +// // //this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - // if( this.lightState.isOn ){ - // //this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); - // } +// // if( this.lightState.isOn ){ +// // //this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); +// // } - // } +// // } - // async setColor() { +// // async setColor() { - // //**** local variables ****\\ - // const brightness = Math.round((2.5 * this.lightState.brightness)); +// // //**** local variables ****\\ +// // const brightness = Math.round((2.5 * this.lightState.brightness)); - // //await this.send([0x31, brightness, 0x00, 0x00, 0x03, 0x01, 0x0F]); //8th byte checksum calculated later in send() +// // //await this.send([0x31, brightness, 0x00, 0x00, 0x03, 0x01, 0x0F]); //8th byte checksum calculated later in send() - // }//setColor +// // }//setColor -} \ No newline at end of file +// } \ No newline at end of file diff --git a/src/accessories/GRBStrip.ts b/src/accessories/GRBStrip.ts index f9186f7..22b816a 100644 --- a/src/accessories/GRBStrip.ts +++ b/src/accessories/GRBStrip.ts @@ -1,51 +1,51 @@ -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; +// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// import { convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, HSVtoRGB, RGBtoHSV } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; -export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { +// export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { +// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - const { hue, saturation } = HSL; - const { red, green, blue }: IColorRGB = convertHSLtoRGB(HSL); +// const { isOn, HSV, colorTemperature, brightness } = accessoryCommand; +// const { hue, saturation, value } = HSV; +// const { red, green, blue }: IColorRGB = HSVtoRGB(HSV); - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - const _green = Math.round((red / 100) * brightness); - const _red = Math.round((green / 100) * brightness); - const _blue = Math.round((blue / 100) * brightness); +// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// const _green = Math.round((red / 100) * brightness); +// const _red = Math.round((green / 100) * brightness); +// const _blue = Math.round((blue / 100) * brightness); - const deviceCommand: IDeviceCommand = { isOn, RGB: { red: _red, green: _green, blue: _blue }, CCT: { warmWhite: 0, coldWhite: 0 }, colorMask: 0xF0 }; - return deviceCommand; - }//setColor +// const deviceCommand: IDeviceCommand = { isOn, RGB: { red: _red, green: _green, blue: _blue }, CCT: { warmWhite: 0, coldWhite: 0 }, colorMask: 0xF0 }; +// return deviceCommand; +// }//setColor - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { +// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { RGB: { red, green, blue }, isOn } = deviceState; - const RGB: IColorRGB = { red: green, green: red, blue }; - // eslint-disable-next-line prefer-const - let { hue, saturation, luminance } = convertRGBtoHSL(RGB); - let brightness = 0; +// const { RGB: { red, green, blue }, isOn } = deviceState; +// const RGB: IColorRGB = { red: green, green: red, blue }; +// // eslint-disable-next-line prefer-const +// let { hue, saturation, value } = RGBtoHSV(RGB); +// let brightness = 0; - //Brightness - if (isOn) { - brightness = luminance; - } +// //Brightness +// if (isOn) { +// brightness = value; +// } - const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; - return accessoryState; - } +// const accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; +// return accessoryState; +// } -} +// } diff --git a/src/accessories/RGBStrip.ts b/src/accessories/RGBStrip.ts index dc32b8b..76e00cf 100644 --- a/src/accessories/RGBStrip.ts +++ b/src/accessories/RGBStrip.ts @@ -1,34 +1,34 @@ -import { clamp, convertHSLtoRGB } from '../misc/utils'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; +// import { clamp } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; -export class RGBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - // public eightByteProtocol = 2; - // async updateDeviceState() { +// export class RGBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { +// // public eightByteProtocol = 2; +// // async updateDeviceState() { - // //**** local variables ****\\ - // const hsl = this.lightState.HSL; - // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB - // const brightness = this.lightState.brightness; +// // //**** local variables ****\\ +// // const hsl = this.lightState.HSL; +// // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB +// // const brightness = this.lightState.brightness; - // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); - // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); +// // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); +// // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - // const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) - // //we default the mask to turn on color. Other values can still be set, they just wont turn on +// // const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) +// // //we default the mask to turn on color. Other values can still be set, they just wont turn on - // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - // const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); - // const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); - // const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); +// // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// // const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); +// // const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); +// // const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - // if(this.eightByteProtocol == 0){ - // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() - // } else if(this.eightByteProtocol == 1){ - // // await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); - // } else if (this.eightByteProtocol == 2){ - // //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; - // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() - // } - // }//setColor -} \ No newline at end of file +// // if(this.eightByteProtocol == 0){ +// // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() +// // } else if(this.eightByteProtocol == 1){ +// // // await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); +// // } else if (this.eightByteProtocol == 2){ +// // //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; +// // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() +// // } +// // }//setColor +// } \ No newline at end of file diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index 13903f9..9b5ffc7 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -1,77 +1,77 @@ -import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; +// import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// import { clamp, convertHueToColorCCT, whiteTemperatureToCCT } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; -export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { +// export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { +// // protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - const { hue, saturation } = HSL; - const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); +// // const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; +// // const { hue, saturation } = HSL; +// // const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); - let { red, green, blue } = RGB; - let warmWhite; - let colorMask = 0xF0; +// // let { red, green, blue } = RGB; +// // let warmWhite; +// // let colorMask = 0xF0; - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - // red = Math.round((red / 100) * brightness); - // green = Math.round((green / 100) * brightness); - // blue = Math.round((blue / 100) * brightness); - warmWhite = Math.round(2.55 * brightness); +// // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// // // red = Math.round((red / 100) * brightness); +// // // green = Math.round((green / 100) * brightness); +// // // blue = Math.round((blue / 100) * brightness); +// // warmWhite = Math.round(2.55 * brightness); - if (hue == 31 && saturation == 33) { +// // if (hue == 31 && saturation == 33) { - red = 0; - green = 0; - blue = 0; - colorMask = 0x0F; +// // red = 0; +// // green = 0; +// // blue = 0; +// // colorMask = 0x0F; - } else if (saturation < 20) { +// // } else if (saturation < 20) { - red = 0; - green = 0; - blue = 0; - colorMask = 0x0F; +// // red = 0; +// // green = 0; +// // blue = 0; +// // colorMask = 0x0F; - } else { - warmWhite = 0; - } +// // } else { +// // warmWhite = 0; +// // } - const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; - return deviceCommand; +// // const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; +// // return deviceCommand; - }//setColor +// // }//setColor - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { +// // deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - // eslint-disable-next-line prefer-const - let { hue, saturation, luminance } = convertRGBtoHSL(RGB); - let brightness = 0; - let colorTemperature = 140; - if (luminance > 0 && isOn) { - brightness = luminance; - } else if (isOn) { - brightness = clamp(warmWhite / 2.55, 0, 100); - } +// // const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; +// // // eslint-disable-next-line prefer-const +// // let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// // let brightness = 0; +// // let colorTemperature = 140; +// // if (luminance > 0 && isOn) { +// // brightness = luminance; +// // } else if (isOn) { +// // brightness = clamp(warmWhite / 2.55, 0, 100); +// // } - if (warmWhite > 0) { - saturation = luminance; - colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); - if (saturation <= 2) { - const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); - hue = hueSat[0]; - saturation = 10; - } - } +// // if (warmWhite > 0) { +// // saturation = luminance; +// // colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); +// // if (saturation <= 2) { +// // const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// // hue = hueSat[0]; +// // saturation = 10; +// // } +// // } - const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; - return accessoryState; - } +// // const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; +// // return accessoryState; +// // } -} \ No newline at end of file +// } \ No newline at end of file diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 5a4ffa1..28c95c3 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -1,86 +1,86 @@ -import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp, convertMiredColorTemperatureToHueSat, whiteTemperatureToCCT } from '../misc/utils'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - - -export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - - const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - const { hue, saturation } = HSL; - const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); - let { red, green, blue } = RGB, warmWhite; - - let colorMask = 0xFF; - - warmWhite = Math.round(2.55 * brightness); - - if (hue == 31 && saturation == 33) { - - red = 0; - green = 0; - blue = 0; - colorMask = 0x0F; - - } else if (saturation < this.colorOffSaturationLevel) { - red = 0; - green = 0; - blue = 0; - - /** - * else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" - * set RGB to 100% saturation and 100% brightness - * this allows brightness to only affect the white colors, creating beautiful white+color balance - * we've set the color saturation to 100% because the higher the white level the more washed out the colors become - * the white brightness effectively acts as the saturation value - */ - - } else if (saturation < this.colorWhiteSimultaniousSaturationLevel) { - - const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation - red = _RGB.red; - green = _RGB.green; - blue = _RGB.blue; - - red = Math.round((red / 100) * (saturation * 2)); - green = Math.round((green / 100) * (saturation * 2)); - blue = Math.round((blue / 100) * (saturation * 2)); - - } else { - warmWhite = 0; - } - - const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; - return deviceCommand; - } - - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - - const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - // eslint-disable-next-line prefer-const - let { hue, saturation, luminance } = convertRGBtoHSL(RGB); - let brightness = 0; - let colorTemperature = 140; - if (luminance > 0 && isOn) { - brightness = luminance; - if (coldWhite > 0 || warmWhite > 0) { - saturation = 25; - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - } - } else { - if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - } - colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); - const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); - hue = hueSat[0]; - saturation = 10; - - } - - const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; - return accessoryState; - } -} \ No newline at end of file +// // import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// // import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// // import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp, convertMiredColorTemperatureToHueSat, whiteTemperatureToCCT } from '../misc/utils'; +// // import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + + +// export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { + +// // protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + +// // const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; +// // const { hue, saturation } = HSL; +// // const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); +// // let { red, green, blue } = RGB, warmWhite; + +// // let colorMask = 0xFF; + +// // warmWhite = Math.round(2.55 * brightness); + +// // if (hue == 31 && saturation == 33) { + +// // red = 0; +// // green = 0; +// // blue = 0; +// // colorMask = 0x0F; + +// // } else if (saturation < this.colorOffSaturationLevel) { +// // red = 0; +// // green = 0; +// // blue = 0; + +// // /** +// // * else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" +// // * set RGB to 100% saturation and 100% brightness +// // * this allows brightness to only affect the white colors, creating beautiful white+color balance +// // * we've set the color saturation to 100% because the higher the white level the more washed out the colors become +// // * the white brightness effectively acts as the saturation value +// // */ + +// // } else if (saturation < this.colorWhiteSimultaniousSaturationLevel) { + +// // const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation +// // red = _RGB.red; +// // green = _RGB.green; +// // blue = _RGB.blue; + +// // red = Math.round((red / 100) * (saturation * 2)); +// // green = Math.round((green / 100) * (saturation * 2)); +// // blue = Math.round((blue / 100) * (saturation * 2)); + +// // } else { +// // warmWhite = 0; +// // } + +// // const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; +// // return deviceCommand; +// // } + +// // deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// // const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; +// // // eslint-disable-next-line prefer-const +// // let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// // let brightness = 0; +// // let colorTemperature = 140; +// // if (luminance > 0 && isOn) { +// // brightness = luminance; +// // if (coldWhite > 0 || warmWhite > 0) { +// // saturation = 25; +// // brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// // } +// // } else { +// // if (isOn) { +// // brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// // } +// // colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); +// // const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// // hue = hueSat[0]; +// // saturation = 10; + +// // } + +// // const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; +// // return accessoryState; +// // } +// } \ No newline at end of file diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index 48b7450..4c8bd10 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -1,95 +1,95 @@ -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; +// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; -export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { +// export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { +// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - const { hue, saturation } = HSL; +// const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; +// const { hue, saturation } = HSL; - const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); - // let _CCT: IColorCCT; - // if (this.ColorCommandMode == 'HSL') { - const _CCT: IColorCCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" - // } else { - // _CCT = cctToWhiteTemperature(colorTemperature); - // } - let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; - - let colorMask = 0xF0; - - - - //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed - //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) - red = Math.round((red / 100) * brightness); - green = Math.round((green / 100) * brightness); - blue = Math.round((blue / 100) * brightness); - warmWhite = Math.round((warmWhite / 100) * brightness); - coldWhite = Math.round((coldWhite / 100) * brightness); - - - if (hue == 31 && saturation == 33) { - - red = 0; - green = 0; - blue = 0; - coldWhite = 0; - colorMask = 0x0F; - } else if (hue == 208 && saturation == 17) { - - red = 0; - green = 0; - blue = 0; - warmWhite = 0; - colorMask = 0x0F; - - //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). - //White colors were already calculated above - } else if (saturation < 20) { - - red = 0; - green = 0; - blue = 0; - - colorMask = 0x0F; - } else { - warmWhite = 0; - coldWhite = 0; - } - - const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; - return deviceCommand; - - }//setColor - - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - // eslint-disable-next-line prefer-const - let { hue, saturation, luminance } = convertRGBtoHSL(RGB); - let brightness = 0; - let colorTemperature = 140; - if (luminance > 0 && isOn) { - brightness = luminance; - if (coldWhite > 0 || warmWhite > 0) { - saturation = 25; - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - } - } else { - if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - } - colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); - const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); - hue = hueSat[0]; - saturation = 10; - - } - const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; - return accessoryState; - } - -} \ No newline at end of file +// const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); +// // let _CCT: IColorCCT; +// // if (this.ColorCommandMode == 'HSL') { +// const _CCT: IColorCCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" +// // } else { +// // _CCT = cctToWhiteTemperature(colorTemperature); +// // } +// let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; + +// let colorMask = 0xF0; + + + +// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// red = Math.round((red / 100) * brightness); +// green = Math.round((green / 100) * brightness); +// blue = Math.round((blue / 100) * brightness); +// warmWhite = Math.round((warmWhite / 100) * brightness); +// coldWhite = Math.round((coldWhite / 100) * brightness); + + +// if (hue == 31 && saturation == 33) { + +// red = 0; +// green = 0; +// blue = 0; +// coldWhite = 0; +// colorMask = 0x0F; +// } else if (hue == 208 && saturation == 17) { + +// red = 0; +// green = 0; +// blue = 0; +// warmWhite = 0; +// colorMask = 0x0F; + +// //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). +// //White colors were already calculated above +// } else if (saturation < 20) { + +// red = 0; +// green = 0; +// blue = 0; + +// colorMask = 0x0F; +// } else { +// warmWhite = 0; +// coldWhite = 0; +// } + +// const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; +// return deviceCommand; + +// }//setColor + +// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { +// const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; +// // eslint-disable-next-line prefer-const +// let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// let brightness = 0; +// let colorTemperature = 140; +// if (luminance > 0 && isOn) { +// brightness = luminance; +// if (coldWhite > 0 || warmWhite > 0) { +// saturation = 25; +// brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// } +// } else { +// if (isOn) { +// brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// } +// colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); +// const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// hue = hueSat[0]; +// saturation = 10; + +// } +// const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; +// return accessoryState; +// } + +// } \ No newline at end of file diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index 915295c..55c5680 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -1,110 +1,110 @@ -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - - const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - - const { hue, saturation } = HSL; - const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); - - // let _CCT: IColorCCT; - // if (this.ColorCommandMode == 'HSL') { - const _CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "convertHueToColorCCT()" - // } else { - // _CCT = cctToWhiteTemperature(colorTemperature); - // } - let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; - let colorMask = 0xFF; - - warmWhite = Math.round((warmWhite / 100) * brightness); - coldWhite = Math.round((coldWhite / 100) * brightness); - - if (hue == 31 && saturation == 33) { - - red = 0; - green = 0; - blue = 0; - coldWhite = 0; - colorMask = 0x0F; - - } else if (hue == 208 && saturation == 17) { - red = 0; - green = 0; - blue = 0; - warmWhite = 0; - colorMask = 0x0F; - - //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). - //White colors were already calculated above - } else if (saturation <= 2) { - - red = 0; - green = 0; - blue = 0; - - //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" - //set RGB to 100% saturation and 100% brightness - //this allows brightness to only affect the white colors, creating beautiful white+color balance - //we've set the color saturation to 100% because the higher the white level the more washed out the colors become - //the white brightness effectively acts as the saturation value - } else if (saturation <= 50) { - - const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation - red = _RGB.red; - green = _RGB.green; - blue = _RGB.blue; - - red = Math.round((red / 100) * (saturation * 2)); - green = Math.round((green / 100) * (saturation * 2)); - blue = Math.round((blue / 100) * (saturation * 2)); - - - //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs - } else { - warmWhite = 0; - coldWhite = 0; - } - - const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; - return deviceCommand; - }//setColor - - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - - const { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - - // eslint-disable-next-line prefer-const - let { hue, saturation, luminance } = convertRGBtoHSL(RGB); - let brightness = 0; - let colorTemperature = 140; - - //Brightness - if (isOn) { - if (coldWhite == 0 && warmWhite == 0) { - brightness = luminance; - } else { - brightness = clamp((Math.max(coldWhite / 2.55), (warmWhite / 2.55)), 0, 100); - } - } - //Hue && Saturation - if (coldWhite > 0 || warmWhite > 0) { - saturation = luminance; - colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); - if (saturation <= 2) { - const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); - hue = hueSat[0]; - saturation = 10; - } - } - - const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; - return accessoryState; - } -} +// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +// export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { + +// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + +// const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + +// const { hue, saturation } = HSL; +// const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); + +// // let _CCT: IColorCCT; +// // if (this.ColorCommandMode == 'HSL') { +// const _CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "convertHueToColorCCT()" +// // } else { +// // _CCT = cctToWhiteTemperature(colorTemperature); +// // } +// let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; +// let colorMask = 0xFF; + +// warmWhite = Math.round((warmWhite / 100) * brightness); +// coldWhite = Math.round((coldWhite / 100) * brightness); + +// if (hue == 31 && saturation == 33) { + +// red = 0; +// green = 0; +// blue = 0; +// coldWhite = 0; +// colorMask = 0x0F; + +// } else if (hue == 208 && saturation == 17) { +// red = 0; +// green = 0; +// blue = 0; +// warmWhite = 0; +// colorMask = 0x0F; + +// //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). +// //White colors were already calculated above +// } else if (saturation <= 2) { + +// red = 0; +// green = 0; +// blue = 0; + +// //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" +// //set RGB to 100% saturation and 100% brightness +// //this allows brightness to only affect the white colors, creating beautiful white+color balance +// //we've set the color saturation to 100% because the higher the white level the more washed out the colors become +// //the white brightness effectively acts as the saturation value +// } else if (saturation <= 50) { + +// const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation +// red = _RGB.red; +// green = _RGB.green; +// blue = _RGB.blue; + +// red = Math.round((red / 100) * (saturation * 2)); +// green = Math.round((green / 100) * (saturation * 2)); +// blue = Math.round((blue / 100) * (saturation * 2)); + + +// //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs +// } else { +// warmWhite = 0; +// coldWhite = 0; +// } + +// const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; +// return deviceCommand; +// }//setColor + +// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// const { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } = deviceState; + +// // eslint-disable-next-line prefer-const +// let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// let brightness = 0; +// let colorTemperature = 140; + +// //Brightness +// if (isOn) { +// if (coldWhite == 0 && warmWhite == 0) { +// brightness = luminance; +// } else { +// brightness = clamp((Math.max(coldWhite / 2.55), (warmWhite / 2.55)), 0, 100); +// } +// } +// //Hue && Saturation +// if (coldWhite > 0 || warmWhite > 0) { +// saturation = luminance; +// colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); +// if (saturation <= 2) { +// const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// hue = hueSat[0]; +// saturation = 10; +// } +// } + +// const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; +// return accessoryState; +// } +// } diff --git a/src/misc/types.ts b/src/misc/types.ts index 8512664..c3fb4cc 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -1,28 +1,28 @@ import type { PlatformAccessory } from 'homebridge'; import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation, IDeviceMetaData, IProtoDevice } from 'magichome-platform'; -import { Switch } from '../accessories/Switch'; -import { DimmerStrip } from '../accessories/DimmerStrip'; -import { RGBStrip } from '../accessories/RGBStrip'; -import { GRBStrip } from '../accessories/GRBStrip'; -import { RGBWBulb } from '../accessories/RGBWBulb'; -import { RGBWWBulb } from '../accessories/RGBWWBulb'; -import { RGBWStrip } from '../accessories/RGBWStrip'; -import { RGBWWStrip } from '../accessories/RGBWWStrip'; -import { CCTStrip } from '../accessories/CCTStrip'; +// import { Switch } from '../accessories/Switch'; +// import { DimmerStrip } from '../accessories/DimmerStrip'; +// import { RGBStrip } from '../accessories/RGBStrip'; +// import { GRBStrip } from '../accessories/GRBStrip'; +// import { RGBWBulb } from '../accessories/RGBWBulb'; +// import { RGBWWBulb } from '../accessories/RGBWWBulb'; +// import { RGBWStrip } from '../accessories/RGBWStrip'; +// import { RGBWWStrip } from '../accessories/RGBWWStrip'; +// import { CCTStrip } from '../accessories/CCTStrip'; -export const homekitInterface = { - // 'Power Socket': Switch, - // 'Dimmer': DimmerStrip, - // 'GRB Strip': GRBStrip, - // 'RGB Strip': RGBStrip, - 'RGBW Non-Simultaneous': RGBWBulb, - 'RGBWW Non-Simultaneous': RGBWWBulb, - 'RGBW Simultaneous': RGBWStrip, - 'RGBWW Simultaneous': RGBWWStrip, - // 'CCT Strip': CCTStrip, -}; +// export const homekitInterface = { +// // 'Power Socket': Switch, +// // 'Dimmer': DimmerStrip, +// // 'GRB Strip': GRBStrip, +// // 'RGB Strip': RGBStrip, +// 'RGBW Non-Simultaneous': RGBWBulb, +// 'RGBWW Non-Simultaneous': RGBWWBulb, +// 'RGBW Simultaneous': RGBWStrip, +// 'RGBWW Simultaneous': RGBWWStrip, +// // 'CCT Strip': CCTStrip, +// }; export interface MagicHomeAccessory extends PlatformAccessory { context: IAccessoryContext @@ -37,23 +37,23 @@ export interface IAccessoryContext { export interface IAccessoryState { isOn: boolean, - HSL: IColorHSL, - colorTemperature?: number, + HSV: IColorHSV, brightness: number, + colorTemperature?: number, } export interface IAccessoryCommand { isOn?: boolean, - HSL?: IColorHSL, + HSV?: IColorHSV, colorTemperature?: number, brightness?: number, isPowerCommand?: boolean, } -export interface IColorHSL { - hue?: number; - saturation?: number; - luminance?: number; +export interface IColorHSV { + hue: number; + saturation: number; + value: number; } @@ -68,16 +68,16 @@ export interface IConfigOptions { export const ColorCommandModes = { CCT: 'CCT', - HSL: 'HSL', + HSV: 'HSV', }; export const DefaultAccessoryCommand = { - isOn: true, - HSL: { + isOn: false, + HSV: { hue: 0, - saturation: 100, - luminance: 0, + saturation: 0, + value: 0, }, - colorTemperature: 140, - brightness: 100, + colorTemperature: 0, + brightness: 0, }; \ No newline at end of file diff --git a/src/misc/utils.ts b/src/misc/utils.ts index 7289aeb..1d1ab23 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -1,6 +1,6 @@ import { existsSync, readFileSync } from 'fs'; import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -import { IAccessoryCommand, IAccessoryState, IColorHSL } from './types'; +import { IAccessoryCommand, IAccessoryState, IColorHSV } from './types'; export function clamp(value: number, min: number, max: number) { @@ -32,46 +32,46 @@ export function checksum(buffer: Uint8Array) { //================================================= // Start Convert RGBtoHSL // -export function convertRGBtoHSL(RGB: IColorRGB) { - - const { red, green, blue } = RGB; - - - const r = red / 255; - const g = green / 255; - const b = blue / 255; - - let h, s, l; - h = s = l = 0; - - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - const C = max - min; - if (C == 0) { - h = 0; - } else if (max == r) { - h = ((g - b) / C) % 6; - } else if (max == g) { - h = (b - r) / C + 2; - } else { - h = (r - g) / C + 4; - } - h *= 60; - if (h < 0) { - h += 360; - } - l = max; - if (l == 0) { - s = 0; - } else { - s = C / l; - } - s *= 100; - l *= 100; - - const HSL: IColorHSL = { hue: Math.floor(h), saturation: Math.floor(s), luminance: Math.floor(l) }; - return HSL; -} +// export function convertRGBtoHSL(RGB: IColorRGB) { + +// const { red, green, blue } = RGB; + + +// const r = red / 255; +// const g = green / 255; +// const b = blue / 255; + +// let h, s, l; +// h = s = l = 0; + +// const max = Math.max(r, g, b); +// const min = Math.min(r, g, b); +// const C = max - min; +// if (C == 0) { +// h = 0; +// } else if (max == r) { +// h = ((g - b) / C) % 6; +// } else if (max == g) { +// h = (b - r) / C + 2; +// } else { +// h = (r - g) / C + 4; +// } +// h *= 60; +// if (h < 0) { +// h += 360; +// } +// l = max; +// if (l == 0) { +// s = 0; +// } else { +// s = C / l; +// } +// s *= 100; +// l *= 100; + +// const HSL: IColorHSL = { hue: Math.floor(h), saturation: Math.floor(s), luminance: Math.floor(l) }; +// return HSL; +// } //================================================= // End Convert RGBtoHSL // @@ -79,55 +79,55 @@ export function convertRGBtoHSL(RGB: IColorRGB) { //================================================= // Start Convert HSLtoRGB // -export function convertHSLtoRGB(HSL: IColorHSL) { - - const { hue, saturation, luminance } = HSL; - - const h = hue; - const s = saturation / 100.0; - const l = luminance / 100.0; - - const C = l * s; - const hh = h / 60.0; - const X = C * (1.0 - Math.abs((hh % 2) - 1.0)); - - let r, g, b; - r = g = b = 0; - - if (hh >= 0 && hh < 1) { - r = C; - g = X; - } else if (hh >= 1 && hh < 2) { - r = X; - g = C; - } else if (hh >= 2 && hh < 3) { - g = C; - b = X; - } else if (hh >= 3 && hh < 4) { - g = X; - b = C; - } else if (hh >= 4 && hh < 5) { - r = X; - b = C; - } else { - r = C; - b = X; - } - - const m = l - C; - r += m; - g += m; - b += m; - r *= 255.0; - g *= 255.0; - b *= 255.0; - r = Math.floor(r); - g = Math.floor(g); - b = Math.floor(b); - - let RGB = Object.assign({}, { red: r, green: g, blue: b }); - return RGB; -} +// export function convertHSLtoRGB(HSL: IColorHSL) { + +// const { hue, saturation, luminance } = HSL; + +// const h = hue; +// const s = saturation / 100.0; +// const l = luminance / 100.0; + +// const C = l * s; +// const hh = h / 60.0; +// const X = C * (1.0 - Math.abs((hh % 2) - 1.0)); + +// let r, g, b; +// r = g = b = 0; + +// if (hh >= 0 && hh < 1) { +// r = C; +// g = X; +// } else if (hh >= 1 && hh < 2) { +// r = X; +// g = C; +// } else if (hh >= 2 && hh < 3) { +// g = C; +// b = X; +// } else if (hh >= 3 && hh < 4) { +// g = X; +// b = C; +// } else if (hh >= 4 && hh < 5) { +// r = X; +// b = C; +// } else { +// r = C; +// b = X; +// } + +// const m = l - C; +// r += m; +// g += m; +// b += m; +// r *= 255.0; +// g *= 255.0; +// b *= 255.0; +// r = Math.floor(r); +// g = Math.floor(g); +// b = Math.floor(b); + +// let RGB = Object.assign({}, { red: r, green: g, blue: b }); +// return RGB; +// } //================================================= // End Convert HSLtoRGB // @@ -180,6 +180,74 @@ export function convertHueToColorCCT(hue: number): IColorCCT { return { warmWhite, coldWhite }; } //hueToWhiteTemperature +/* +HSV to RGB conversion formula +When 0 ≤ H < 360, 0 ≤ S ≤ 1 and 0 ≤ V ≤ 1: +C = V × S +X = C × (1 - |(H / 60°) mod 2 - 1|) +m = V - C +(R,G,B) = ((R'+m)×255, (G'+m)×255, (B'+m)×255) +*/ + +export function HSVtoRGB(HSV: IColorHSV): IColorRGB { + const { hue, saturation, value }: IColorHSV = HSV; + let [H, S, V] = [hue, saturation, value]; + H = clamp(H, 0, 359) + S = clamp(S, 0, 100) + V = clamp(V, 0, 100) + + // console.log("-- SENDING -- H: ", H, "S: ", S, "V: ", V) + S /= 100.0 + V /= 100.0 + const C = V * S; + const X = C * (1 - Math.abs(((H / 60) % 2) - 1)) + const m = V - C; + + let order; + if (H < 60) order = [C, X, 0]; + else if (H < 120) order = [X, C, 0]; + else if (H < 180) order = [0, C, X]; + else if (H < 240) order = [0, X, C]; + else if (H < 300) order = [X, 0, C]; + else if (H < 360) order = [C, 0, X]; + + const [dR, dG, dB] = order; + const [red, green, blue] = [(dR + m) * 255, (dG + m) * 255, (dB + m) * 255] + // console.log(`--SENDING-- RED: ${red} GREEN: ${green} BLUE: ${blue}`) + return { red, green, blue }; +} + +export function RGBtoHSV(RGB: IColorRGB): IColorHSV { + + const { red, green, blue }: IColorRGB = RGB; + + // console.log(`--RECEIVING-- RED: ${red} GREEN: ${green} BLUE: ${blue}`) + + const [R, G, B] = [red, green, blue]; + const [dR, dG, dB] = [R / 255, G / 255, B / 255]; + + const Dmax = Math.max(dR, dG, dB); + const Dmin = Math.min(dR, dG, dB); + const D = Dmax - Dmin; + + let H, S, V; + if (D === 0) H = 0; + else if (Dmax === dR) H = ((dG - dB) / D) % 6; + else if (Dmax === dG) H = ((dB - dR) / D) + 2; + else H = ((dR - dG) / D) + 4 + H *= 60; + if (H < 0) H += 360; + V = Dmax; + if (V === 0) S = 0; + else S = D / V; + + S *= 100; + V *= 100; + // console.log("-- RECEIVED -- H: ", H, "S: ", S, "V: ", V) + + return { hue: H, saturation: S, value: V }; +} + export function cctToWhiteTemperature(CCT: number, multiplier = 0): { warmWhite: number, coldWhite: number } { CCT -= 140; let warmWhite, coldWhite; @@ -211,73 +279,73 @@ export function delayToSpeed(delay: never) { clamped -= 1; // bring into interval [0, 30] return 100 - (clamped / 30) * 100; } - + export function speedToDelay(speed: never) { const clamped = clamp(speed, 0, 100); return 30 - (clamped / 100) * 30 + 1; } */ -export function convertMiredColorTemperatureToHueSat(temperature: number): [number, number] { - const xy = convertMiredColorTemperatureToXY(500 - temperature); - return convertXyToHueSat(xy[0], xy[1]); -} - -export function convertXyToHueSat(x: number, y: number): [number, number] { - // Based on: https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/ - const z: number = 1.0 - x - y; - const Y = 1.0; - const X: number = (Y / y) * x; - const Z: number = (Y / y) * z; - - // sRGB D65 conversion - let r: number = (X * 1.656492) - (Y * 0.354851) - (Z * 0.255038); - let g: number = (-X * 0.707196) + (Y * 1.655397) + (Z * 0.036152); - let b: number = (X * 0.051713) - (Y * 0.121364) + (Z * 1.011530); - - // Remove negative values - const m = Math.min(r, g, b); - if (m < 0.0) { - r -= m; - g -= m; - b -= m; - } - - // Normalize - if (r > b && r > g && r > 1.0) { - // red is too big - g = g / r; - b = b / r; - r = 1.0; - } else if (g > b && g > r && g > 1.0) { - // green is too big - r = r / g; - b = b / g; - g = 1.0; - } else if (b > r && b > g && b > 1.0) { - // blue is too big - r = r / b; - g = g / b; - b = 1.0; - } - - // Gamma correction - r = reverseGammaCorrection(r); - g = reverseGammaCorrection(g); - b = reverseGammaCorrection(b); - - // Maximize - const max = Math.max(r, g, b); - r = (r === max) ? 255 : (255 * (r / max)); - g = (g === max) ? 255 : (255 * (g / max)); - b = (b === max) ? 255 : (255 * (b / max)); - - const RGB: IColorRGB = { red: r, green: g, blue: b }; - const HSL = convertRGBtoHSL(RGB); - - const hsv = [HSL.hue, HSL.saturation]; - - return [hsv[0], hsv[1]]; -} +// export function convertMiredColorTemperatureToHueSat(temperature: number): [number, number] { +// const xy = convertMiredColorTemperatureToXY(500 - temperature); +// return convertXyToHueSat(xy[0], xy[1]); +// } + +// export function convertXyToHueSat(x: number, y: number): [number, number] { +// // Based on: https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/ +// const z: number = 1.0 - x - y; +// const Y = 1.0; +// const X: number = (Y / y) * x; +// const Z: number = (Y / y) * z; + +// // sRGB D65 conversion +// let r: number = (X * 1.656492) - (Y * 0.354851) - (Z * 0.255038); +// let g: number = (-X * 0.707196) + (Y * 1.655397) + (Z * 0.036152); +// let b: number = (X * 0.051713) - (Y * 0.121364) + (Z * 1.011530); + +// // Remove negative values +// const m = Math.min(r, g, b); +// if (m < 0.0) { +// r -= m; +// g -= m; +// b -= m; +// } + +// // Normalize +// if (r > b && r > g && r > 1.0) { +// // red is too big +// g = g / r; +// b = b / r; +// r = 1.0; +// } else if (g > b && g > r && g > 1.0) { +// // green is too big +// r = r / g; +// b = b / g; +// g = 1.0; +// } else if (b > r && b > g && b > 1.0) { +// // blue is too big +// r = r / b; +// g = g / b; +// b = 1.0; +// } + +// // Gamma correction +// r = reverseGammaCorrection(r); +// g = reverseGammaCorrection(g); +// b = reverseGammaCorrection(b); + +// // Maximize +// const max = Math.max(r, g, b); +// r = (r === max) ? 255 : (255 * (r / max)); +// g = (g === max) ? 255 : (255 * (g / max)); +// b = (b === max) ? 255 : (255 * (b / max)); + +// const RGB: IColorRGB = { red: r, green: g, blue: b }; +// const HSL = convertRGBtoHSL(RGB); + +// const hsv = [HSL.hue, HSL.saturation]; + +// return [hsv[0], hsv[1]]; +// } function convertMiredColorTemperatureToXY(temperature: number): [number, number] { // Based on MiredColorTemperatureToXY from: diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 433bdeb..ce6c6d9 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -4,15 +4,15 @@ import type { } from 'homebridge'; import { CharacteristicEventTypes } from 'homebridge'; -import { clamp, convertHSLtoRGB, convertRGBtoHSL } from './misc/utils'; +import { clamp, HSVtoRGB, RGBtoHSV } from './misc/utils'; import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep } from 'magichome-platform'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE } from 'magichome-platform'; import { Logs } from './logs'; const CCT = 'CCT'; -const HSL = 'HSL'; -const DEFAULT_ACCESSORY_STATE: IAccessoryState = { isOn: false, HSL: { hue: 0, saturation: 0, luminance: 50 }, brightness: 100 } +const HSV = 'HSV'; +const DEFAULT_ACCESSORY_STATE: IAccessoryState = { isOn: false, HSV: { hue: 0, saturation: 0, value: 0 }, brightness: 0 }; /** * Platform Accessory * An instance of this class is created for each accessory your platform registers @@ -29,7 +29,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected accessoryState: IAccessoryState; - protected ColorCommandMode = HSL; + protected ColorCommandMode = HSV; protected colorWhiteSimultaniousSaturationLevel; protected colorOffSaturationLevel; @@ -76,27 +76,26 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setHue(value: CharacteristicValue) { - this.accessoryState.HSL.hue = value as number; - this.ColorCommandMode = HSL; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { hue: value as number } }; + + this.accessoryState.HSV.hue = value as number; + this.ColorCommandMode = HSV; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; this.processAccessoryCommand(accessoryCommand); } setSaturation(value: CharacteristicValue) { - this.accessoryState.HSL.saturation = value as number; - - this.ColorCommandMode = HSL; - - const accessoryCommand: IAccessoryCommand = { isOn: true, HSL: { saturation: value as number } }; + this.accessoryState.HSV.saturation = value as number; + this.ColorCommandMode = HSV; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; this.processAccessoryCommand(accessoryCommand); } async setBrightness(value: CharacteristicValue) { - + this.accessoryState.HSV.value = value as number; this.accessoryState.brightness = value as number; - const accessoryCommand: IAccessoryCommand = { isOn: true, brightness: value as number }; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; this.processAccessoryCommand(accessoryCommand); } @@ -112,6 +111,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { const name: string = value.toString(); this.logs.warn('Renaming device to %o', name); this.accessory.context.displayName = name; + console.log(this.accessory.context.displayName) this.api.updatePlatformAccessories([this.accessory]); } @@ -127,35 +127,34 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start Getters // getHue() { - const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + const { isOn, HSV: { hue, saturation } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - this.fetchAndUpdateState(2); + // this.fetchAndUpdateState(2); return hue; } - // getColorTemperature() { - // const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) + getColorTemperature() { + const { isOn, HSV: { hue, saturation }, brightness, colorTemperature } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - // const colorTemperature = this.accessory.context.accessoryState.colorTemperature; - // this.fetchAndUpdateState(3); - // return colorTemperature; - // } + this.fetchAndUpdateState(3); + return colorTemperature; + } getBrightness() { - const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + const { isOn, HSV: { hue, saturation, value }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - this.fetchAndUpdateState(2); + // this.fetchAndUpdateState(2); return brightness; } - /** + /** ** @getOn * instantly retrieve the current on/off state stored in our object * next call this.getState() which will update all values asynchronously as they are ready */ async getOn() { - const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + const { isOn, HSV: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); this.fetchAndUpdateState(2); return isOn; @@ -170,9 +169,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { - // for (const interval of this.intervals) { - // this.controller.clearAnimations(); - //} await this.prepareCommand(accessoryCommand); } @@ -181,20 +177,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { try { this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState ); - console.log(accessoryCommand) - console.log(sanitizedAcessoryCommand) - if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSL') || accessoryCommand.hasOwnProperty('brightness'))) { + const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState); + // console.log(accessoryCommand) + // console.log(sanitizedAcessoryCommand) + if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; } - const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand); + const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: true, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, remainingRetries: 5 }); return completeResponse; } catch (error) { this.hbLogger.error(error); } } - protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions?: ICommandOptions): Promise { + protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions): Promise { try { @@ -203,7 +199,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { let response; if (!accessoryCommand.isPowerCommand) { - response = await this.controller.setAllValues(deviceCommand); + // console.log(commandOptions) + response = await this.controller.setAllValues(deviceCommand, commandOptions); } else { response = await this.controller.setOn(deviceCommand.isOn); } @@ -216,13 +213,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - - const RGB = convertHSLtoRGB(HSL); - RGB.red = Math.round((RGB.red / 100) * brightness); - RGB.green = Math.round((RGB.green / 100) * brightness); - RGB.blue = Math.round((RGB.blue / 100) * brightness); + const { isOn, HSV, colorTemperature, brightness } = accessoryCommand; + const RGB = HSVtoRGB(HSV); const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; return deviceCommand; @@ -232,30 +225,29 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { try { if (!deviceState) { deviceState = await this.controller?.fetchState(); - // ?? this.accessory.context.cachedDeviceInformation.deviceState; } this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; - const { HSL: { hue, saturation, luminance }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); + const { HSV: { hue, saturation, value }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); let accessoryState: IAccessoryState; if (deviceState) { switch (requestLevel) { case 0: - // accessoryState = { HSL: { luminance }, isOn }; + // accessoryState = { HSV: { value }, isOn }; break; case 1: - // accessoryState = { HSL: { hue, luminance }, isOn }; + // accessoryState = { HSV: { hue, value }, isOn }; break; case 2: - accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; + accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; break; case 3: - accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness, colorTemperature }; + accessoryState = { HSV: { hue, saturation, value }, isOn, brightness, colorTemperature }; break; } this.accessoryState = accessoryState; - + console.log(accessoryState) this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); } @@ -265,7 +257,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } updateHomekitState() { - const { isOn, HSL: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + const { isOn, HSV: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); @@ -275,23 +267,24 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - //TODO - REPLACE HSL WITH HSV + //TODO - REPLACE HSV WITH HSV // eslint-disable-next-line prefer-const - let { hue, saturation, luminance } = convertRGBtoHSL(RGB); + let { hue, saturation, value } = RGBtoHSV(RGB); let brightness = 0; - if (luminance > 0 && isOn) { - brightness = luminance * 2; - } else if (isOn) { - brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); - if (warmWhite > coldWhite) { - saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); - } else { - saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); - } + if (value > 0) { + brightness = value; } + // else if (isOn) { + // brightness = clamp(Math.max(coldWhite, warmWhite) / 2.55, 0, 100); + // if (warmWhite > coldWhite) { + // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); + // } else { + // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); + // } + // } - const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; + const accessoryState: IAccessoryState = { HSV: { hue, saturation, value }, isOn, colorTemperature: 140, brightness }; return accessoryState; } @@ -386,18 +379,18 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { .onGet(this.getBrightness.bind(this)); } - addColorTemperatureCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.ColorTemperature); - // .onSet(this.setColorTemperature.bind(this)) - // .onGet(this.getColorTemperature.bind(this)); - - if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); - this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service); - this.accessory.configureController(this.adaptiveLightingService); - } - } + // addColorTemperatureCharacteristic() { + // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); + // this.service.getCharacteristic(this.hap.Characteristic.ColorTemperature) + // .onSet(this.setColorTemperature.bind(this)) + // .onGet(this.getColorTemperature.bind(this)); + + // if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { + // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); + // this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service); + // this.accessory.configureController(this.adaptiveLightingService); + // } + // } addAccessoryInformationCharacteristic() { From a106e5aa4161b924ab00bfc9991f8b2eda3ecbef Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Wed, 24 Aug 2022 12:19:12 -0400 Subject: [PATCH 32/42] Basic animation functionality --- package.json | 1 - src/AccessoryGenerator.ts | 34 +- src/AnimationGenerator.ts | 163 +++++++ src/animationAccessory.ts | 642 +++++++++++++++++++++++++++ src/misc/types.ts | 12 +- src/misc/utils.ts | 8 +- src/platform.ts | 31 +- src/platformAccessory.ts | 134 +++--- src/specs/controllerCreation.spec.ts | 15 + 9 files changed, 939 insertions(+), 101 deletions(-) create mode 100644 src/AnimationGenerator.ts create mode 100644 src/animationAccessory.ts create mode 100644 src/specs/controllerCreation.spec.ts diff --git a/package.json b/package.json index fe284c3..4d7da08 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,6 @@ "smart lights" ], "dependencies": { - "color-convert": "^2.0.1", "homebridge-lib": "^5.1.14" }, "devDependencies": { diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 2d8ec68..199fe7c 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -5,7 +5,6 @@ import { API, HAP, PlatformAccessory, PlatformConfig } from 'homebridge'; // import { homekitInterface } from './misc/types'; import { Logs } from './logs'; import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -import { Console } from 'console'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; @@ -22,6 +21,7 @@ export class AccessoryGenerator { private config: PlatformConfig; private controllerGenerator: ControllerGenerator; private logs: Logs; + activeAccessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[]; constructor(api, logs, hbLogger, config, accessoriesFromDiskMap, controllerGenerator) { this.api = api; this.hap = api.hap; @@ -30,9 +30,10 @@ export class AccessoryGenerator { this.config = config; this.accessoriesFromDiskMap = accessoriesFromDiskMap; this.controllerGenerator = controllerGenerator; + this.activeAccessoriesList = []; } - public async discoverDevices() { + public async discoverDevices(): Promise { this.logs.info('Scanning network for MagicHome accessories...'); try { @@ -40,8 +41,9 @@ export class AccessoryGenerator { const controllers: BaseController[] = await this.controllerGenerator.generateControllers(completeDevices); - await this.generateActiveAccessories(controllers); + const activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] = await this.generateActiveAccessories(controllers); // this.registerOfflineAccessories(); + return activeAccessories; } catch (error) { this.logs.error(error); } @@ -77,25 +79,23 @@ export class AccessoryGenerator { * which is quite wasteful... */ - async generateActiveAccessories(controllers: BaseController[]) { + generateActiveAccessories(controllers: BaseController[]): HomebridgeMagichomeDynamicPlatformAccessory[] { const newAccessoriesList: MagicHomeAccessory[] = []; const existingAccessoriesList: MagicHomeAccessory[] = []; for (const controller of controllers) { try { - // console.log(controller) const { protoDevice: { uniqueId }, deviceState, deviceAPI } = controller.getCachedDeviceInformation(); let currAccessory: MagicHomeAccessory; if (this.accessoriesFromDiskMap.has(uniqueId)) { const existingAccessory = this.accessoriesFromDiskMap.get(uniqueId); - console.log(existingAccessory.context.displayName) - console.log(existingAccessory.context.displayName.toLocaleLowerCase().includes('zack')); + // console.log(existingAccessory.context.displayName) + // console.log(existingAccessory.context.displayName.toLocaleLowerCase().includes('zack')); - if (!existingAccessory.context.displayName.includes('Zacks')) { - // console.log("NOT ZACK") - continue; - } + // if (!existingAccessory.context.displayName.includes('Zacks')) { + // continue; + // } this.accessoriesFromDiskMap.delete(uniqueId); this.logs.info(`[${existingAccessory.context.displayName}] - Found existing accessory. Updating...`); currAccessory = this.processOnlineAccessory(controller, existingAccessory); @@ -115,7 +115,7 @@ export class AccessoryGenerator { this.registerNewAccessories(newAccessoriesList); //register new accessories from scan this.updateExistingAccessories(existingAccessoriesList); - + return this.activeAccessoriesList; } // repairActiveAcessories(protoDevices: IProtoDevice[]) { @@ -136,8 +136,6 @@ export class AccessoryGenerator { const cachedDeviceInformation = controller.getCachedDeviceInformation(); const { protoDevice: { uniqueId }, protoDevice, deviceAPI: { description }, deviceMetaData } = cachedDeviceInformation; - // console.log(description); - // console.log(uniqueId) if (!this.isAllowed(uniqueId)) { return; } @@ -147,8 +145,8 @@ export class AccessoryGenerator { // console.log(newAccessory) newAccessory.context = { displayName: description as string, deviceMetaData, protoDevice, latestUpdate: Date.now() }; // new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); - new HomebridgeMagichomeDynamicPlatformAccessory(this.api, newAccessory, this.config, controller, this.hbLogger, this.logs) - + const hBAccessory = new HomebridgeMagichomeDynamicPlatformAccessory(this.api, newAccessory, this.config, controller, this.hbLogger, this.logs) + this.activeAccessoriesList.push(hBAccessory); return newAccessory; } @@ -164,7 +162,9 @@ export class AccessoryGenerator { overwriteDeep(existingAccessory.context, { protoDevice, deviceMetaData, latestUpdate: Date.now() }); try { - new HomebridgeMagichomeDynamicPlatformAccessory(this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs) + const hBAccessory = new HomebridgeMagichomeDynamicPlatformAccessory(this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); + this.activeAccessoriesList.push(hBAccessory); + // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); } catch (error) { // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); diff --git a/src/AnimationGenerator.ts b/src/AnimationGenerator.ts new file mode 100644 index 0000000..ab05440 --- /dev/null +++ b/src/AnimationGenerator.ts @@ -0,0 +1,163 @@ +import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop } from 'magichome-platform'; +import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; +import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; +import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; + +// import { homekitInterface } from './misc/types'; +import { Logs } from './logs'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +import { HomebridgeAnimationAccessory } from './animationAccessory'; + +const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; +const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; +const animationLoops = [colorWave, thunderStruck] +export class AnimationGenerator { + + public readonly animationsFromDiskMap: Map = new Map(); + public readonly activeAnimationAcessoriesMap: Map = new Map(); + public readonly cachedAccessoriesMap: Map = new Map(); + private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]; + private hap: HAP; + private api: API; + private hbLogger; + private config: PlatformConfig; + private logs: Logs; + constructor( + api: API, + logs: Logs, + hbLogger, + config, + animationsFromDiskMap, + activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]) { + this.api = api; + this.hap = api.hap; + this.hbLogger = hbLogger; + this.logs = logs; + this.config = config; + this.animationsFromDiskMap = animationsFromDiskMap; + this.activeAccessories = activeAccessories; + } + + + + async generateActiveAccessories() { + + const newAccessoriesList: AnimationAccessory[] = []; + const existingAccessoriesList: AnimationAccessory[] = []; + + this.animationsFromDiskMap.forEach((animation) => { + this.unregisterAccessory(animation) + }) + for (const animationLoop of animationLoops) { + let currAccessory: AnimationAccessory; + const max = 99999999; + const min = 11111111 + const randomInt = Math.floor(Math.random() * (max - min + 1) + min); + animationLoop.name = randomInt.toString(); + + const uniqueId = animationLoop.name; + + // try { + // if (this.animationsFromDiskMap.has(uniqueId)) { + // const existingAccessory = this.animationsFromDiskMap.get(uniqueId); + + // this.animationsFromDiskMap.delete(uniqueId); + // this.logs.info(`[${existingAccessory.context.animationLoop.name}] - Found existing accessory. Updating...`); + // currAccessory = this.processOnlineAccessory(existingAccessory, animationLoop); + // existingAccessoriesList.push(currAccessory); + + // } else if (!this.activeAnimationAcessoriesMap.has(uniqueId)) { //if the accessory is not a duplicate active device + currAccessory = this.createNewAnimation(animationLoop); + this.logs.info(`[${currAccessory.context.animationLoop.name}] - Found new accessory. Registering...`); + newAccessoriesList.push(currAccessory); //add it to new accessory list + // } + + this.activeAnimationAcessoriesMap.set(uniqueId, currAccessory); + // } catch (error) { + // this.logs.error(error); + // } + } + + this.registerNewAccessories(newAccessoriesList); //register new accessories from scan + this.updateExistingAccessories(existingAccessoriesList); + + } + + createNewAnimation(animationLoop: IAnimationLoop): AnimationAccessory { + const { name, pattern, accessoryOffsetMS } = animationLoop; + const homebridgeUUID = this.hap.uuid.generate(name); + const newAccessory: AnimationAccessory = new this.api.platformAccessory(name, homebridgeUUID) as AnimationAccessory; + newAccessory.context.animationLoop = animationLoop; + new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); + + return newAccessory; + + } + + processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationLoop) { + + + const { name, pattern, accessoryOffsetMS } = animationLoop; + + + try { + new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationLoop); + // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); + } catch (error) { + // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); + } + return existingAccessory; + } + + // registerOfflineAccessories() { + // const offlineAccessoriesList: MagicHomeAccessory[] = []; + // const completeDevicesInfo: ICompleteDeviceInfo[] = []; + // this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { + // const { displayName, deviceMetaData, protoDevice, latestUpdate } = offlineAccessory.context; + // const completeDeviceInfo: ICompleteDeviceInfo = { protoDevice, deviceMetaData, latestUpdate }; + // completeDevicesInfo.push(completeDeviceInfo); + // }); + + // const controllers = this.controllerGenerator.generateCustomControllers(completeDevicesInfo); + + // for (const controller of controllers) { + // try { + // const { protoDevice: { uniqueId } } = controller.getCachedDeviceInformation(); + // if (this.accessoriesFromDiskMap.has(uniqueId)) { + // const offlineAccessory = this.accessoriesFromDiskMap.get(uniqueId); + // this.accessoriesFromDiskMap.delete(uniqueId); + // this.processOfflineAccessory(offlineAccessory, controller); + // offlineAccessoriesList.push(offlineAccessory); + // this.cachedAccessoriesMap.set(uniqueId, offlineAccessory); + // } + // } catch (error) { + // this.logs.error(error); + // } + // } + + // this.updateExistingAccessories(offlineAccessoriesList); + // } + + + + + registerNewAccessories(newAccessories: AnimationAccessory[]) { + // link the accessory to your platform + this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); + + } + + updateExistingAccessories(existingAccessories: AnimationAccessory[]) { + this.api.updatePlatformAccessories(existingAccessories); + } + + unregisterAccessory(existingAnimationAccessory) { + + // this.activeAnimationAcessoriesMap.delete(uuid); + this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAnimationAccessory]); + // this.logs.warn(reason); + } + + // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; + +} \ No newline at end of file diff --git a/src/animationAccessory.ts b/src/animationAccessory.ts new file mode 100644 index 0000000..c747b7a --- /dev/null +++ b/src/animationAccessory.ts @@ -0,0 +1,642 @@ +import type { + API, Service, PlatformConfig, CharacteristicValue, + CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, +} from 'homebridge'; + + +import { cctToWhiteTemperature, clamp, HSVtoRGB, RGBtoHSV, whiteTemperatureToCCT } from './misc/utils'; +import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; +// import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE, AnimationController, colorWave } from 'magichome-platform'; +import { Logs } from './logs'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; + +const CCT = 'CCT'; +const HSV = 'HSV'; +const DEFAULT_ACCESSORY_STATE: IAccessoryState = { isOn: false, HSV: { hue: 0, saturation: 0, value: 0 }, brightness: 0 }; +/** + * 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 HomebridgeAnimationAccessory { + + protected service: Service; + protected activeControllerList: BaseController[]; + protected newAccessoryCommand: IAccessoryCommand; + protected latestAccessoryCommand: IAccessoryCommand; + + protected accessoryState: IAccessoryState; + + protected colorCommandMode = HSV; + + protected colorWhiteSimultaniousSaturationLevel; + protected colorOffSaturationLevel; + protected simultaniousDevicesColorWhite; + + protected deviceWriteStatus = 'ready'; + protected deviceReadStatus = 'ready'; + protected readRequestLevel = 0; + + protected queue; + protected slowQueueRetry = false; + protected animationController: AnimationController; + //================================================= + // Start Constructor // + + constructor( + protected hap: HAP, + protected logs, + protected api, + protected accessory, + protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], + protected animationLoop + ) { + + this.setupMisc(); + this.accessoryState = DEFAULT_ACCESSORY_STATE; + // this.logs = logs; + // this.controller = controller; + this.hap = api.hap; + this.api = api; + // this.config = config; + this.initializeCharacteristics(); + this.fetchAndUpdateState(2); + this.animationController = new AnimationController([]); + } + + //================================================= + // End Constructor // + + //================================================= + // Start Setters // + async setOn(value: CharacteristicValue) { + + if(value) { + const accessoryList = this.accessoriesList.filter(accessory => { + return accessory.accessoryState.isOn; + }); + + const controllerList = [] + for(const accessory of accessoryList) { + controllerList.push(accessory.getController()); + } + + await this.animationController.animateAsynchronously(controllerList, this.animationLoop).catch(e => console.log(e)) + } else { + this.animationController.clearAnimations(); + } + + const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; + this.processAccessoryCommand(accessoryCommand); + } + + setHue(value: CharacteristicValue) { + + this.accessoryState.HSV.hue = value as number; + this.colorCommandMode = HSV; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; + this.processAccessoryCommand(accessoryCommand); + } + + setSaturation(value: CharacteristicValue) { + + this.accessoryState.HSV.saturation = value as number; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; + this.processAccessoryCommand(accessoryCommand); + } + + async setBrightness(value: CharacteristicValue) { + + this.accessoryState.HSV.value = value as number; + this.accessoryState.brightness = value as number; + const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; + this.processAccessoryCommand(accessoryCommand); + } + + // setColorTemperature(value: CharacteristicValue) { + + // this.ColorCommandMode = CCT; + // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; + // this.processAccessoryCommand(accessoryCommand); + // } + + setConfiguredName(value: CharacteristicValue) { + + const name: string = value.toString(); + this.logs.warn('Renaming device to %o', name); + this.accessory.context.displayName = name; + console.log(this.accessory.context.displayName) + this.api.updatePlatformAccessories([this.accessory]); + } + + identifyLight() { + + this.flashEffect(); + } + + //================================================= + // End Setters // + + //================================================= + // Start Getters // + + getHue() { + const { isOn, HSV: { hue, saturation } } = this.accessoryState; + + // this.fetchAndUpdateState(2); + return hue; + + } + + getBrightness() { + const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + + // this.fetchAndUpdateState(2); + return brightness; + } + + /** + ** @getOn + * instantly retrieve the current on/off state stored in our object + * next call this.getState() which will update all values asynchronously as they are ready + */ + async getOn() { + const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + + this.fetchAndUpdateState(2); + return isOn; + } + + flashEffect() { + // + } //flashEffect + + //================================================= + // End LightEffects // + + + protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { + + const ret = await this.prepareCommand(accessoryCommand).catch(e => { console.log(e) }); + console.log('return value: ', ret) + } + + protected async prepareCommand(accessoryCommand: IAccessoryCommand) { + + this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); + const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState); + // console.log(accessoryCommand) + // console.log(sanitizedAcessoryCommand) + if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { + sanitizedAcessoryCommand.isPowerCommand = true; + } + // const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }); + // return completeResponse; + + } + + protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions) { + // const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); + + // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); + + // let response; + // // if (!accessoryCommand.isPowerCommand) response = await this.controller.setAllValues(deviceCommand, commandOptions); + // // else response = await this.controller.setOn(deviceCommand.isOn); + + // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); + // return response; + } + + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + const { isOn, HSV, colorTemperature, brightness } = accessoryCommand; + + const RGB = HSVtoRGB(HSV); + + const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; + return deviceCommand; + } + + protected async updateLocalState(requestLevel, deviceState) { + + if (!deviceState) { + // deviceState = await this.controller.fetchState(); + console.log(deviceState) + } + this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); + // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; + const { HSV: { hue, saturation, value }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); + let accessoryState: IAccessoryState; + if (deviceState) { + switch (requestLevel) { + case 0: + // accessoryState = { HSV: { value }, isOn }; + break; + case 1: + // accessoryState = { HSV: { hue, value }, isOn }; + break; + case 2: + accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; + break; + case 3: + accessoryState = { HSV: { hue, saturation, value }, isOn, brightness, colorTemperature }; + break; + } + + this.accessoryState = accessoryState; + // console.log(accessoryState) + + + + this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); + } + + + } + + updateHomekitState() { + const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, brightness); + } + + deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + + const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; + //TODO - REPLACE HSV WITH HSV + // eslint-disable-next-line prefer-const + let { hue, saturation, value } = RGBtoHSV(RGB); + let brightness = 0; + + if (value > 0) { + brightness = value; + } + // else if (isOn) { + // brightness = clamp(Math.max(coldWhite, warmWhite) / 2.55, 0, 100); + // if (warmWhite > coldWhite) { + // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); + // } else { + // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); + // } + // } + + const accessoryState: IAccessoryState = { HSV: { hue, saturation, value }, isOn, colorTemperature: 140, brightness }; + return accessoryState; + } + + initializeCharacteristics() { + + const cachedDeviceInformation = this.accessoryState; + // if (cachedDeviceInformation) { + // this.accessory.context.accessoryState = accessoryState; + // } else { + // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; + // } + // const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; + + this.addAccessoryInformationCharacteristic(); + + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); + this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); + + + this.addHueCharacteristic(); + this.addSaturationCharacteristic(); + this.addBrightnessCharacteristic(); + this.addOnCharacteristic(); + this.addConfiguredNameCharacteristic(); + } + + setupMisc() { + + // const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName?? "unknown"); + // const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = Object.assign({}, this.config.globalAccessoryOptions, localAccessoryOptions); + + + // this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; + // this.colorOffSaturationLevel = colorOffSaturationLevel; + // this.logs = new Logs(this.hbLogger, logLevel ?? 3); + + } + + async fetchAndUpdateState(requestLevel) { + try { + this.readRequestLevel = requestLevel; + await this.updateLocalState(this.readRequestLevel, null); + this.updateHomekitState(); + } catch (error) { + // this.hbLogger.error(error); + } + } + + + + addOnCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.On) + .onSet(this.setOn.bind(this)) + .onGet(this.getOn.bind(this)); + } + + addHueCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.Hue) + .onSet(this.setHue.bind(this)) + .onGet(this.getHue.bind(this)); + } + + addSaturationCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.Saturation) + .onSet(this.setSaturation.bind(this)); + // .onGet(this.CHANGE_ME.bind(this)); + + } + + removeSaturationCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.Saturation) + .removeAllListeners(this.hap.CharacteristicEventTypes.SET) + .removeAllListeners(this.hap.CharacteristicEventTypes.GET); + + } + + addBrightnessCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.Brightness) + .onSet(this.setBrightness.bind(this)) + .onGet(this.getBrightness.bind(this)); + } + + // addColorTemperatureCharacteristic() { + // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); + // this.service.getCharacteristic(this.hap.Characteristic.ColorTemperature) + // .onSet(this.setColorTemperature.bind(this)) + // .onGet(this.getColorTemperature.bind(this)); + + // if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { + // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); + // this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service); + // this.accessory.configureController(this.adaptiveLightingService); + // } + // } + + addAccessoryInformationCharacteristic() { + + // const { + // protoDevice: { uniqueId, modelNumber }, + // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, + // } = this.accessory.context.cachedDeviceInformation; + // set accessory information + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic ') + // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) + // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) + // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') + // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') + .getCharacteristic(this.hap.Characteristic.Identify) + .removeAllListeners(this.hap.CharacteristicEventTypes.SET) + .removeAllListeners(this.hap.CharacteristicEventTypes.GET) + .on(this.hap.CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below + + + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); + } + + addConfiguredNameCharacteristic() { + if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { + this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } else { + this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + + } + + + /* + // Add the garage door service if it doesn't already exist + this.service = + this.accessory.getService(this.hapServ.GarageDoorOpener) || + this.accessory.addService(this.hapServ.GarageDoorOpener) + + // Add some extra Eve characteristics + if (!this.service.testCharacteristic(this.eveChar.LastActivation)) { + this.service.addCharacteristic(this.eveChar.LastActivation) + } + if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) { + this.service.addCharacteristic(this.eveChar.ResetTotal) + } + if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) { + this.service.addCharacteristic(this.eveChar.TimesOpened) + } + + // Add the set handler to the garage door target state characteristic + this.service + .getCharacteristic(this.hapChar.TargetDoorState) + .onSet(value => this.internalTargetUpdate(value)) + this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value + this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value + + // Add the set handler to the garage door reset total characteristic + this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { + this.service.updateCharacteristic(this.eveChar.TimesOpened, 0) + }) + + // Update the obstruction detected to false on plugin load + this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false) + + // Pass the accessory to Fakegato to set up with Eve + this.accessory.eveService = new platform.eveService('door', this.accessory, { + log: platform.config.debugFakegato ? this.log : () => {} + }) + */ + + + +} // ZackneticMagichomePlatformAccessory class +// import type { API, CharacteristicEventTypes, CharacteristicValue, HAP, Service } from "homebridge"; +// import { AnimationController, BaseController } from "magichome-platform"; +// import { Logs } from "./logs"; +// import { AnimationAccessory, DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState } from "./misc/types"; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from "./platformAccessory"; + +// export class HomebridgeAnimationAccessory { + +// protected service: Service; +// protected accessoryState: IAccessoryState = DefaultAccessoryCommand; +// protected accessory: AnimationAccessory; +// protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[]; +// protected activeControllerList: BaseController[]; +// hap: HAP; +// logs: Logs; +// api: API; +// constructor( +// hap: HAP, +// logs: Logs, +// api: API, +// accessory: AnimationAccessory, +// // accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[] + +// ) { +// this.accessory = accessory; +// const animationController: AnimationController = new AnimationController([]); +// // this.accessoriesList = accessoriesList; +// this.hap = hap; +// this.logs = logs; +// this.api = api; +// } + +// // Start Setters // +// async setOn(value: CharacteristicValue) { +// const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; +// // this.processAccessoryCommand(accessoryCommand); +// } + +// setHue(value: CharacteristicValue) { + +// this.accessoryState.HSV.hue = value as number; +// const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; +// // this.processAccessoryCommand(accessoryCommand); +// } + +// setSaturation(value: CharacteristicValue) { + +// this.accessoryState.HSV.saturation = value as number; +// const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; +// // this.processAccessoryCommand(accessoryCommand); +// } + +// async setBrightness(value: CharacteristicValue) { + +// this.accessoryState.HSV.value = value as number; +// this.accessoryState.brightness = value as number; +// const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; +// // this.processAccessoryCommand(accessoryCommand); +// } + +// setConfiguredName(value: CharacteristicValue) { + +// const name: string = value.toString(); +// this.logs.warn('Renaming device to %o', name); +// this.accessory.context.animationLoop.name = name; +// this.api.updatePlatformAccessories([this.accessory]); +// } + + +// getHue() { +// const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + +// // this.fetchAndUpdateState(2); +// return hue; + +// } + +// getBrightness() { +// const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + +// // this.fetchAndUpdateState(2); +// return brightness; +// } + +// /** +// ** @getOn +// * instantly retrieve the current on/off state stored in our object +// * next call this.getState() which will update all values asynchronously as they are ready +// */ +// async getOn() { +// const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + +// // this.fetchAndUpdateState(2); +// return isOn; +// } + +// addOnCharacteristic() { +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); +// this.service.getCharacteristic(this.hap.Characteristic.On) +// .onSet(this.setOn.bind(this)) +// .onGet(this.getOn.bind(this)); +// } + +// addHueCharacteristic() { +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); +// this.service.getCharacteristic(this.hap.Characteristic.Hue) +// .onSet(this.setHue.bind(this)) +// .onGet(this.getHue.bind(this)); +// } + +// addSaturationCharacteristic() { +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); +// this.service.getCharacteristic(this.hap.Characteristic.Saturation) +// .onSet(this.setSaturation.bind(this)); +// // .onGet(this.CHANGE_ME.bind(this)); + +// } + +// addBrightnessCharacteristic() { +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); +// this.service.getCharacteristic(this.hap.Characteristic.Brightness) +// .onSet(this.setBrightness.bind(this)) +// .onGet(this.getBrightness.bind(this)); +// } + +// addAccessoryInformationCharacteristic() { + +// // const { +// // protoDevice: { uniqueId, modelNumber }, +// // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, +// // } = this.accessory.context.cachedDeviceInformation; +// // set accessory information +// this.accessory.getService(this.hap.Service.AccessoryInformation)! +// // .removeAllListeners(CharacteristicEventTypes.SET) +// // .removeAllListeners(CharacteristicEventTypes.GET) +// .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') +// // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) +// // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) +// // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') +// // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') + + +// this.accessory.getService(this.hap.Service.AccessoryInformation)! +// .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); +// } + +// addConfiguredNameCharacteristic() { +// if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { +// this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) +// .onSet(this.setConfiguredName.bind(this)); +// } else { +// this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) +// .onSet(this.setConfiguredName.bind(this)); +// } +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + +// } + +// initializeCharacteristics() { + +// // const cachedDeviceInformation = this.controller.getCachedDeviceInformation(); +// // if (cachedDeviceInformation) { +// // this.accessory.context.accessoryState = accessoryState; +// // } else { +// // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; +// // } +// // const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; + +// this.addAccessoryInformationCharacteristic(); + +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); +// this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); +// this.addHueCharacteristic(); +// this.addSaturationCharacteristic(); +// this.addBrightnessCharacteristic(); +// this.addOnCharacteristic(); +// this.addConfiguredNameCharacteristic(); +// } +// } diff --git a/src/misc/types.ts b/src/misc/types.ts index c3fb4cc..18526c3 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -1,5 +1,5 @@ import type { PlatformAccessory } from 'homebridge'; -import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation, IDeviceMetaData, IProtoDevice } from 'magichome-platform'; +import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation, IDeviceMetaData, IProtoDevice, IAnimationLoop } from 'magichome-platform'; // import { Switch } from '../accessories/Switch'; // import { DimmerStrip } from '../accessories/DimmerStrip'; @@ -25,7 +25,15 @@ import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInforma // }; export interface MagicHomeAccessory extends PlatformAccessory { - context: IAccessoryContext + context: IAccessoryContext; +} + +export interface AnimationAccessory extends PlatformAccessory { + context: IAnimationContext; +} + +export interface IAnimationContext { + animationLoop: IAnimationLoop; } export interface IAccessoryContext { diff --git a/src/misc/utils.ts b/src/misc/utils.ts index 1d1ab23..4882fea 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -200,7 +200,7 @@ export function HSVtoRGB(HSV: IColorHSV): IColorRGB { S /= 100.0 V /= 100.0 const C = V * S; - const X = C * (1 - Math.abs(((H / 60) % 2) - 1)) + const X = C * (1 - Math.abs(((H / 60) % 2) - 1)); const m = V - C; let order; @@ -212,13 +212,14 @@ export function HSVtoRGB(HSV: IColorHSV): IColorRGB { else if (H < 360) order = [C, 0, X]; const [dR, dG, dB] = order; - const [red, green, blue] = [(dR + m) * 255, (dG + m) * 255, (dB + m) * 255] + const [red, green, blue] = [Math.round((dR + m) * 255), Math.round((dG + m) * 255), Math.round((dB + m) * 255)] + // console.log(`--SENDING-- RED: ${red} GREEN: ${green} BLUE: ${blue}`) return { red, green, blue }; } export function RGBtoHSV(RGB: IColorRGB): IColorHSV { - + const { red, green, blue }: IColorRGB = RGB; // console.log(`--RECEIVING-- RED: ${red} GREEN: ${green} BLUE: ${blue}`) @@ -241,6 +242,7 @@ export function RGBtoHSV(RGB: IColorRGB): IColorHSV { if (V === 0) S = 0; else S = D / V; + S *= 100; V *= 100; // console.log("-- RECEIVED -- H: ", H, "S: ", S, "V: ", V) diff --git a/src/platform.ts b/src/platform.ts index 43bc386..30bfed6 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -11,14 +11,14 @@ import { } from 'homebridge'; import { ControllerGenerator } from 'magichome-platform'; - -import { MagicHomeAccessory } from './misc/types'; +import { AnimationGenerator } from './AnimationGenerator' +import { AnimationAccessory, MagicHomeAccessory } from './misc/types'; import { AccessoryGenerator } from './AccessoryGenerator'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; /** */ const controllerGenerator = new ControllerGenerator(); -let hap: HAP; /** * HomebridgePlatform @@ -33,21 +33,23 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin public count = 1; private periodicDiscovery: NodeJS.Timeout | null = null; + protected hap: HAP; public readonly config: PlatformConfig; public readonly accessoriesFromDiskMap: Map = new Map(); private readonly hbLogger: Logging; private readonly log: Logs; + animationsFromDiskMap:Map = new Map(); constructor( logging: Logging, config: PlatformConfig, api: API, ) { this.hbLogger = logging; - hap = api.hap; + this.api = api; + this.hap = api.hap; this.config = config; this.log = new Logs(logging, config?.globalAccessoryOptions?.logLevel ?? 3); - this.api = api; //this.logs = getLogger(); this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); this.log.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); @@ -68,16 +70,23 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin * This function is invoked when homebridge restores cached accessories from disk at startup. * It should be used to setup event handlers for characteristics and update respective values. */ - configureAccessory(accessory: MagicHomeAccessory) { + configureAccessory(accessory) { + // set cached accessory as not recently seen // if found later to be a match with a discovered device, will change to true // accessory.context.scansSinceSeen++; // accessory.context.pendingRegistration = true; // // add the restored accessory to the accessories cache so we can track if it has already been registered + if (typeof accessory.context.protoDevice != 'undefined') { + const homebridgeUUID = accessory.context.protoDevice?.uniqueId; + this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); + this.log.info(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); + } else { + const homebridgeUUID = accessory.context.animationLoop.name; + + this.animationsFromDiskMap.set(homebridgeUUID, accessory); + } - const homebridgeUUID = accessory.context.protoDevice.uniqueId; - this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); - this.log.info(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); } @@ -96,7 +105,9 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); - await accesssoryGenerator.discoverDevices(); + const activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] = await accesssoryGenerator.discoverDevices(); + const animationGenerator = new AnimationGenerator(this.api, this.log, this.hbLogger, this.config, this.animationsFromDiskMap, activeAccessories); + animationGenerator.generateActiveAccessories(); // this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); } diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index ce6c6d9..1ae400a 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -2,9 +2,9 @@ import type { API, Service, PlatformConfig, CharacteristicValue, CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, } from 'homebridge'; -import { CharacteristicEventTypes } from 'homebridge'; -import { clamp, HSVtoRGB, RGBtoHSV } from './misc/utils'; + +import { cctToWhiteTemperature, clamp, HSVtoRGB, RGBtoHSV, whiteTemperatureToCCT } from './misc/utils'; import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE } from 'magichome-platform'; @@ -27,9 +27,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected newAccessoryCommand: IAccessoryCommand; protected latestAccessoryCommand: IAccessoryCommand; - protected accessoryState: IAccessoryState; + public accessoryState: IAccessoryState; - protected ColorCommandMode = HSV; + protected colorCommandMode = HSV; protected colorWhiteSimultaniousSaturationLevel; protected colorOffSaturationLevel; @@ -78,7 +78,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setHue(value: CharacteristicValue) { this.accessoryState.HSV.hue = value as number; - this.ColorCommandMode = HSV; + this.colorCommandMode = HSV; const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; this.processAccessoryCommand(accessoryCommand); } @@ -86,7 +86,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setSaturation(value: CharacteristicValue) { this.accessoryState.HSV.saturation = value as number; - this.ColorCommandMode = HSV; const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; this.processAccessoryCommand(accessoryCommand); } @@ -170,46 +169,35 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { - await this.prepareCommand(accessoryCommand); + const ret = await this.prepareCommand(accessoryCommand).catch(e => { console.log(e) }); + console.log('return value: ', ret) } protected async prepareCommand(accessoryCommand: IAccessoryCommand): Promise { - try { - this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState); - // console.log(accessoryCommand) - // console.log(sanitizedAcessoryCommand) - if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { - sanitizedAcessoryCommand.isPowerCommand = true; - } - const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: true, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, remainingRetries: 5 }); - return completeResponse; - } catch (error) { - this.hbLogger.error(error); + this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); + const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState); + // console.log(accessoryCommand) + // console.log(sanitizedAcessoryCommand) + if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { + sanitizedAcessoryCommand.isPowerCommand = true; } + const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }); + return completeResponse; + } protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions): Promise { - try { + const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); + + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); + let response; + if (!accessoryCommand.isPowerCommand) response = await this.controller.setAllValues(deviceCommand, commandOptions); + else response = await this.controller.setOn(deviceCommand.isOn); - const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); - - let response; - if (!accessoryCommand.isPowerCommand) { - // console.log(commandOptions) - response = await this.controller.setAllValues(deviceCommand, commandOptions); - } else { - response = await this.controller.setOn(deviceCommand.isOn); - } - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); - return response; - } catch (error) { - this.hbLogger.error(error); - - } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); + return response; } protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { @@ -222,38 +210,40 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } protected async updateLocalState(requestLevel, deviceState) { - try { - if (!deviceState) { - deviceState = await this.controller?.fetchState(); - } - this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); - // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; - const { HSV: { hue, saturation, value }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); - let accessoryState: IAccessoryState; - if (deviceState) { - switch (requestLevel) { - case 0: - // accessoryState = { HSV: { value }, isOn }; - break; - case 1: - // accessoryState = { HSV: { hue, value }, isOn }; - break; - case 2: - accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; - break; - case 3: - accessoryState = { HSV: { hue, saturation, value }, isOn, brightness, colorTemperature }; - break; - } - - this.accessoryState = accessoryState; - console.log(accessoryState) - this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); + + if (!deviceState) { + deviceState = await this.controller.fetchState(); + console.log(deviceState) + } + this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); + // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; + const { HSV: { hue, saturation, value }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); + let accessoryState: IAccessoryState; + if (deviceState) { + switch (requestLevel) { + case 0: + // accessoryState = { HSV: { value }, isOn }; + break; + case 1: + // accessoryState = { HSV: { hue, value }, isOn }; + break; + case 2: + accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; + break; + case 3: + accessoryState = { HSV: { hue, saturation, value }, isOn, brightness, colorTemperature }; + break; } - } catch (error) { + this.accessoryState = accessoryState; + // console.log(accessoryState) + + + this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); } + + } updateHomekitState() { @@ -313,7 +303,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } if (hasCCT) { - // addColorTemperatureCharacteristic(); + // this.addColorTemperatureCharacteristic(); } if (!hasBrightness) { @@ -372,6 +362,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } + removeSaturationCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.Saturation) + .removeAllListeners(this.hap.CharacteristicEventTypes.SET) + .removeAllListeners(this.hap.CharacteristicEventTypes.GET); + + } + addBrightnessCharacteristic() { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); this.service.getCharacteristic(this.hap.Characteristic.Brightness) @@ -406,9 +404,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') .getCharacteristic(this.hap.Characteristic.Identify) - .removeAllListeners(CharacteristicEventTypes.SET) - .removeAllListeners(CharacteristicEventTypes.GET) - .on(CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below + .removeAllListeners(this.hap.CharacteristicEventTypes.SET) + .removeAllListeners(this.hap.CharacteristicEventTypes.GET) + .on(this.hap.CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below this.accessory.getService(this.hap.Service.AccessoryInformation)! diff --git a/src/specs/controllerCreation.spec.ts b/src/specs/controllerCreation.spec.ts new file mode 100644 index 0000000..d375d5d --- /dev/null +++ b/src/specs/controllerCreation.spec.ts @@ -0,0 +1,15 @@ + +describe('Test the device creation', function () { + + + + + it('Should retrieve meta-data on each device', async function () { + + }) + + it('Should create a controller for each device', function () { + + }) + +}) \ No newline at end of file From b45d99928aca4c70490df1db021c03dbbbaf0b4c Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Thu, 25 Aug 2022 00:31:34 -0400 Subject: [PATCH 33/42] updated animation accessory --- src/AnimationGenerator.ts | 4 +-- src/animationAccessory.ts | 27 +++++++------- src/platformAccessory.ts | 75 ++++++++++++++++++--------------------- 3 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/AnimationGenerator.ts b/src/AnimationGenerator.ts index ab05440..1bb21fd 100644 --- a/src/AnimationGenerator.ts +++ b/src/AnimationGenerator.ts @@ -1,4 +1,4 @@ -import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop } from 'magichome-platform'; +import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave } from 'magichome-platform'; import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; @@ -10,7 +10,7 @@ import { HomebridgeAnimationAccessory } from './animationAccessory'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; -const animationLoops = [colorWave, thunderStruck] +const animationLoops = [colorWave, thunderStruck, cctWave] export class AnimationGenerator { public readonly animationsFromDiskMap: Map = new Map(); diff --git a/src/animationAccessory.ts b/src/animationAccessory.ts index c747b7a..c193c61 100644 --- a/src/animationAccessory.ts +++ b/src/animationAccessory.ts @@ -52,7 +52,7 @@ export class HomebridgeAnimationAccessory { protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], protected animationLoop ) { - + this.setupMisc(); this.accessoryState = DEFAULT_ACCESSORY_STATE; // this.logs = logs; @@ -71,18 +71,20 @@ export class HomebridgeAnimationAccessory { //================================================= // Start Setters // async setOn(value: CharacteristicValue) { + if (this.animationController.isActive) this.animationController.clearAnimations(); - if(value) { + if (value) { const accessoryList = this.accessoriesList.filter(accessory => { - return accessory.accessoryState.isOn; + // return accessory.accessoryState.isOn; + return true; }); - + const controllerList = [] - for(const accessory of accessoryList) { + for (const accessory of accessoryList) { controllerList.push(accessory.getController()); } - - await this.animationController.animateAsynchronously(controllerList, this.animationLoop).catch(e => console.log(e)) + + await this.animationController.animateAsynchronously(controllerList, this.animationLoop).catch(e => { }) } else { this.animationController.clearAnimations(); } @@ -178,14 +180,14 @@ export class HomebridgeAnimationAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { - const ret = await this.prepareCommand(accessoryCommand).catch(e => { console.log(e) }); - console.log('return value: ', ret) + const ret = await this.prepareCommand(accessoryCommand).catch(e => { { } }); + // console.log('return value: ', ret) } protected async prepareCommand(accessoryCommand: IAccessoryCommand) { this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState); + const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState, DEFAULT_ACCESSORY_STATE); // console.log(accessoryCommand) // console.log(sanitizedAcessoryCommand) if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { @@ -221,8 +223,7 @@ export class HomebridgeAnimationAccessory { protected async updateLocalState(requestLevel, deviceState) { if (!deviceState) { - // deviceState = await this.controller.fetchState(); - console.log(deviceState) + // deviceState = await this..fetchState(); } this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; @@ -325,7 +326,7 @@ export class HomebridgeAnimationAccessory { async fetchAndUpdateState(requestLevel) { try { this.readRequestLevel = requestLevel; - await this.updateLocalState(this.readRequestLevel, null); + await this.updateLocalState(this.readRequestLevel, null).catch(e => { }); this.updateHomekitState(); } catch (error) { // this.hbLogger.error(error); diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 1ae400a..6cfb68c 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -128,22 +128,22 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getHue() { const { isOn, HSV: { hue, saturation } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - // this.fetchAndUpdateState(2); + this.fetchAndUpdateState(2); return hue; } - getColorTemperature() { - const { isOn, HSV: { hue, saturation }, brightness, colorTemperature } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) + // getColorTemperature() { + // const { isOn, HSV: { hue, saturation }, brightness, colorTemperature } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) - this.fetchAndUpdateState(3); - return colorTemperature; - } + // this.fetchAndUpdateState(3); + // return colorTemperature; + // } getBrightness() { const { isOn, HSV: { hue, saturation, value }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - // this.fetchAndUpdateState(2); + this.fetchAndUpdateState(2); return brightness; } @@ -169,32 +169,31 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { - const ret = await this.prepareCommand(accessoryCommand).catch(e => { console.log(e) }); - console.log('return value: ', ret) + const ret = await this.prepareCommand(accessoryCommand).catch(e => { }); + // console.log('return value: ', ret) } - protected async prepareCommand(accessoryCommand: IAccessoryCommand): Promise { - + protected async prepareCommand(accessoryCommand: IAccessoryCommand): Promise { + // console.log(accessoryCommand) this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState); - // console.log(accessoryCommand) - // console.log(sanitizedAcessoryCommand) + if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; } - const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }); + const completeResponse: ICompleteResponse | void = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }).catch(e => { }); return completeResponse; } - + E protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions): Promise { const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); - + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); let response; - if (!accessoryCommand.isPowerCommand) response = await this.controller.setAllValues(deviceCommand, commandOptions); - else response = await this.controller.setOn(deviceCommand.isOn); + if (!accessoryCommand.isPowerCommand) response = await this.controller.setAllValues(deviceCommand, commandOptions).catch(e => { }); + else response = await this.controller.setOn(deviceCommand.isOn).catch(e => { }); this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); return response; @@ -204,17 +203,18 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { const { isOn, HSV, colorTemperature, brightness } = accessoryCommand; const RGB = HSVtoRGB(HSV); - - const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; + + const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: null, CCT: { warmWhite: 0, coldWhite: 0 } }; return deviceCommand; } protected async updateLocalState(requestLevel, deviceState) { - if (!deviceState) { - deviceState = await this.controller.fetchState(); - console.log(deviceState) - } + if (!deviceState) deviceState = await this.controller.fetchState().catch(e => { + console.log('updateLocalState Error: ', e) + return; + }); + this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; const { HSV: { hue, saturation, value }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); @@ -255,26 +255,18 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + if (!deviceState) throw 'device state not provided'; + let { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - //TODO - REPLACE HSV WITH HSV - // eslint-disable-next-line prefer-const let { hue, saturation, value } = RGBtoHSV(RGB); let brightness = 0; - if (value > 0) { - brightness = value; - } - // else if (isOn) { - // brightness = clamp(Math.max(coldWhite, warmWhite) / 2.55, 0, 100); - // if (warmWhite > coldWhite) { - // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); - // } else { - // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); - // } - // } + if (value > 0) brightness = value; + else brightness = clamp(Math.max(coldWhite, warmWhite) / 2.55, 0, 100); - const accessoryState: IAccessoryState = { HSV: { hue, saturation, value }, isOn, colorTemperature: 140, brightness }; + if (brightness <= 0) isOn = false; + + const accessoryState: IAccessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; return accessoryState; } @@ -329,7 +321,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { async fetchAndUpdateState(requestLevel) { try { this.readRequestLevel = requestLevel; - await this.updateLocalState(this.readRequestLevel, null); + await this.updateLocalState(this.readRequestLevel, null).catch(e => { console.log('fetchAndUpdateState ERROR', e) }); this.updateHomekitState(); } catch (error) { this.hbLogger.error(error); @@ -466,4 +458,5 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { -} // ZackneticMagichomePlatformAccessory class \ No newline at end of file +} // ZackneticMagichomePlatformAccessory class + From 00e881c454daacc69ae2a951b13e0c6f5028c4e4 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 27 Aug 2022 15:07:49 -0400 Subject: [PATCH 34/42] updated command and state to be device type agnostic --- src/platformAccessory.ts | 192 +++++++++++++++++++++++---------------- 1 file changed, 113 insertions(+), 79 deletions(-) diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 6cfb68c..be5b223 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -4,15 +4,15 @@ import type { } from 'homebridge'; -import { cctToWhiteTemperature, clamp, HSVtoRGB, RGBtoHSV, whiteTemperatureToCCT } from './misc/utils'; -import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; +import { temperatureToCCT, clamp, TBtoCCT, HSVtoRGB, RGBtoHSV, CCTtoTB } from './misc/utils'; +import { DEFAULT_ACCESSORY_COMMAND, DEFAULT_ACCESSORY_STATE, IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB, IConfigOptions, IPartialAccessoryCommand, MagicHomeAccessory } from './misc/types'; // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE } from 'magichome-platform'; +import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE, COLOR_MASKS } from 'magichome-platform'; import { Logs } from './logs'; -const CCT = 'CCT'; -const HSV = 'HSV'; -const DEFAULT_ACCESSORY_STATE: IAccessoryState = { isOn: false, HSV: { hue: 0, saturation: 0, value: 0 }, brightness: 0 }; +const WHITE_MODE = 'WHITE_MODE'; +const COLOR_MODE = 'COLOR_MODE'; + /** * Platform Accessory * An instance of this class is created for each accessory your platform registers @@ -29,7 +29,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { public accessoryState: IAccessoryState; - protected colorCommandMode = HSV; + protected colorCommandMode: string = COLOR_MODE; protected colorWhiteSimultaniousSaturationLevel; protected colorOffSaturationLevel; @@ -41,6 +41,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected queue; protected slowQueueRetry = false; + protected lastValue: number; + lastHue: number; + lastBrightness: number; //================================================= // Start Constructor // @@ -70,32 +73,42 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // Start Setters // - async setOn(value: CharacteristicValue) { - const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; - this.processAccessoryCommand(accessoryCommand); + setOn(value: CharacteristicValue) { + const partialAccessoryCommand: IPartialAccessoryCommand = { isOn: value as boolean, isPowerCommand: true }; + this.processAccessoryCommand(partialAccessoryCommand); } setHue(value: CharacteristicValue) { - - this.accessoryState.HSV.hue = value as number; - this.colorCommandMode = HSV; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; - this.processAccessoryCommand(accessoryCommand); + let partialAccessoryCommand: IPartialAccessoryCommand; + if (this.colorCommandMode == COLOR_MODE) { + this.accessoryState.HSV.hue = value as number; + partialAccessoryCommand = { HSV: { hue: value as number } }; + } else { + this.accessoryState.TB.temperature = value as number; + partialAccessoryCommand = { TB: { temperature: value as number } }; + } + this.processAccessoryCommand(partialAccessoryCommand); } setSaturation(value: CharacteristicValue) { this.accessoryState.HSV.saturation = value as number; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; - this.processAccessoryCommand(accessoryCommand); + const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { saturation: value as number } }; + this.processAccessoryCommand(partialAccessoryCommand); } - async setBrightness(value: CharacteristicValue) { + setBrightness(value: CharacteristicValue) { - this.accessoryState.HSV.value = value as number; - this.accessoryState.brightness = value as number; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; - this.processAccessoryCommand(accessoryCommand); + let partialAccessoryCommand: IPartialAccessoryCommand; + if (this.colorCommandMode == COLOR_MODE) { + this.accessoryState.HSV.value = value as number; + partialAccessoryCommand = { HSV: { value: value as number } }; + } else { + this.accessoryState.TB.brightness = value as number; + partialAccessoryCommand = { TB: { brightness: value as number } }; + } + + this.processAccessoryCommand(partialAccessoryCommand); } // setColorTemperature(value: CharacteristicValue) { @@ -126,10 +139,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // Start Getters // getHue() { - const { isOn, HSV: { hue, saturation } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + const { HSV: { hue }, TB: { temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + + let _hue; + if (this.colorCommandMode == COLOR_MODE) _hue = hue; + else _hue = temperature; this.fetchAndUpdateState(2); - return hue; + return _hue; } @@ -141,10 +158,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // } getBrightness() { - const { isOn, HSV: { hue, saturation, value }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + const { HSV: { value }, TB: { brightness } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + + let _brightness; + if (this.colorCommandMode = COLOR_MODE) _brightness = brightness; + else _brightness = value; this.fetchAndUpdateState(2); - return brightness; + return _brightness; } /** @@ -153,7 +174,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { * next call this.getState() which will update all values asynchronously as they are ready */ async getOn() { - const { isOn, HSV: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + const { isOn } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); this.fetchAndUpdateState(2); return isOn; @@ -166,28 +187,56 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // End LightEffects // + //TODO, Severe! Bundle commands so that close consecutive changes in hue, sat, and brightness aren't sent as separate commands + protected async processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { - protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { + const sanitizedAcessoryCommand = await this.completeAccessoryCommand(partialAccessoryCommand); + const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); - const ret = await this.prepareCommand(accessoryCommand).catch(e => { }); - // console.log('return value: ', ret) + const completeResponse: ICompleteResponse | void = await this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand).catch(e => { }); + return completeResponse; } - protected async prepareCommand(accessoryCommand: IAccessoryCommand): Promise { - // console.log(accessoryCommand) + protected completeAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand): IAccessoryCommand { this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState); - - if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { + const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, partialAccessoryCommand, this.accessoryState); + console.log(partialAccessoryCommand, this.accessoryState) + if (partialAccessoryCommand.hasOwnProperty('isOn') && !(partialAccessoryCommand.hasOwnProperty('HSV') || partialAccessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; } - const completeResponse: ICompleteResponse | void = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }).catch(e => { }); - return completeResponse; + return sanitizedAcessoryCommand; + } + + protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): { deviceCommand: IDeviceCommand, commandOptions: ICommandOptions } { + const { isOn, HSV: { hue, saturation, value }, TB } = accessoryCommand; + const commandOptions: ICommandOptions = { colorAssist: true, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; + console.log(this.colorCommandMode) + + let red, green, blue, warmWhite, coldWhite; + + if (saturation < 95) { + this.colorCommandMode = WHITE_MODE; + ({ warmWhite, coldWhite } = TBtoCCT(TB)); + + ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value })); + + if (saturation < 5) { + red = 0, green = 0, blue = 0; + } + + } else { + this.colorCommandMode = COLOR_MODE; + ({ red, green, blue } = HSVtoRGB({ hue, saturation, value })); + warmWhite = 0; + coldWhite = 0; + } + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, colorMask: null, CCT: { warmWhite, coldWhite } }; + + return { deviceCommand, commandOptions }; } - E - protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions): Promise { - const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); + + protected async sendCommand(deviceCommand: IDeviceCommand, commandOptions: ICommandOptions, accessoryCommand: IAccessoryCommand): Promise { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); @@ -199,14 +248,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { return response; } - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const { isOn, HSV, colorTemperature, brightness } = accessoryCommand; - const RGB = HSVtoRGB(HSV); - - const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: null, CCT: { warmWhite: 0, coldWhite: 0 } }; - return deviceCommand; - } protected async updateLocalState(requestLevel, deviceState) { @@ -217,7 +259,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; - const { HSV: { hue, saturation, value }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); + const { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); let accessoryState: IAccessoryState; if (deviceState) { switch (requestLevel) { @@ -228,10 +270,10 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // accessoryState = { HSV: { hue, value }, isOn }; break; case 2: - accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; + accessoryState = { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } }; break; case 3: - accessoryState = { HSV: { hue, saturation, value }, isOn, brightness, colorTemperature }; + accessoryState = { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } }; break; } @@ -247,26 +289,31 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } updateHomekitState() { - const { isOn, HSV: { hue, saturation }, brightness } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + + let _hue, _brightness + + if (this.colorCommandMode = COLOR_MODE) { + _hue = hue; + _brightness = value; + } else { + _hue = temperature; + _brightness = brightness; + } + this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, brightness); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, _hue); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, _brightness); } deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { if (!deviceState) throw 'device state not provided'; - let { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - - let { hue, saturation, value } = RGBtoHSV(RGB); - let brightness = 0; - - if (value > 0) brightness = value; - else brightness = clamp(Math.max(coldWhite, warmWhite) / 2.55, 0, 100); - - if (brightness <= 0) isOn = false; - - const accessoryState: IAccessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; + let { RGB, CCT, isOn } = deviceState; + const HSV: IColorHSV = RGBtoHSV(RGB); + const TB: IColorTB = CCTtoTB(CCT); + HSV.saturation = clamp(HSV.saturation - (TB.brightness / 4), 0, 100) + const accessoryState: IAccessoryState = { HSV, TB, isOn }; return accessoryState; } @@ -354,14 +401,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } - removeSaturationCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.Saturation) - .removeAllListeners(this.hap.CharacteristicEventTypes.SET) - .removeAllListeners(this.hap.CharacteristicEventTypes.GET); - - } - addBrightnessCharacteristic() { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); this.service.getCharacteristic(this.hap.Characteristic.Brightness) @@ -384,10 +423,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { addAccessoryInformationCharacteristic() { - // const { - // protoDevice: { uniqueId, modelNumber }, - // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, - // } = this.accessory.context.cachedDeviceInformation; + const { + protoDevice: { uniqueId, modelNumber }, deviceMetaData: { controllerFirmwareVersion, controllerHardwareVersion } } = this.controller.getCachedDeviceInformation(); // set accessory information this.accessory.getService(this.hap.Service.AccessoryInformation)! .setCharacteristic(this.hap.Characteristic.Manufacturer, 'MagicHome') @@ -417,7 +454,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } - /* // Add the garage door service if it doesn't already exist this.service = @@ -456,7 +492,5 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { }) */ - - } // ZackneticMagichomePlatformAccessory class From e4311360077d29bf19411824011541ba55a7eacd Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sat, 27 Aug 2022 15:08:28 -0400 Subject: [PATCH 35/42] updated device state and command --- .homebridge-dev/config.json | 2 +- src/AnimationGenerator.ts | 304 +++++----- src/animationAccessory.ts | 1051 +++++++++++++++++------------------ src/misc/types.ts | 59 +- src/misc/utils.ts | 78 +-- src/platform.ts | 6 +- 6 files changed, 769 insertions(+), 731 deletions(-) diff --git a/.homebridge-dev/config.json b/.homebridge-dev/config.json index 8f0b928..d14121f 100644 --- a/.homebridge-dev/config.json +++ b/.homebridge-dev/config.json @@ -1,7 +1,7 @@ { "bridge": { "name": "HomebridgeDev", - "username": "DD:BB:DD:DD:FF:GG", + "username": "DD:FB:FF:DD:FF:GG", "manufacturer": "homebridge.io", "model": "homebridge", "port": 51826, diff --git a/src/AnimationGenerator.ts b/src/AnimationGenerator.ts index 1bb21fd..2d70365 100644 --- a/src/AnimationGenerator.ts +++ b/src/AnimationGenerator.ts @@ -1,163 +1,163 @@ -import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave } from 'magichome-platform'; -import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; -import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; -import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; - -// import { homekitInterface } from './misc/types'; -import { Logs } from './logs'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -import { HomebridgeAnimationAccessory } from './animationAccessory'; - -const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; -const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; -const animationLoops = [colorWave, thunderStruck, cctWave] -export class AnimationGenerator { - - public readonly animationsFromDiskMap: Map = new Map(); - public readonly activeAnimationAcessoriesMap: Map = new Map(); - public readonly cachedAccessoriesMap: Map = new Map(); - private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]; - private hap: HAP; - private api: API; - private hbLogger; - private config: PlatformConfig; - private logs: Logs; - constructor( - api: API, - logs: Logs, - hbLogger, - config, - animationsFromDiskMap, - activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]) { - this.api = api; - this.hap = api.hap; - this.hbLogger = hbLogger; - this.logs = logs; - this.config = config; - this.animationsFromDiskMap = animationsFromDiskMap; - this.activeAccessories = activeAccessories; - } - - - - async generateActiveAccessories() { - - const newAccessoriesList: AnimationAccessory[] = []; - const existingAccessoriesList: AnimationAccessory[] = []; - - this.animationsFromDiskMap.forEach((animation) => { - this.unregisterAccessory(animation) - }) - for (const animationLoop of animationLoops) { - let currAccessory: AnimationAccessory; - const max = 99999999; - const min = 11111111 - const randomInt = Math.floor(Math.random() * (max - min + 1) + min); - animationLoop.name = randomInt.toString(); - - const uniqueId = animationLoop.name; - - // try { - // if (this.animationsFromDiskMap.has(uniqueId)) { - // const existingAccessory = this.animationsFromDiskMap.get(uniqueId); - - // this.animationsFromDiskMap.delete(uniqueId); - // this.logs.info(`[${existingAccessory.context.animationLoop.name}] - Found existing accessory. Updating...`); - // currAccessory = this.processOnlineAccessory(existingAccessory, animationLoop); - // existingAccessoriesList.push(currAccessory); - - // } else if (!this.activeAnimationAcessoriesMap.has(uniqueId)) { //if the accessory is not a duplicate active device - currAccessory = this.createNewAnimation(animationLoop); - this.logs.info(`[${currAccessory.context.animationLoop.name}] - Found new accessory. Registering...`); - newAccessoriesList.push(currAccessory); //add it to new accessory list - // } - - this.activeAnimationAcessoriesMap.set(uniqueId, currAccessory); - // } catch (error) { - // this.logs.error(error); - // } - } - - this.registerNewAccessories(newAccessoriesList); //register new accessories from scan - this.updateExistingAccessories(existingAccessoriesList); - - } - - createNewAnimation(animationLoop: IAnimationLoop): AnimationAccessory { - const { name, pattern, accessoryOffsetMS } = animationLoop; - const homebridgeUUID = this.hap.uuid.generate(name); - const newAccessory: AnimationAccessory = new this.api.platformAccessory(name, homebridgeUUID) as AnimationAccessory; - newAccessory.context.animationLoop = animationLoop; - new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); - - return newAccessory; - - } - - processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationLoop) { - - - const { name, pattern, accessoryOffsetMS } = animationLoop; - - - try { - new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationLoop); - // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); - } catch (error) { - // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); - } - return existingAccessory; - } - - // registerOfflineAccessories() { - // const offlineAccessoriesList: MagicHomeAccessory[] = []; - // const completeDevicesInfo: ICompleteDeviceInfo[] = []; - // this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { - // const { displayName, deviceMetaData, protoDevice, latestUpdate } = offlineAccessory.context; - // const completeDeviceInfo: ICompleteDeviceInfo = { protoDevice, deviceMetaData, latestUpdate }; - // completeDevicesInfo.push(completeDeviceInfo); - // }); - - // const controllers = this.controllerGenerator.generateCustomControllers(completeDevicesInfo); - - // for (const controller of controllers) { - // try { - // const { protoDevice: { uniqueId } } = controller.getCachedDeviceInformation(); - // if (this.accessoriesFromDiskMap.has(uniqueId)) { - // const offlineAccessory = this.accessoriesFromDiskMap.get(uniqueId); - // this.accessoriesFromDiskMap.delete(uniqueId); - // this.processOfflineAccessory(offlineAccessory, controller); - // offlineAccessoriesList.push(offlineAccessory); - // this.cachedAccessoriesMap.set(uniqueId, offlineAccessory); - // } - // } catch (error) { - // this.logs.error(error); - // } - // } +// import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave } from 'magichome-platform'; +// import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; +// import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; +// import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; + +// // import { homekitInterface } from './misc/types'; +// import { Logs } from './logs'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +// import { HomebridgeAnimationAccessory } from './animationAccessory'; + +// const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; +// const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; +// const animationLoops = [colorWave, thunderStruck, cctWave] +// export class AnimationGenerator { + +// public readonly animationsFromDiskMap: Map = new Map(); +// public readonly activeAnimationAcessoriesMap: Map = new Map(); +// public readonly cachedAccessoriesMap: Map = new Map(); +// private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]; +// private hap: HAP; +// private api: API; +// private hbLogger; +// private config: PlatformConfig; +// private logs: Logs; +// constructor( +// api: API, +// logs: Logs, +// hbLogger, +// config, +// animationsFromDiskMap, +// activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]) { +// this.api = api; +// this.hap = api.hap; +// this.hbLogger = hbLogger; +// this.logs = logs; +// this.config = config; +// this.animationsFromDiskMap = animationsFromDiskMap; +// this.activeAccessories = activeAccessories; +// } + + + +// async generateActiveAccessories() { + +// const newAccessoriesList: AnimationAccessory[] = []; +// const existingAccessoriesList: AnimationAccessory[] = []; + +// this.animationsFromDiskMap.forEach((animation) => { +// this.unregisterAccessory(animation) +// }) +// for (const animationLoop of animationLoops) { +// let currAccessory: AnimationAccessory; +// const max = 99999999; +// const min = 11111111 +// const randomInt = Math.floor(Math.random() * (max - min + 1) + min); +// animationLoop.name = randomInt.toString(); + +// const uniqueId = animationLoop.name; + +// // try { +// // if (this.animationsFromDiskMap.has(uniqueId)) { +// // const existingAccessory = this.animationsFromDiskMap.get(uniqueId); + +// // this.animationsFromDiskMap.delete(uniqueId); +// // this.logs.info(`[${existingAccessory.context.animationLoop.name}] - Found existing accessory. Updating...`); +// // currAccessory = this.processOnlineAccessory(existingAccessory, animationLoop); +// // existingAccessoriesList.push(currAccessory); + +// // } else if (!this.activeAnimationAcessoriesMap.has(uniqueId)) { //if the accessory is not a duplicate active device +// currAccessory = this.createNewAnimation(animationLoop); +// this.logs.info(`[${currAccessory.context.animationLoop.name}] - Found new accessory. Registering...`); +// newAccessoriesList.push(currAccessory); //add it to new accessory list +// // } + +// this.activeAnimationAcessoriesMap.set(uniqueId, currAccessory); +// // } catch (error) { +// // this.logs.error(error); +// // } +// } + +// this.registerNewAccessories(newAccessoriesList); //register new accessories from scan +// this.updateExistingAccessories(existingAccessoriesList); + +// } + +// createNewAnimation(animationLoop: IAnimationLoop): AnimationAccessory { +// const { name, pattern, accessoryOffsetMS } = animationLoop; +// const homebridgeUUID = this.hap.uuid.generate(name); +// const newAccessory: AnimationAccessory = new this.api.platformAccessory(name, homebridgeUUID) as AnimationAccessory; +// newAccessory.context.animationLoop = animationLoop; +// new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); + +// return newAccessory; + +// } + +// processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationLoop) { + + +// const { name, pattern, accessoryOffsetMS } = animationLoop; + + +// try { +// new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationLoop); +// // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); +// } catch (error) { +// // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); +// } +// return existingAccessory; +// } + +// // registerOfflineAccessories() { +// // const offlineAccessoriesList: MagicHomeAccessory[] = []; +// // const completeDevicesInfo: ICompleteDeviceInfo[] = []; +// // this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { +// // const { displayName, deviceMetaData, protoDevice, latestUpdate } = offlineAccessory.context; +// // const completeDeviceInfo: ICompleteDeviceInfo = { protoDevice, deviceMetaData, latestUpdate }; +// // completeDevicesInfo.push(completeDeviceInfo); +// // }); + +// // const controllers = this.controllerGenerator.generateCustomControllers(completeDevicesInfo); + +// // for (const controller of controllers) { +// // try { +// // const { protoDevice: { uniqueId } } = controller.getCachedDeviceInformation(); +// // if (this.accessoriesFromDiskMap.has(uniqueId)) { +// // const offlineAccessory = this.accessoriesFromDiskMap.get(uniqueId); +// // this.accessoriesFromDiskMap.delete(uniqueId); +// // this.processOfflineAccessory(offlineAccessory, controller); +// // offlineAccessoriesList.push(offlineAccessory); +// // this.cachedAccessoriesMap.set(uniqueId, offlineAccessory); +// // } +// // } catch (error) { +// // this.logs.error(error); +// // } +// // } - // this.updateExistingAccessories(offlineAccessoriesList); - // } +// // this.updateExistingAccessories(offlineAccessoriesList); +// // } - registerNewAccessories(newAccessories: AnimationAccessory[]) { - // link the accessory to your platform - this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); +// registerNewAccessories(newAccessories: AnimationAccessory[]) { +// // link the accessory to your platform +// this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); - } +// } - updateExistingAccessories(existingAccessories: AnimationAccessory[]) { - this.api.updatePlatformAccessories(existingAccessories); - } +// updateExistingAccessories(existingAccessories: AnimationAccessory[]) { +// this.api.updatePlatformAccessories(existingAccessories); +// } - unregisterAccessory(existingAnimationAccessory) { +// unregisterAccessory(existingAnimationAccessory) { - // this.activeAnimationAcessoriesMap.delete(uuid); - this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAnimationAccessory]); - // this.logs.warn(reason); - } +// // this.activeAnimationAcessoriesMap.delete(uuid); +// this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAnimationAccessory]); +// // this.logs.warn(reason); +// } - // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; +// // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; -} \ No newline at end of file +// } \ No newline at end of file diff --git a/src/animationAccessory.ts b/src/animationAccessory.ts index c193c61..e73fe9c 100644 --- a/src/animationAccessory.ts +++ b/src/animationAccessory.ts @@ -1,538 +1,149 @@ -import type { - API, Service, PlatformConfig, CharacteristicValue, - CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, -} from 'homebridge'; - - -import { cctToWhiteTemperature, clamp, HSVtoRGB, RGBtoHSV, whiteTemperatureToCCT } from './misc/utils'; -import { DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; -// import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE, AnimationController, colorWave } from 'magichome-platform'; -import { Logs } from './logs'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; - -const CCT = 'CCT'; -const HSV = 'HSV'; -const DEFAULT_ACCESSORY_STATE: IAccessoryState = { isOn: false, HSV: { hue: 0, saturation: 0, value: 0 }, brightness: 0 }; -/** - * 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 HomebridgeAnimationAccessory { - - protected service: Service; - protected activeControllerList: BaseController[]; - protected newAccessoryCommand: IAccessoryCommand; - protected latestAccessoryCommand: IAccessoryCommand; - - protected accessoryState: IAccessoryState; - - protected colorCommandMode = HSV; - - protected colorWhiteSimultaniousSaturationLevel; - protected colorOffSaturationLevel; - protected simultaniousDevicesColorWhite; - - protected deviceWriteStatus = 'ready'; - protected deviceReadStatus = 'ready'; - protected readRequestLevel = 0; - - protected queue; - protected slowQueueRetry = false; - protected animationController: AnimationController; - //================================================= - // Start Constructor // - - constructor( - protected hap: HAP, - protected logs, - protected api, - protected accessory, - protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], - protected animationLoop - ) { - - this.setupMisc(); - this.accessoryState = DEFAULT_ACCESSORY_STATE; - // this.logs = logs; - // this.controller = controller; - this.hap = api.hap; - this.api = api; - // this.config = config; - this.initializeCharacteristics(); - this.fetchAndUpdateState(2); - this.animationController = new AnimationController([]); - } - - //================================================= - // End Constructor // - - //================================================= - // Start Setters // - async setOn(value: CharacteristicValue) { - if (this.animationController.isActive) this.animationController.clearAnimations(); - - if (value) { - const accessoryList = this.accessoriesList.filter(accessory => { - // return accessory.accessoryState.isOn; - return true; - }); - - const controllerList = [] - for (const accessory of accessoryList) { - controllerList.push(accessory.getController()); - } - - await this.animationController.animateAsynchronously(controllerList, this.animationLoop).catch(e => { }) - } else { - this.animationController.clearAnimations(); - } - - const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; - this.processAccessoryCommand(accessoryCommand); - } - - setHue(value: CharacteristicValue) { - - this.accessoryState.HSV.hue = value as number; - this.colorCommandMode = HSV; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; - this.processAccessoryCommand(accessoryCommand); - } - - setSaturation(value: CharacteristicValue) { - - this.accessoryState.HSV.saturation = value as number; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; - this.processAccessoryCommand(accessoryCommand); - } - - async setBrightness(value: CharacteristicValue) { - - this.accessoryState.HSV.value = value as number; - this.accessoryState.brightness = value as number; - const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; - this.processAccessoryCommand(accessoryCommand); - } - - // setColorTemperature(value: CharacteristicValue) { - - // this.ColorCommandMode = CCT; - // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; - // this.processAccessoryCommand(accessoryCommand); - // } - - setConfiguredName(value: CharacteristicValue) { - - const name: string = value.toString(); - this.logs.warn('Renaming device to %o', name); - this.accessory.context.displayName = name; - console.log(this.accessory.context.displayName) - this.api.updatePlatformAccessories([this.accessory]); - } - - identifyLight() { - - this.flashEffect(); - } - - //================================================= - // End Setters // - - //================================================= - // Start Getters // - - getHue() { - const { isOn, HSV: { hue, saturation } } = this.accessoryState; - - // this.fetchAndUpdateState(2); - return hue; - - } - - getBrightness() { - const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; - - // this.fetchAndUpdateState(2); - return brightness; - } - - /** - ** @getOn - * instantly retrieve the current on/off state stored in our object - * next call this.getState() which will update all values asynchronously as they are ready - */ - async getOn() { - const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; - - this.fetchAndUpdateState(2); - return isOn; - } - - flashEffect() { - // - } //flashEffect - - //================================================= - // End LightEffects // - - - protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { - - const ret = await this.prepareCommand(accessoryCommand).catch(e => { { } }); - // console.log('return value: ', ret) - } - - protected async prepareCommand(accessoryCommand: IAccessoryCommand) { - - this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); - const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState, DEFAULT_ACCESSORY_STATE); - // console.log(accessoryCommand) - // console.log(sanitizedAcessoryCommand) - if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { - sanitizedAcessoryCommand.isPowerCommand = true; - } - // const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }); - // return completeResponse; - - } - - protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions) { - // const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); - - // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); - - // let response; - // // if (!accessoryCommand.isPowerCommand) response = await this.controller.setAllValues(deviceCommand, commandOptions); - // // else response = await this.controller.setOn(deviceCommand.isOn); - - // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); - // return response; - } - - protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - const { isOn, HSV, colorTemperature, brightness } = accessoryCommand; - - const RGB = HSVtoRGB(HSV); - - const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; - return deviceCommand; - } - - protected async updateLocalState(requestLevel, deviceState) { - - if (!deviceState) { - // deviceState = await this..fetchState(); - } - this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); - // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; - const { HSV: { hue, saturation, value }, colorTemperature, brightness, isOn } = this.deviceStateToAccessoryState(deviceState); - let accessoryState: IAccessoryState; - if (deviceState) { - switch (requestLevel) { - case 0: - // accessoryState = { HSV: { value }, isOn }; - break; - case 1: - // accessoryState = { HSV: { hue, value }, isOn }; - break; - case 2: - accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; - break; - case 3: - accessoryState = { HSV: { hue, saturation, value }, isOn, brightness, colorTemperature }; - break; - } - - this.accessoryState = accessoryState; - // console.log(accessoryState) - +// import type { +// API, Service, PlatformConfig, CharacteristicValue, +// CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, +// } from 'homebridge'; + + +// import { temperatureToCCT, clamp, HSVtoRGB, RGBtoHSV, CCTtoTemperature } from './misc/utils'; +// import { DEFAULT_ACCESSORY_COMMAND, DEFAULT_ACCESSORY_STATE, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; +// // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; +// import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE, AnimationController, colorWave } from 'magichome-platform'; +// import { Logs } from './logs'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; + +// const CCT = 'CCT'; +// const HSV = 'HSV'; +// /** +// * 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 HomebridgeAnimationAccessory { +// protected service: Service; +// protected activeControllerList: BaseController[]; +// protected newAccessoryCommand: IAccessoryCommand; +// protected latestAccessoryCommand: IAccessoryCommand; - this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); - } - - - } - - updateHomekitState() { - const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; - this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, brightness); - } - - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - - const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - //TODO - REPLACE HSV WITH HSV - // eslint-disable-next-line prefer-const - let { hue, saturation, value } = RGBtoHSV(RGB); - let brightness = 0; - - if (value > 0) { - brightness = value; - } - // else if (isOn) { - // brightness = clamp(Math.max(coldWhite, warmWhite) / 2.55, 0, 100); - // if (warmWhite > coldWhite) { - // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); - // } else { - // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); - // } - // } - - const accessoryState: IAccessoryState = { HSV: { hue, saturation, value }, isOn, colorTemperature: 140, brightness }; - return accessoryState; - } - - initializeCharacteristics() { - - const cachedDeviceInformation = this.accessoryState; - // if (cachedDeviceInformation) { - // this.accessory.context.accessoryState = accessoryState; - // } else { - // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; - // } - // const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; - - this.addAccessoryInformationCharacteristic(); - - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); - this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); - - - this.addHueCharacteristic(); - this.addSaturationCharacteristic(); - this.addBrightnessCharacteristic(); - this.addOnCharacteristic(); - this.addConfiguredNameCharacteristic(); - } - - setupMisc() { - - // const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName?? "unknown"); - // const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = Object.assign({}, this.config.globalAccessoryOptions, localAccessoryOptions); - - - // this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; - // this.colorOffSaturationLevel = colorOffSaturationLevel; - // this.logs = new Logs(this.hbLogger, logLevel ?? 3); - - } - - async fetchAndUpdateState(requestLevel) { - try { - this.readRequestLevel = requestLevel; - await this.updateLocalState(this.readRequestLevel, null).catch(e => { }); - this.updateHomekitState(); - } catch (error) { - // this.hbLogger.error(error); - } - } - - - - addOnCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.On) - .onSet(this.setOn.bind(this)) - .onGet(this.getOn.bind(this)); - } - - addHueCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.Hue) - .onSet(this.setHue.bind(this)) - .onGet(this.getHue.bind(this)); - } - - addSaturationCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.Saturation) - .onSet(this.setSaturation.bind(this)); - // .onGet(this.CHANGE_ME.bind(this)); - - } - - removeSaturationCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.Saturation) - .removeAllListeners(this.hap.CharacteristicEventTypes.SET) - .removeAllListeners(this.hap.CharacteristicEventTypes.GET); - - } - - addBrightnessCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.Brightness) - .onSet(this.setBrightness.bind(this)) - .onGet(this.getBrightness.bind(this)); - } - - // addColorTemperatureCharacteristic() { - // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); - // this.service.getCharacteristic(this.hap.Characteristic.ColorTemperature) - // .onSet(this.setColorTemperature.bind(this)) - // .onGet(this.getColorTemperature.bind(this)); - - // if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { - // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); - // this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service); - // this.accessory.configureController(this.adaptiveLightingService); - // } - // } - - addAccessoryInformationCharacteristic() { - - // const { - // protoDevice: { uniqueId, modelNumber }, - // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, - // } = this.accessory.context.cachedDeviceInformation; - // set accessory information - this.accessory.getService(this.hap.Service.AccessoryInformation)! - .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic ') - // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) - // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) - // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') - // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') - .getCharacteristic(this.hap.Characteristic.Identify) - .removeAllListeners(this.hap.CharacteristicEventTypes.SET) - .removeAllListeners(this.hap.CharacteristicEventTypes.GET) - .on(this.hap.CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below - - - this.accessory.getService(this.hap.Service.AccessoryInformation)! - .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); - } - - addConfiguredNameCharacteristic() { - if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { - this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) - .onSet(this.setConfiguredName.bind(this)); - } else { - this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) - .onSet(this.setConfiguredName.bind(this)); - } - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); - - } - - - /* - // Add the garage door service if it doesn't already exist - this.service = - this.accessory.getService(this.hapServ.GarageDoorOpener) || - this.accessory.addService(this.hapServ.GarageDoorOpener) - - // Add some extra Eve characteristics - if (!this.service.testCharacteristic(this.eveChar.LastActivation)) { - this.service.addCharacteristic(this.eveChar.LastActivation) - } - if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) { - this.service.addCharacteristic(this.eveChar.ResetTotal) - } - if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) { - this.service.addCharacteristic(this.eveChar.TimesOpened) - } - - // Add the set handler to the garage door target state characteristic - this.service - .getCharacteristic(this.hapChar.TargetDoorState) - .onSet(value => this.internalTargetUpdate(value)) - this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value - this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value - - // Add the set handler to the garage door reset total characteristic - this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { - this.service.updateCharacteristic(this.eveChar.TimesOpened, 0) - }) - - // Update the obstruction detected to false on plugin load - this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false) - - // Pass the accessory to Fakegato to set up with Eve - this.accessory.eveService = new platform.eveService('door', this.accessory, { - log: platform.config.debugFakegato ? this.log : () => {} - }) - */ +// protected accessoryState: IAccessoryState; +// protected colorCommandMode = HSV; +// protected colorWhiteSimultaniousSaturationLevel; +// protected colorOffSaturationLevel; +// protected simultaniousDevicesColorWhite; -} // ZackneticMagichomePlatformAccessory class -// import type { API, CharacteristicEventTypes, CharacteristicValue, HAP, Service } from "homebridge"; -// import { AnimationController, BaseController } from "magichome-platform"; -// import { Logs } from "./logs"; -// import { AnimationAccessory, DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState } from "./misc/types"; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from "./platformAccessory"; +// protected deviceWriteStatus = 'ready'; +// protected deviceReadStatus = 'ready'; +// protected readRequestLevel = 0; -// export class HomebridgeAnimationAccessory { +// protected queue; +// protected slowQueueRetry = false; +// protected animationController: AnimationController; +// //================================================= +// // Start Constructor // -// protected service: Service; -// protected accessoryState: IAccessoryState = DefaultAccessoryCommand; -// protected accessory: AnimationAccessory; -// protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[]; -// protected activeControllerList: BaseController[]; -// hap: HAP; -// logs: Logs; -// api: API; // constructor( -// hap: HAP, -// logs: Logs, -// api: API, -// accessory: AnimationAccessory, -// // accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[] - +// protected hap: HAP, +// protected logs, +// protected api, +// protected accessory, +// protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], +// protected animationLoop // ) { -// this.accessory = accessory; -// const animationController: AnimationController = new AnimationController([]); -// // this.accessoriesList = accessoriesList; -// this.hap = hap; -// this.logs = logs; + +// this.setupMisc(); +// this.accessoryState = DEFAULT_ACCESSORY_STATE; +// // this.logs = logs; +// // this.controller = controller; +// this.hap = api.hap; // this.api = api; +// // this.config = config; +// this.initializeCharacteristics(); +// this.fetchAndUpdateState(2); +// this.animationController = new AnimationController([]); // } +// //================================================= +// // End Constructor // + +// //================================================= // // Start Setters // // async setOn(value: CharacteristicValue) { +// if (this.animationController.isActive) this.animationController.clearAnimations(); + +// if (value) { +// const accessoryList = this.accessoriesList.filter(accessory => { +// // return accessory.accessoryState.isOn; +// return true; +// }); + +// const controllerList = [] +// for (const accessory of accessoryList) { +// controllerList.push(accessory.getController()); +// } + +// await this.animationController.animateAsynchronously(controllerList, this.animationLoop).catch(e => { }) +// } else { +// this.animationController.clearAnimations(); +// } + // const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; -// // this.processAccessoryCommand(accessoryCommand); +// this.processAccessoryCommand(accessoryCommand); // } // setHue(value: CharacteristicValue) { // this.accessoryState.HSV.hue = value as number; +// this.colorCommandMode = HSV; // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; -// // this.processAccessoryCommand(accessoryCommand); +// this.processAccessoryCommand(accessoryCommand); // } // setSaturation(value: CharacteristicValue) { // this.accessoryState.HSV.saturation = value as number; // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; -// // this.processAccessoryCommand(accessoryCommand); +// this.processAccessoryCommand(accessoryCommand); // } // async setBrightness(value: CharacteristicValue) { // this.accessoryState.HSV.value = value as number; -// this.accessoryState.brightness = value as number; +// this.accessoryState.whiteBrightness = value as number; // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; -// // this.processAccessoryCommand(accessoryCommand); +// this.processAccessoryCommand(accessoryCommand); // } +// // setColorTemperature(value: CharacteristicValue) { + +// // this.ColorCommandMode = CCT; +// // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; +// // this.processAccessoryCommand(accessoryCommand); +// // } + // setConfiguredName(value: CharacteristicValue) { // const name: string = value.toString(); // this.logs.warn('Renaming device to %o', name); -// this.accessory.context.animationLoop.name = name; +// this.accessory.context.displayName = name; +// console.log(this.accessory.context.displayName) // this.api.updatePlatformAccessories([this.accessory]); // } +// identifyLight() { + +// this.flashEffect(); +// } + +// //================================================= +// // End Setters // + +// //================================================= +// // Start Getters // // getHue() { -// const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; +// const { isOn, HSV: { hue, saturation } } = this.accessoryState; // // this.fetchAndUpdateState(2); // return hue; @@ -540,7 +151,7 @@ export class HomebridgeAnimationAccessory { // } // getBrightness() { -// const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; +// const { isOn, HSV: { hue, saturation }, whiteBrightness: brightness } = this.accessoryState; // // this.fetchAndUpdateState(2); // return brightness; @@ -552,41 +163,227 @@ export class HomebridgeAnimationAccessory { // * next call this.getState() which will update all values asynchronously as they are ready // */ // async getOn() { -// const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; +// const { isOn, HSV: { hue, saturation }, whiteBrightness: brightness } = this.accessoryState; -// // this.fetchAndUpdateState(2); +// this.fetchAndUpdateState(2); // return isOn; // } +// flashEffect() { +// // +// } //flashEffect + +// //================================================= +// // End LightEffects // + + +// protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { + +// const ret = await this.prepareCommand(accessoryCommand).catch(e => { { } }); +// // console.log('return value: ', ret) +// } + +// protected async prepareCommand(accessoryCommand: IAccessoryCommand) { + +// this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); +// const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState, DEFAULT_ACCESSORY_STATE); +// // console.log(accessoryCommand) +// // console.log(sanitizedAcessoryCommand) +// if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { +// sanitizedAcessoryCommand.isPowerCommand = true; +// } +// // const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }); +// // return completeResponse; + +// } + +// protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions) { +// // const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); + +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); + +// // let response; +// // // if (!accessoryCommand.isPowerCommand) response = await this.controller.setAllValues(deviceCommand, commandOptions); +// // // else response = await this.controller.setOn(deviceCommand.isOn); + +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); +// // return response; +// } + +// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { +// const { isOn, HSV, } = accessoryCommand; + +// const RGB = HSVtoRGB(HSV); + +// const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; +// return deviceCommand; +// } + +// protected async updateLocalState(requestLevel, deviceState) { + +// if (!deviceState) { +// // deviceState = await this..fetchState(); +// } +// this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); +// // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; +// const { HSV: { hue, saturation, value }, colorTemperature, whiteBrightness: brightness, isOn } = this.deviceStateToAccessoryState(deviceState); +// let accessoryState: IAccessoryState; +// if (deviceState) { +// switch (requestLevel) { +// case 0: +// // accessoryState = { HSV: { value }, isOn }; +// break; +// case 1: +// // accessoryState = { HSV: { hue, value }, isOn }; +// break; +// case 2: +// accessoryState = { HSV: { hue, saturation, value }, isOn, whiteBrightness: brightness }; +// break; +// case 3: +// accessoryState = { HSV: { hue, saturation, value }, isOn, whiteBrightness: brightness, colorTemperature }; +// break; +// } + +// this.accessoryState = accessoryState; +// // console.log(accessoryState) + + + +// this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); +// } + + +// } + +// updateHomekitState() { +// const { isOn, HSV: { hue, saturation }, whiteBrightness: brightness } = this.accessoryState; +// this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); +// this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); +// this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); +// this.service.updateCharacteristic(this.hap.Characteristic.Brightness, brightness); +// } + +// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; +// //TODO - REPLACE HSV WITH HSV +// // eslint-disable-next-line prefer-const +// let { hue, saturation, value } = RGBtoHSV(RGB); +// let brightness = 0; + +// if (value > 0) { +// brightness = value; +// } +// // else if (isOn) { +// // brightness = clamp(Math.max(coldWhite, warmWhite) / 2.55, 0, 100); +// // if (warmWhite > coldWhite) { +// // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); +// // } else { +// // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); +// // } +// // } + +// const accessoryState: IAccessoryState = { HSV: { hue, saturation, value }, isOn, colorTemperature: 140, whiteBrightness: brightness }; +// return accessoryState; +// } + +// initializeCharacteristics() { + +// const cachedDeviceInformation = this.accessoryState; +// // if (cachedDeviceInformation) { +// // this.accessory.context.accessoryState = accessoryState; +// // } else { +// // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; +// // } +// // const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; + +// this.addAccessoryInformationCharacteristic(); + +// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); +// this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); + + +// this.addHueCharacteristic(); +// this.addSaturationCharacteristic(); +// this.addBrightnessCharacteristic(); +// this.addOnCharacteristic(); +// this.addConfiguredNameCharacteristic(); +// } + +// setupMisc() { + +// // const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName?? "unknown"); +// // const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = Object.assign({}, this.config.globalAccessoryOptions, localAccessoryOptions); + + +// // this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; +// // this.colorOffSaturationLevel = colorOffSaturationLevel; +// // this.logs = new Logs(this.hbLogger, logLevel ?? 3); + +// } + +// async fetchAndUpdateState(requestLevel) { +// try { +// this.readRequestLevel = requestLevel; +// await this.updateLocalState(this.readRequestLevel, null).catch(e => { }); +// this.updateHomekitState(); +// } catch (error) { +// // this.hbLogger.error(error); +// } +// } + + + // addOnCharacteristic() { -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); +// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); // this.service.getCharacteristic(this.hap.Characteristic.On) // .onSet(this.setOn.bind(this)) // .onGet(this.getOn.bind(this)); // } // addHueCharacteristic() { -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); +// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); // this.service.getCharacteristic(this.hap.Characteristic.Hue) // .onSet(this.setHue.bind(this)) // .onGet(this.getHue.bind(this)); // } // addSaturationCharacteristic() { -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); +// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); // this.service.getCharacteristic(this.hap.Characteristic.Saturation) // .onSet(this.setSaturation.bind(this)); // // .onGet(this.CHANGE_ME.bind(this)); // } +// removeSaturationCharacteristic() { +// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); +// this.service.getCharacteristic(this.hap.Characteristic.Saturation) +// .removeAllListeners(this.hap.CharacteristicEventTypes.SET) +// .removeAllListeners(this.hap.CharacteristicEventTypes.GET); + +// } + // addBrightnessCharacteristic() { -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); +// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); // this.service.getCharacteristic(this.hap.Characteristic.Brightness) // .onSet(this.setBrightness.bind(this)) // .onGet(this.getBrightness.bind(this)); // } +// // addColorTemperatureCharacteristic() { +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); +// // this.service.getCharacteristic(this.hap.Characteristic.ColorTemperature) +// // .onSet(this.setColorTemperature.bind(this)) +// // .onGet(this.getColorTemperature.bind(this)); + +// // if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { +// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); +// // this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service); +// // this.accessory.configureController(this.adaptiveLightingService); +// // } +// // } + // addAccessoryInformationCharacteristic() { // // const { @@ -595,13 +392,15 @@ export class HomebridgeAnimationAccessory { // // } = this.accessory.context.cachedDeviceInformation; // // set accessory information // this.accessory.getService(this.hap.Service.AccessoryInformation)! -// // .removeAllListeners(CharacteristicEventTypes.SET) -// // .removeAllListeners(CharacteristicEventTypes.GET) -// .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') -// // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) -// // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) -// // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') -// // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') +// .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic ') +// // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) +// // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) +// // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') +// // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') +// .getCharacteristic(this.hap.Characteristic.Identify) +// .removeAllListeners(this.hap.CharacteristicEventTypes.SET) +// .removeAllListeners(this.hap.CharacteristicEventTypes.GET) +// .on(this.hap.CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below // this.accessory.getService(this.hap.Service.AccessoryInformation)! @@ -616,28 +415,228 @@ export class HomebridgeAnimationAccessory { // this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) // .onSet(this.setConfiguredName.bind(this)); // } -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); +// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); // } -// initializeCharacteristics() { - -// // const cachedDeviceInformation = this.controller.getCachedDeviceInformation(); -// // if (cachedDeviceInformation) { -// // this.accessory.context.accessoryState = accessoryState; -// // } else { -// // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; -// // } -// // const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; - -// this.addAccessoryInformationCharacteristic(); -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); -// this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); -// this.addHueCharacteristic(); -// this.addSaturationCharacteristic(); -// this.addBrightnessCharacteristic(); -// this.addOnCharacteristic(); -// this.addConfiguredNameCharacteristic(); -// } -// } +// /* +// // Add the garage door service if it doesn't already exist +// this.service = +// this.accessory.getService(this.hapServ.GarageDoorOpener) || +// this.accessory.addService(this.hapServ.GarageDoorOpener) + +// // Add some extra Eve characteristics +// if (!this.service.testCharacteristic(this.eveChar.LastActivation)) { +// this.service.addCharacteristic(this.eveChar.LastActivation) +// } +// if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) { +// this.service.addCharacteristic(this.eveChar.ResetTotal) +// } +// if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) { +// this.service.addCharacteristic(this.eveChar.TimesOpened) +// } + +// // Add the set handler to the garage door target state characteristic +// this.service +// .getCharacteristic(this.hapChar.TargetDoorState) +// .onSet(value => this.internalTargetUpdate(value)) +// this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value +// this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value + +// // Add the set handler to the garage door reset total characteristic +// this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { +// this.service.updateCharacteristic(this.eveChar.TimesOpened, 0) +// }) + +// // Update the obstruction detected to false on plugin load +// this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false) + +// // Pass the accessory to Fakegato to set up with Eve +// this.accessory.eveService = new platform.eveService('door', this.accessory, { +// log: platform.config.debugFakegato ? this.log : () => {} +// }) +// */ + + + +// } // ZackneticMagichomePlatformAccessory class +// // import type { API, CharacteristicEventTypes, CharacteristicValue, HAP, Service } from "homebridge"; +// // import { AnimationController, BaseController } from "magichome-platform"; +// // import { Logs } from "./logs"; +// // import { AnimationAccessory, DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState } from "./misc/types"; +// // import { HomebridgeMagichomeDynamicPlatformAccessory } from "./platformAccessory"; + +// // export class HomebridgeAnimationAccessory { + +// // protected service: Service; +// // protected accessoryState: IAccessoryState = DefaultAccessoryCommand; +// // protected accessory: AnimationAccessory; +// // protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[]; +// // protected activeControllerList: BaseController[]; +// // hap: HAP; +// // logs: Logs; +// // api: API; +// // constructor( +// // hap: HAP, +// // logs: Logs, +// // api: API, +// // accessory: AnimationAccessory, +// // // accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[] + +// // ) { +// // this.accessory = accessory; +// // const animationController: AnimationController = new AnimationController([]); +// // // this.accessoriesList = accessoriesList; +// // this.hap = hap; +// // this.logs = logs; +// // this.api = api; +// // } + +// // // Start Setters // +// // async setOn(value: CharacteristicValue) { +// // const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; +// // // this.processAccessoryCommand(accessoryCommand); +// // } + +// // setHue(value: CharacteristicValue) { + +// // this.accessoryState.HSV.hue = value as number; +// // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; +// // // this.processAccessoryCommand(accessoryCommand); +// // } + +// // setSaturation(value: CharacteristicValue) { + +// // this.accessoryState.HSV.saturation = value as number; +// // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; +// // // this.processAccessoryCommand(accessoryCommand); +// // } + +// // async setBrightness(value: CharacteristicValue) { + +// // this.accessoryState.HSV.value = value as number; +// // this.accessoryState.brightness = value as number; +// // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; +// // // this.processAccessoryCommand(accessoryCommand); +// // } + +// // setConfiguredName(value: CharacteristicValue) { + +// // const name: string = value.toString(); +// // this.logs.warn('Renaming device to %o', name); +// // this.accessory.context.animationLoop.name = name; +// // this.api.updatePlatformAccessories([this.accessory]); +// // } + + +// // getHue() { +// // const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + +// // // this.fetchAndUpdateState(2); +// // return hue; + +// // } + +// // getBrightness() { +// // const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + +// // // this.fetchAndUpdateState(2); +// // return brightness; +// // } + +// // /** +// // ** @getOn +// // * instantly retrieve the current on/off state stored in our object +// // * next call this.getState() which will update all values asynchronously as they are ready +// // */ +// // async getOn() { +// // const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; + +// // // this.fetchAndUpdateState(2); +// // return isOn; +// // } + +// // addOnCharacteristic() { +// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); +// // this.service.getCharacteristic(this.hap.Characteristic.On) +// // .onSet(this.setOn.bind(this)) +// // .onGet(this.getOn.bind(this)); +// // } + +// // addHueCharacteristic() { +// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); +// // this.service.getCharacteristic(this.hap.Characteristic.Hue) +// // .onSet(this.setHue.bind(this)) +// // .onGet(this.getHue.bind(this)); +// // } + +// // addSaturationCharacteristic() { +// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); +// // this.service.getCharacteristic(this.hap.Characteristic.Saturation) +// // .onSet(this.setSaturation.bind(this)); +// // // .onGet(this.CHANGE_ME.bind(this)); + +// // } + +// // addBrightnessCharacteristic() { +// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); +// // this.service.getCharacteristic(this.hap.Characteristic.Brightness) +// // .onSet(this.setBrightness.bind(this)) +// // .onGet(this.getBrightness.bind(this)); +// // } + +// // addAccessoryInformationCharacteristic() { + +// // // const { +// // // protoDevice: { uniqueId, modelNumber }, +// // // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, +// // // } = this.accessory.context.cachedDeviceInformation; +// // // set accessory information +// // this.accessory.getService(this.hap.Service.AccessoryInformation)! +// // // .removeAllListeners(CharacteristicEventTypes.SET) +// // // .removeAllListeners(CharacteristicEventTypes.GET) +// // .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') +// // // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) +// // // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) +// // // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') +// // // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') + + +// // this.accessory.getService(this.hap.Service.AccessoryInformation)! +// // .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); +// // } + +// // addConfiguredNameCharacteristic() { +// // if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { +// // this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) +// // .onSet(this.setConfiguredName.bind(this)); +// // } else { +// // this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) +// // .onSet(this.setConfiguredName.bind(this)); +// // } +// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + +// // } + +// // initializeCharacteristics() { + +// // // const cachedDeviceInformation = this.controller.getCachedDeviceInformation(); +// // // if (cachedDeviceInformation) { +// // // this.accessory.context.accessoryState = accessoryState; +// // // } else { +// // // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; +// // // } +// // // const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; + +// // this.addAccessoryInformationCharacteristic(); + +// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); +// // this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); +// // this.addHueCharacteristic(); +// // this.addSaturationCharacteristic(); +// // this.addBrightnessCharacteristic(); +// // this.addOnCharacteristic(); +// // this.addConfiguredNameCharacteristic(); +// // } +// // } diff --git a/src/misc/types.ts b/src/misc/types.ts index 18526c3..43109fe 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -46,24 +46,45 @@ export interface IAccessoryContext { export interface IAccessoryState { isOn: boolean, HSV: IColorHSV, - brightness: number, - colorTemperature?: number, + TB: IColorTB } - -export interface IAccessoryCommand { +export interface IPartialAccessoryCommand { isOn?: boolean, - HSV?: IColorHSV, + HSV?: IPartialColorHSV, + TB?: IPartialColorTB, colorTemperature?: number, - brightness?: number, isPowerCommand?: boolean, } +export interface IAccessoryCommand { + isOn: boolean, + HSV: IColorHSV, + TB: IColorTB + isPowerCommand: boolean, +} + export interface IColorHSV { hue: number; saturation: number; value: number; } +export interface IColorTB { + temperature: number; + brightness: number; +} + +export interface IPartialColorTB { + temperature?: number; + brightness?: number; +} + +export interface IPartialColorHSV { + hue?: number; + saturation?: number; + value?: number; +} + export interface IConfigOptions { logLevel: number, @@ -72,20 +93,36 @@ export interface IConfigOptions { colorWhiteSimultaniousSaturationLevel?: number, } -/*----------------------[Constants]----------------------*/ +/*----------------------[DEFAULT VALIES]----------------------*/ -export const ColorCommandModes = { +export const COLOR_COMMAND_MODES = { CCT: 'CCT', HSV: 'HSV', }; -export const DefaultAccessoryCommand = { +export const DEFAULT_ACCESSORY_STATE: IAccessoryState = { + isOn: false, + HSV: { + hue: 0, + saturation: 0, + value: 0, + }, + TB: { + temperature: 0, + brightness: 0 + } +}; + +export const DEFAULT_ACCESSORY_COMMAND: IAccessoryCommand = { isOn: false, + isPowerCommand: false, HSV: { hue: 0, saturation: 0, value: 0, }, - colorTemperature: 0, - brightness: 0, + TB: { + temperature: 0, + brightness: 0 + } }; \ No newline at end of file diff --git a/src/misc/utils.ts b/src/misc/utils.ts index 4882fea..b125f08 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -1,6 +1,6 @@ import { existsSync, readFileSync } from 'fs'; import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -import { IAccessoryCommand, IAccessoryState, IColorHSV } from './types'; +import { IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB } from './types'; export function clamp(value: number, min: number, max: number) { @@ -153,32 +153,34 @@ export function loadJson(file: string, replacement: T): T { * the closer to 180 the weaker warmWhite brightness becomes * the closer to 90/270 the stronger both warmWhite and coldWhite become simultaniously */ -export function convertHueToColorCCT(hue: number): IColorCCT { - let multiplier = 0; +export function TBtoCCT(TB: IColorTB): IColorCCT { + let multiplier = 1; let warmWhite = 0, coldWhite = 0; - - - if (hue <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue - multiplier = ((hue / 90)); - coldWhite = Math.round((127 * multiplier)); - warmWhite = 255 - coldWhite; - } else if (hue > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue - multiplier = (1 - (hue - 270) / 90); - coldWhite = Math.round((127 * multiplier)); - warmWhite = 255 - coldWhite; - } else if (hue > 180 && hue <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue - multiplier = ((hue - 180) / 90); - warmWhite = Math.round((127 * multiplier)); - coldWhite = 255 - warmWhite; - - } else if (hue > 90 && hue <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue - multiplier = (1 - (hue - 90) / 90); - warmWhite = Math.round((127 * multiplier)); - coldWhite = 255 - warmWhite; + const { temperature, brightness } = TB; + + console.log(`TEMP: ${temperature}, BRIGHT: ${brightness}`) + + if (temperature <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue + multiplier = ((temperature / 90)); + coldWhite = Math.round((255 * multiplier)); + warmWhite = 255; + } else if (temperature > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue + multiplier = (1 - (temperature - 270) / 90); + coldWhite = Math.round((255 * multiplier)); + warmWhite = 255; + } else if (temperature > 180 && temperature <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue + multiplier = ((temperature - 180) / 90); + warmWhite = Math.round((255 * multiplier)); + coldWhite = 255; + + } else if (temperature > 90 && temperature <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue + multiplier = (1 - (temperature - 90) / 90); + warmWhite = Math.round((255 * multiplier)); + coldWhite = 255; } - - return { warmWhite, coldWhite }; -} //hueToWhiteTemperature + const CCT = { warmWhite: Math.round((warmWhite * brightness) / 100), coldWhite: Math.round((coldWhite * brightness) / 100) } + return CCT +} //TBtoCCT /* HSV to RGB conversion formula @@ -192,7 +194,7 @@ m = V - C export function HSVtoRGB(HSV: IColorHSV): IColorRGB { const { hue, saturation, value }: IColorHSV = HSV; let [H, S, V] = [hue, saturation, value]; - H = clamp(H, 0, 359) + H = clamp(H, 0, 360) S = clamp(S, 0, 100) V = clamp(V, 0, 100) @@ -203,13 +205,14 @@ export function HSVtoRGB(HSV: IColorHSV): IColorRGB { const X = C * (1 - Math.abs(((H / 60) % 2) - 1)); const m = V - C; + let order; if (H < 60) order = [C, X, 0]; else if (H < 120) order = [X, C, 0]; else if (H < 180) order = [0, C, X]; else if (H < 240) order = [0, X, C]; else if (H < 300) order = [X, 0, C]; - else if (H < 360) order = [C, 0, X]; + else if (H <= 360) order = [C, 0, X]; const [dR, dG, dB] = order; const [red, green, blue] = [Math.round((dR + m) * 255), Math.round((dG + m) * 255), Math.round((dB + m) * 255)] @@ -242,7 +245,7 @@ export function RGBtoHSV(RGB: IColorRGB): IColorHSV { if (V === 0) S = 0; else S = D / V; - + S *= 100; V *= 100; // console.log("-- RECEIVED -- H: ", H, "S: ", S, "V: ", V) @@ -250,29 +253,28 @@ export function RGBtoHSV(RGB: IColorRGB): IColorHSV { return { hue: H, saturation: S, value: V }; } -export function cctToWhiteTemperature(CCT: number, multiplier = 0): { warmWhite: number, coldWhite: number } { - CCT -= 140; +export function temperatureToCCT(temperature: number, multiplier = 0): { warmWhite: number, coldWhite: number } { let warmWhite, coldWhite; const threshold = 110; - if (CCT >= threshold) { + if (temperature >= threshold) { warmWhite = 127; - multiplier = (1 - ((CCT - threshold) / (360 - threshold))); + multiplier = (1 - ((temperature - threshold) / (360 - threshold))); coldWhite = Math.round((127 * multiplier)); } else { coldWhite = 127; - multiplier = (CCT / threshold); + multiplier = (temperature / threshold); warmWhite = Math.round((127 * multiplier)); } return { warmWhite, coldWhite }; } -export function whiteTemperatureToCCT(whiteTemperature: IColorCCT) { - const { coldWhite } = whiteTemperature; - const CCT = (coldWhite * 1.41) + 140; - - return CCT; +export function CCTtoTB(CCT: IColorCCT): IColorTB { + const { warmWhite, coldWhite } = CCT; + const temperature = Math.round(coldWhite * 1.4117); + const brightness = Math.round(Math.max(warmWhite, coldWhite) / 2.55) + return { temperature, brightness }; } /* diff --git a/src/platform.ts b/src/platform.ts index 30bfed6..88ecbd5 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -11,7 +11,7 @@ import { } from 'homebridge'; import { ControllerGenerator } from 'magichome-platform'; -import { AnimationGenerator } from './AnimationGenerator' +// import { AnimationGenerator } from './AnimationGenerator' import { AnimationAccessory, MagicHomeAccessory } from './misc/types'; import { AccessoryGenerator } from './AccessoryGenerator'; import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; @@ -106,8 +106,8 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); const activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] = await accesssoryGenerator.discoverDevices(); - const animationGenerator = new AnimationGenerator(this.api, this.log, this.hbLogger, this.config, this.animationsFromDiskMap, activeAccessories); - animationGenerator.generateActiveAccessories(); + // const animationGenerator = new AnimationGenerator(this.api, this.log, this.hbLogger, this.config, this.animationsFromDiskMap, activeAccessories); + // animationGenerator.generateActiveAccessories(); // this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); } From 43fd44b0ddef2301ef0d0f622558b3b6d18c88dc Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Sun, 28 Aug 2022 14:01:12 -0400 Subject: [PATCH 36/42] non-functional attempt to control cct and rgb seperately --- src/AccessoryGenerator.ts | 2 +- src/misc/types.ts | 6 ++-- src/platformAccessory.ts | 58 +++++++++++++++++++++++++++------------ 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 199fe7c..8b5791a 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -93,7 +93,7 @@ export class AccessoryGenerator { // console.log(existingAccessory.context.displayName) // console.log(existingAccessory.context.displayName.toLocaleLowerCase().includes('zack')); - // if (!existingAccessory.context.displayName.includes('Zacks')) { + // if (!existingAccessory.context.displayName.includes('Office')) { // continue; // } this.accessoriesFromDiskMap.delete(uniqueId); diff --git a/src/misc/types.ts b/src/misc/types.ts index 43109fe..29561f9 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -101,15 +101,15 @@ export const COLOR_COMMAND_MODES = { }; export const DEFAULT_ACCESSORY_STATE: IAccessoryState = { - isOn: false, + isOn: true, HSV: { hue: 0, saturation: 0, - value: 0, + value: 100, }, TB: { temperature: 0, - brightness: 0 + brightness: 100 } }; diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index be5b223..f262e0d 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -24,7 +24,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected readonly hap: HAP; protected adaptiveLightingService; - protected newAccessoryCommand: IAccessoryCommand; + protected newAccessoryCommand: IPartialAccessoryCommand = {}; protected latestAccessoryCommand: IAccessoryCommand; public accessoryState: IAccessoryState; @@ -44,6 +44,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected lastValue: number; lastHue: number; lastBrightness: number; + waitingSendoff: boolean; //================================================= // Start Constructor // @@ -161,8 +162,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { const { HSV: { value }, TB: { brightness } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); let _brightness; - if (this.colorCommandMode = COLOR_MODE) _brightness = brightness; - else _brightness = value; + if (this.colorCommandMode == COLOR_MODE) _brightness = value; + else _brightness = brightness; this.fetchAndUpdateState(2); return _brightness; @@ -188,19 +189,35 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // End LightEffects // //TODO, Severe! Bundle commands so that close consecutive changes in hue, sat, and brightness aren't sent as separate commands - protected async processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { + protected processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { + + overwriteDeep(this.newAccessoryCommand, partialAccessoryCommand); + if (!this.waitingSendoff) { + this.waitingSendoff = true; + + return new Promise((resolve, reject) => { + setTimeout(async () => { + + + const sanitizedAcessoryCommand = this.completeAccessoryCommand(this.newAccessoryCommand); + this.newAccessoryCommand = {}; + const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); + + const completeResponse: ICompleteResponse | void = await this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand).catch(e => { }); + resolve(completeResponse); + return; + }, 20); + }) + + } - const sanitizedAcessoryCommand = await this.completeAccessoryCommand(partialAccessoryCommand); - const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); - const completeResponse: ICompleteResponse | void = await this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand).catch(e => { }); - return completeResponse; } protected completeAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand): IAccessoryCommand { this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, partialAccessoryCommand, this.accessoryState); - console.log(partialAccessoryCommand, this.accessoryState) + // console.log(partialAccessoryCommand, this.accessoryState) if (partialAccessoryCommand.hasOwnProperty('isOn') && !(partialAccessoryCommand.hasOwnProperty('HSV') || partialAccessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; } @@ -208,11 +225,13 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): { deviceCommand: IDeviceCommand, commandOptions: ICommandOptions } { - const { isOn, HSV: { hue, saturation, value }, TB } = accessoryCommand; - const commandOptions: ICommandOptions = { colorAssist: true, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; - console.log(this.colorCommandMode) + let { isOn, HSV: { hue, saturation, value }, TB } = accessoryCommand; + const { temperature, brightness } = TB; + + if (Math.max(brightness, value) > 0) isOn = true; + const commandOptions: ICommandOptions = { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; - let red, green, blue, warmWhite, coldWhite; + let red, green, blue, warmWhite, coldWhite, colorMask = null; if (saturation < 95) { this.colorCommandMode = WHITE_MODE; @@ -222,17 +241,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { if (saturation < 5) { red = 0, green = 0, blue = 0; + colorMask = COLOR_MASKS.WHITE } } else { + colorMask = COLOR_MASKS.COLOR this.colorCommandMode = COLOR_MODE; ({ red, green, blue } = HSVtoRGB({ hue, saturation, value })); warmWhite = 0; coldWhite = 0; } + console.log(this.colorCommandMode) - const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, colorMask: null, CCT: { warmWhite, coldWhite } }; - + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, colorMask, CCT: { warmWhite, coldWhite } }; + console.log(deviceCommand) return { deviceCommand, commandOptions }; } @@ -302,7 +324,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); + // this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); this.service.updateCharacteristic(this.hap.Characteristic.Hue, _hue); this.service.updateCharacteristic(this.hap.Characteristic.Brightness, _brightness); } @@ -312,7 +334,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { let { RGB, CCT, isOn } = deviceState; const HSV: IColorHSV = RGBtoHSV(RGB); const TB: IColorTB = CCTtoTB(CCT); - HSV.saturation = clamp(HSV.saturation - (TB.brightness / 4), 0, 100) + HSV.saturation = clamp(HSV.saturation - TB.brightness, 0, 100) + // if(HSV.saturation < 95) this.colorCommandMode = WHITE_MODE + console.log(RGB, CCT, HSV, TB) const accessoryState: IAccessoryState = { HSV, TB, isOn }; return accessoryState; } From 43c0895005202392a2cf14f695d3fae5aab661ad Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Fri, 21 Oct 2022 14:43:20 -0400 Subject: [PATCH 37/42] changes to throws --- src/AnimationGenerator.ts | 271 ++++++------- src/animationAccessory.ts | 800 ++++++++------------------------------ src/misc/types.ts | 12 +- src/misc/utils.ts | 2 - src/platform.ts | 9 +- src/platformAccessory.ts | 221 ++++------- 6 files changed, 363 insertions(+), 952 deletions(-) diff --git a/src/AnimationGenerator.ts b/src/AnimationGenerator.ts index 2d70365..1b95b2e 100644 --- a/src/AnimationGenerator.ts +++ b/src/AnimationGenerator.ts @@ -1,163 +1,124 @@ -// import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave } from 'magichome-platform'; -// import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; -// import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; -// import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; - -// // import { homekitInterface } from './misc/types'; -// import { Logs } from './logs'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -// import { HomebridgeAnimationAccessory } from './animationAccessory'; - -// const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; -// const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; -// const animationLoops = [colorWave, thunderStruck, cctWave] -// export class AnimationGenerator { - -// public readonly animationsFromDiskMap: Map = new Map(); -// public readonly activeAnimationAcessoriesMap: Map = new Map(); -// public readonly cachedAccessoriesMap: Map = new Map(); -// private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]; -// private hap: HAP; -// private api: API; -// private hbLogger; -// private config: PlatformConfig; -// private logs: Logs; -// constructor( -// api: API, -// logs: Logs, -// hbLogger, -// config, -// animationsFromDiskMap, -// activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]) { -// this.api = api; -// this.hap = api.hap; -// this.hbLogger = hbLogger; -// this.logs = logs; -// this.config = config; -// this.animationsFromDiskMap = animationsFromDiskMap; -// this.activeAccessories = activeAccessories; -// } - - - -// async generateActiveAccessories() { - -// const newAccessoriesList: AnimationAccessory[] = []; -// const existingAccessoriesList: AnimationAccessory[] = []; - -// this.animationsFromDiskMap.forEach((animation) => { -// this.unregisterAccessory(animation) -// }) -// for (const animationLoop of animationLoops) { -// let currAccessory: AnimationAccessory; -// const max = 99999999; -// const min = 11111111 -// const randomInt = Math.floor(Math.random() * (max - min + 1) + min); -// animationLoop.name = randomInt.toString(); - -// const uniqueId = animationLoop.name; - -// // try { -// // if (this.animationsFromDiskMap.has(uniqueId)) { -// // const existingAccessory = this.animationsFromDiskMap.get(uniqueId); - -// // this.animationsFromDiskMap.delete(uniqueId); -// // this.logs.info(`[${existingAccessory.context.animationLoop.name}] - Found existing accessory. Updating...`); -// // currAccessory = this.processOnlineAccessory(existingAccessory, animationLoop); -// // existingAccessoriesList.push(currAccessory); - -// // } else if (!this.activeAnimationAcessoriesMap.has(uniqueId)) { //if the accessory is not a duplicate active device -// currAccessory = this.createNewAnimation(animationLoop); -// this.logs.info(`[${currAccessory.context.animationLoop.name}] - Found new accessory. Registering...`); -// newAccessoriesList.push(currAccessory); //add it to new accessory list -// // } - -// this.activeAnimationAcessoriesMap.set(uniqueId, currAccessory); -// // } catch (error) { -// // this.logs.error(error); -// // } -// } - -// this.registerNewAccessories(newAccessoriesList); //register new accessories from scan -// this.updateExistingAccessories(existingAccessoriesList); - -// } - -// createNewAnimation(animationLoop: IAnimationLoop): AnimationAccessory { -// const { name, pattern, accessoryOffsetMS } = animationLoop; -// const homebridgeUUID = this.hap.uuid.generate(name); -// const newAccessory: AnimationAccessory = new this.api.platformAccessory(name, homebridgeUUID) as AnimationAccessory; -// newAccessory.context.animationLoop = animationLoop; -// new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); - -// return newAccessory; - -// } - -// processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationLoop) { - - -// const { name, pattern, accessoryOffsetMS } = animationLoop; - - -// try { -// new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationLoop); -// // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); -// } catch (error) { -// // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); -// } -// return existingAccessory; -// } - -// // registerOfflineAccessories() { -// // const offlineAccessoriesList: MagicHomeAccessory[] = []; -// // const completeDevicesInfo: ICompleteDeviceInfo[] = []; -// // this.accessoriesFromDiskMap.forEach(async (offlineAccessory) => { -// // const { displayName, deviceMetaData, protoDevice, latestUpdate } = offlineAccessory.context; -// // const completeDeviceInfo: ICompleteDeviceInfo = { protoDevice, deviceMetaData, latestUpdate }; -// // completeDevicesInfo.push(completeDeviceInfo); -// // }); - -// // const controllers = this.controllerGenerator.generateCustomControllers(completeDevicesInfo); - -// // for (const controller of controllers) { -// // try { -// // const { protoDevice: { uniqueId } } = controller.getCachedDeviceInformation(); -// // if (this.accessoriesFromDiskMap.has(uniqueId)) { -// // const offlineAccessory = this.accessoriesFromDiskMap.get(uniqueId); -// // this.accessoriesFromDiskMap.delete(uniqueId); -// // this.processOfflineAccessory(offlineAccessory, controller); -// // offlineAccessoriesList.push(offlineAccessory); -// // this.cachedAccessoriesMap.set(uniqueId, offlineAccessory); -// // } -// // } catch (error) { -// // this.logs.error(error); -// // } -// // } +import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave } from 'magichome-platform'; +import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; +import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; +import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; + +// import { homekitInterface } from './misc/types'; +import { Logs } from './logs'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +import { HomebridgeAnimationAccessory } from './animationAccessory'; + +const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; +const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; +const animationLoops = [colorWave, thunderStruck] +export class AnimationGenerator { + + public readonly animationsFromDiskMap: Map = new Map(); + public readonly activeAnimationAcessoriesMap: Map = new Map(); + public readonly cachedAccessoriesMap: Map = new Map(); + private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]; + private hap: HAP; + private api: API; + private hbLogger; + private config: PlatformConfig; + private logs: Logs; + constructor( + api: API, + logs: Logs, + hbLogger, + config, + animationsFromDiskMap, + activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]) { + this.api = api; + this.hap = api.hap; + this.hbLogger = hbLogger; + this.logs = logs; + this.config = config; + this.animationsFromDiskMap = animationsFromDiskMap; + this.activeAccessories = activeAccessories; + } + + + + async generateActiveAccessories() { + + const newAccessoriesList: AnimationAccessory[] = []; + const existingAccessoriesList: AnimationAccessory[] = []; + + + for (const animationLoop of animationLoops) { + const homebridgeUUID = this.hap.uuid.generate(animationLoop.name); + console.log(animationLoop.name) + try { + if (this.animationsFromDiskMap.has(homebridgeUUID)) { + const existingAnimationAccessory = this.animationsFromDiskMap.get(homebridgeUUID); + this.animationsFromDiskMap.delete(homebridgeUUID); + this.logs.info(`[${animationLoop.name}] - Found existing accessory. Updating...`); + const existingAccessory = this.processOnlineAccessory(existingAnimationAccessory, animationLoop); + existingAccessoriesList.push(existingAccessory); + + } else if (!this.activeAnimationAcessoriesMap.has(homebridgeUUID)) { //if the accessory is not a duplicate active device + const newAccessory: AnimationAccessory = this.createNewAnimation(animationLoop); + this.logs.info(`[${animationLoop.name}] - Found new accessory. Registering...`); + newAccessoriesList.push(newAccessory); //add it to new accessory list + + + this.activeAnimationAcessoriesMap.set(homebridgeUUID, newAccessory); + + } + + + } catch (e) { + this.logs.error(e) + } + } + + this.registerNewAccessories(newAccessoriesList); //register new accessories from scan + this.updateExistingAccessories(existingAccessoriesList); + } + + createNewAnimation(animationLoop: IAnimationLoop): AnimationAccessory { + let homebridgeUUID = this.hap.uuid.generate(animationLoop.name); + console.log(homebridgeUUID, animationLoop.name) + const newAccessory: AnimationAccessory = new this.api.platformAccessory(animationLoop.name, homebridgeUUID) as AnimationAccessory; + newAccessory.context.animationLoop = animationLoop; + new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); + return newAccessory; + } + + processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationLoop) { + + + // const { name, pattern, accessoryOffsetMS } = animationLoop; + + + try { + new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationLoop); + // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); + } catch (error) { + // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); + } + return existingAccessory; + } -// // this.updateExistingAccessories(offlineAccessoriesList); -// // } + registerNewAccessories(newAccessories: AnimationAccessory[]) { + // link the accessory to your platform + this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); + } + updateExistingAccessories(existingAccessories: AnimationAccessory[]) { + this.api.updatePlatformAccessories(existingAccessories); + } -// registerNewAccessories(newAccessories: AnimationAccessory[]) { -// // link the accessory to your platform -// this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); + unregisterAccessory(existingAnimationAccessory) { -// } + // this.activeAnimationAcessoriesMap.delete(uuid); + this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAnimationAccessory]); + // this.logs.warn(reason); + } -// updateExistingAccessories(existingAccessories: AnimationAccessory[]) { -// this.api.updatePlatformAccessories(existingAccessories); -// } + // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; -// unregisterAccessory(existingAnimationAccessory) { - -// // this.activeAnimationAcessoriesMap.delete(uuid); -// this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAnimationAccessory]); -// // this.logs.warn(reason); -// } - -// // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; - -// } \ No newline at end of file +} \ No newline at end of file diff --git a/src/animationAccessory.ts b/src/animationAccessory.ts index e73fe9c..bb0b4fd 100644 --- a/src/animationAccessory.ts +++ b/src/animationAccessory.ts @@ -1,642 +1,158 @@ -// import type { -// API, Service, PlatformConfig, CharacteristicValue, -// CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, -// } from 'homebridge'; - - -// import { temperatureToCCT, clamp, HSVtoRGB, RGBtoHSV, CCTtoTemperature } from './misc/utils'; -// import { DEFAULT_ACCESSORY_COMMAND, DEFAULT_ACCESSORY_STATE, IAccessoryCommand, IAccessoryState, IConfigOptions, MagicHomeAccessory } from './misc/types'; -// // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -// import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE, AnimationController, colorWave } from 'magichome-platform'; -// import { Logs } from './logs'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; - -// const CCT = 'CCT'; -// const HSV = 'HSV'; -// /** -// * 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 HomebridgeAnimationAccessory { - -// protected service: Service; -// protected activeControllerList: BaseController[]; -// protected newAccessoryCommand: IAccessoryCommand; -// protected latestAccessoryCommand: IAccessoryCommand; - -// protected accessoryState: IAccessoryState; - -// protected colorCommandMode = HSV; - -// protected colorWhiteSimultaniousSaturationLevel; -// protected colorOffSaturationLevel; -// protected simultaniousDevicesColorWhite; - -// protected deviceWriteStatus = 'ready'; -// protected deviceReadStatus = 'ready'; -// protected readRequestLevel = 0; - -// protected queue; -// protected slowQueueRetry = false; -// protected animationController: AnimationController; -// //================================================= -// // Start Constructor // - -// constructor( -// protected hap: HAP, -// protected logs, -// protected api, -// protected accessory, -// protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], -// protected animationLoop -// ) { - -// this.setupMisc(); -// this.accessoryState = DEFAULT_ACCESSORY_STATE; -// // this.logs = logs; -// // this.controller = controller; -// this.hap = api.hap; -// this.api = api; -// // this.config = config; -// this.initializeCharacteristics(); -// this.fetchAndUpdateState(2); -// this.animationController = new AnimationController([]); -// } - -// //================================================= -// // End Constructor // - -// //================================================= -// // Start Setters // -// async setOn(value: CharacteristicValue) { -// if (this.animationController.isActive) this.animationController.clearAnimations(); - -// if (value) { -// const accessoryList = this.accessoriesList.filter(accessory => { -// // return accessory.accessoryState.isOn; -// return true; -// }); - -// const controllerList = [] -// for (const accessory of accessoryList) { -// controllerList.push(accessory.getController()); -// } - -// await this.animationController.animateAsynchronously(controllerList, this.animationLoop).catch(e => { }) -// } else { -// this.animationController.clearAnimations(); -// } - -// const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; -// this.processAccessoryCommand(accessoryCommand); -// } - -// setHue(value: CharacteristicValue) { - -// this.accessoryState.HSV.hue = value as number; -// this.colorCommandMode = HSV; -// const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; -// this.processAccessoryCommand(accessoryCommand); -// } - -// setSaturation(value: CharacteristicValue) { - -// this.accessoryState.HSV.saturation = value as number; -// const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; -// this.processAccessoryCommand(accessoryCommand); -// } - -// async setBrightness(value: CharacteristicValue) { - -// this.accessoryState.HSV.value = value as number; -// this.accessoryState.whiteBrightness = value as number; -// const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; -// this.processAccessoryCommand(accessoryCommand); -// } - -// // setColorTemperature(value: CharacteristicValue) { - -// // this.ColorCommandMode = CCT; -// // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; -// // this.processAccessoryCommand(accessoryCommand); -// // } - -// setConfiguredName(value: CharacteristicValue) { - -// const name: string = value.toString(); -// this.logs.warn('Renaming device to %o', name); -// this.accessory.context.displayName = name; -// console.log(this.accessory.context.displayName) -// this.api.updatePlatformAccessories([this.accessory]); -// } - -// identifyLight() { - -// this.flashEffect(); -// } - -// //================================================= -// // End Setters // - -// //================================================= -// // Start Getters // - -// getHue() { -// const { isOn, HSV: { hue, saturation } } = this.accessoryState; - -// // this.fetchAndUpdateState(2); -// return hue; - -// } - -// getBrightness() { -// const { isOn, HSV: { hue, saturation }, whiteBrightness: brightness } = this.accessoryState; - -// // this.fetchAndUpdateState(2); -// return brightness; -// } - -// /** -// ** @getOn -// * instantly retrieve the current on/off state stored in our object -// * next call this.getState() which will update all values asynchronously as they are ready -// */ -// async getOn() { -// const { isOn, HSV: { hue, saturation }, whiteBrightness: brightness } = this.accessoryState; - -// this.fetchAndUpdateState(2); -// return isOn; -// } - -// flashEffect() { -// // -// } //flashEffect - -// //================================================= -// // End LightEffects // - - -// protected async processAccessoryCommand(accessoryCommand: IAccessoryCommand) { - -// const ret = await this.prepareCommand(accessoryCommand).catch(e => { { } }); -// // console.log('return value: ', ret) -// } - -// protected async prepareCommand(accessoryCommand: IAccessoryCommand) { - -// this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); -// const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, accessoryCommand, this.accessoryState, DEFAULT_ACCESSORY_STATE); -// // console.log(accessoryCommand) -// // console.log(sanitizedAcessoryCommand) -// if (accessoryCommand.hasOwnProperty('isOn') && !(accessoryCommand.hasOwnProperty('HSV') || accessoryCommand.hasOwnProperty('brightness'))) { -// sanitizedAcessoryCommand.isPowerCommand = true; -// } -// // const completeResponse: ICompleteResponse = await this.sendCommand(sanitizedAcessoryCommand, { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }); -// // return completeResponse; - -// } - -// protected async sendCommand(accessoryCommand: IAccessoryCommand, commandOptions: ICommandOptions) { -// // const deviceCommand = this.accessoryCommandToDeviceCommand(accessoryCommand); - -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); - -// // let response; -// // // if (!accessoryCommand.isPowerCommand) response = await this.controller.setAllValues(deviceCommand, commandOptions); -// // // else response = await this.controller.setOn(deviceCommand.isOn); - -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); -// // return response; -// } - -// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { -// const { isOn, HSV, } = accessoryCommand; - -// const RGB = HSVtoRGB(HSV); - -// const deviceCommand: IDeviceCommand = { isOn, RGB, colorMask: 0xF0, CCT: { warmWhite: 0, coldWhite: 0 } }; -// return deviceCommand; -// } - -// protected async updateLocalState(requestLevel, deviceState) { - -// if (!deviceState) { -// // deviceState = await this..fetchState(); -// } -// this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); -// // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; -// const { HSV: { hue, saturation, value }, colorTemperature, whiteBrightness: brightness, isOn } = this.deviceStateToAccessoryState(deviceState); -// let accessoryState: IAccessoryState; -// if (deviceState) { -// switch (requestLevel) { -// case 0: -// // accessoryState = { HSV: { value }, isOn }; -// break; -// case 1: -// // accessoryState = { HSV: { hue, value }, isOn }; -// break; -// case 2: -// accessoryState = { HSV: { hue, saturation, value }, isOn, whiteBrightness: brightness }; -// break; -// case 3: -// accessoryState = { HSV: { hue, saturation, value }, isOn, whiteBrightness: brightness, colorTemperature }; -// break; -// } - -// this.accessoryState = accessoryState; -// // console.log(accessoryState) - - - -// this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); -// } - - -// } - -// updateHomekitState() { -// const { isOn, HSV: { hue, saturation }, whiteBrightness: brightness } = this.accessoryState; -// this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); -// this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); -// this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); -// this.service.updateCharacteristic(this.hap.Characteristic.Brightness, brightness); -// } - -// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - -// const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; -// //TODO - REPLACE HSV WITH HSV -// // eslint-disable-next-line prefer-const -// let { hue, saturation, value } = RGBtoHSV(RGB); -// let brightness = 0; - -// if (value > 0) { -// brightness = value; -// } -// // else if (isOn) { -// // brightness = clamp(Math.max(coldWhite, warmWhite) / 2.55, 0, 100); -// // if (warmWhite > coldWhite) { -// // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (coldWhite / 255)); -// // } else { -// // saturation = this.colorWhiteSimultaniousSaturationLevel - (this.colorWhiteSimultaniousSaturationLevel * (warmWhite / 255)); -// // } -// // } - -// const accessoryState: IAccessoryState = { HSV: { hue, saturation, value }, isOn, colorTemperature: 140, whiteBrightness: brightness }; -// return accessoryState; -// } - -// initializeCharacteristics() { - -// const cachedDeviceInformation = this.accessoryState; -// // if (cachedDeviceInformation) { -// // this.accessory.context.accessoryState = accessoryState; -// // } else { -// // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; -// // } -// // const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; - -// this.addAccessoryInformationCharacteristic(); - -// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); -// this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); - - -// this.addHueCharacteristic(); -// this.addSaturationCharacteristic(); -// this.addBrightnessCharacteristic(); -// this.addOnCharacteristic(); -// this.addConfiguredNameCharacteristic(); -// } - -// setupMisc() { - -// // const localAccessoryOptions = new Map(Object.entries(this.config?.individualAccessoryOptions)).get(this.accessory.context.displayName?? "unknown"); -// // const { colorOffSaturationLevel, colorWhiteSimultaniousSaturationLevel, logLevel } = Object.assign({}, this.config.globalAccessoryOptions, localAccessoryOptions); - - -// // this.colorWhiteSimultaniousSaturationLevel = colorWhiteSimultaniousSaturationLevel; -// // this.colorOffSaturationLevel = colorOffSaturationLevel; -// // this.logs = new Logs(this.hbLogger, logLevel ?? 3); - -// } - -// async fetchAndUpdateState(requestLevel) { -// try { -// this.readRequestLevel = requestLevel; -// await this.updateLocalState(this.readRequestLevel, null).catch(e => { }); -// this.updateHomekitState(); -// } catch (error) { -// // this.hbLogger.error(error); -// } -// } - - - -// addOnCharacteristic() { -// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); -// this.service.getCharacteristic(this.hap.Characteristic.On) -// .onSet(this.setOn.bind(this)) -// .onGet(this.getOn.bind(this)); -// } - -// addHueCharacteristic() { -// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); -// this.service.getCharacteristic(this.hap.Characteristic.Hue) -// .onSet(this.setHue.bind(this)) -// .onGet(this.getHue.bind(this)); -// } - -// addSaturationCharacteristic() { -// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); -// this.service.getCharacteristic(this.hap.Characteristic.Saturation) -// .onSet(this.setSaturation.bind(this)); -// // .onGet(this.CHANGE_ME.bind(this)); - -// } - -// removeSaturationCharacteristic() { -// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); -// this.service.getCharacteristic(this.hap.Characteristic.Saturation) -// .removeAllListeners(this.hap.CharacteristicEventTypes.SET) -// .removeAllListeners(this.hap.CharacteristicEventTypes.GET); - -// } - -// addBrightnessCharacteristic() { -// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); -// this.service.getCharacteristic(this.hap.Characteristic.Brightness) -// .onSet(this.setBrightness.bind(this)) -// .onGet(this.getBrightness.bind(this)); -// } - -// // addColorTemperatureCharacteristic() { -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); -// // this.service.getCharacteristic(this.hap.Characteristic.ColorTemperature) -// // .onSet(this.setColorTemperature.bind(this)) -// // .onGet(this.getColorTemperature.bind(this)); - -// // if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { -// // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); -// // this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service); -// // this.accessory.configureController(this.adaptiveLightingService); -// // } -// // } - -// addAccessoryInformationCharacteristic() { - -// // const { -// // protoDevice: { uniqueId, modelNumber }, -// // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, -// // } = this.accessory.context.cachedDeviceInformation; -// // set accessory information -// this.accessory.getService(this.hap.Service.AccessoryInformation)! -// .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic ') -// // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) -// // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) -// // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') -// // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') -// .getCharacteristic(this.hap.Characteristic.Identify) -// .removeAllListeners(this.hap.CharacteristicEventTypes.SET) -// .removeAllListeners(this.hap.CharacteristicEventTypes.GET) -// .on(this.hap.CharacteristicEventTypes.SET, this.identifyLight.bind(this)); // SET - bind to the 'Identify` method below - - -// this.accessory.getService(this.hap.Service.AccessoryInformation)! -// .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); -// } - -// addConfiguredNameCharacteristic() { -// if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { -// this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) -// .onSet(this.setConfiguredName.bind(this)); -// } else { -// this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) -// .onSet(this.setConfiguredName.bind(this)); -// } -// this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); - -// } - - -// /* -// // Add the garage door service if it doesn't already exist -// this.service = -// this.accessory.getService(this.hapServ.GarageDoorOpener) || -// this.accessory.addService(this.hapServ.GarageDoorOpener) - -// // Add some extra Eve characteristics -// if (!this.service.testCharacteristic(this.eveChar.LastActivation)) { -// this.service.addCharacteristic(this.eveChar.LastActivation) -// } -// if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) { -// this.service.addCharacteristic(this.eveChar.ResetTotal) -// } -// if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) { -// this.service.addCharacteristic(this.eveChar.TimesOpened) -// } - -// // Add the set handler to the garage door target state characteristic -// this.service -// .getCharacteristic(this.hapChar.TargetDoorState) -// .onSet(value => this.internalTargetUpdate(value)) -// this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value -// this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value - -// // Add the set handler to the garage door reset total characteristic -// this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { -// this.service.updateCharacteristic(this.eveChar.TimesOpened, 0) -// }) - -// // Update the obstruction detected to false on plugin load -// this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false) - -// // Pass the accessory to Fakegato to set up with Eve -// this.accessory.eveService = new platform.eveService('door', this.accessory, { -// log: platform.config.debugFakegato ? this.log : () => {} -// }) -// */ - - - -// } // ZackneticMagichomePlatformAccessory class -// // import type { API, CharacteristicEventTypes, CharacteristicValue, HAP, Service } from "homebridge"; -// // import { AnimationController, BaseController } from "magichome-platform"; -// // import { Logs } from "./logs"; -// // import { AnimationAccessory, DefaultAccessoryCommand, IAccessoryCommand, IAccessoryState } from "./misc/types"; -// // import { HomebridgeMagichomeDynamicPlatformAccessory } from "./platformAccessory"; - -// // export class HomebridgeAnimationAccessory { - -// // protected service: Service; -// // protected accessoryState: IAccessoryState = DefaultAccessoryCommand; -// // protected accessory: AnimationAccessory; -// // protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[]; -// // protected activeControllerList: BaseController[]; -// // hap: HAP; -// // logs: Logs; -// // api: API; -// // constructor( -// // hap: HAP, -// // logs: Logs, -// // api: API, -// // accessory: AnimationAccessory, -// // // accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[] - -// // ) { -// // this.accessory = accessory; -// // const animationController: AnimationController = new AnimationController([]); -// // // this.accessoriesList = accessoriesList; -// // this.hap = hap; -// // this.logs = logs; -// // this.api = api; -// // } - -// // // Start Setters // -// // async setOn(value: CharacteristicValue) { -// // const accessoryCommand: IAccessoryCommand = { isOn: value as boolean }; -// // // this.processAccessoryCommand(accessoryCommand); -// // } - -// // setHue(value: CharacteristicValue) { - -// // this.accessoryState.HSV.hue = value as number; -// // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: value as number, saturation: null, value: null } }; -// // // this.processAccessoryCommand(accessoryCommand); -// // } - -// // setSaturation(value: CharacteristicValue) { - -// // this.accessoryState.HSV.saturation = value as number; -// // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: value as number, value: null } }; -// // // this.processAccessoryCommand(accessoryCommand); -// // } - -// // async setBrightness(value: CharacteristicValue) { - -// // this.accessoryState.HSV.value = value as number; -// // this.accessoryState.brightness = value as number; -// // const accessoryCommand: IAccessoryCommand = { isOn: true, HSV: { hue: null, saturation: null, value: value as number } }; -// // // this.processAccessoryCommand(accessoryCommand); -// // } - -// // setConfiguredName(value: CharacteristicValue) { - -// // const name: string = value.toString(); -// // this.logs.warn('Renaming device to %o', name); -// // this.accessory.context.animationLoop.name = name; -// // this.api.updatePlatformAccessories([this.accessory]); -// // } - - -// // getHue() { -// // const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; - -// // // this.fetchAndUpdateState(2); -// // return hue; - -// // } - -// // getBrightness() { -// // const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; - -// // // this.fetchAndUpdateState(2); -// // return brightness; -// // } - -// // /** -// // ** @getOn -// // * instantly retrieve the current on/off state stored in our object -// // * next call this.getState() which will update all values asynchronously as they are ready -// // */ -// // async getOn() { -// // const { isOn, HSV: { hue, saturation }, brightness } = this.accessoryState; - -// // // this.fetchAndUpdateState(2); -// // return isOn; -// // } - -// // addOnCharacteristic() { -// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); -// // this.service.getCharacteristic(this.hap.Characteristic.On) -// // .onSet(this.setOn.bind(this)) -// // .onGet(this.getOn.bind(this)); -// // } - -// // addHueCharacteristic() { -// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); -// // this.service.getCharacteristic(this.hap.Characteristic.Hue) -// // .onSet(this.setHue.bind(this)) -// // .onGet(this.getHue.bind(this)); -// // } - -// // addSaturationCharacteristic() { -// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); -// // this.service.getCharacteristic(this.hap.Characteristic.Saturation) -// // .onSet(this.setSaturation.bind(this)); -// // // .onGet(this.CHANGE_ME.bind(this)); - -// // } - -// // addBrightnessCharacteristic() { -// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); -// // this.service.getCharacteristic(this.hap.Characteristic.Brightness) -// // .onSet(this.setBrightness.bind(this)) -// // .onGet(this.getBrightness.bind(this)); -// // } - -// // addAccessoryInformationCharacteristic() { - -// // // const { -// // // protoDevice: { uniqueId, modelNumber }, -// // // deviceState: { controllerFirmwareVersion, controllerHardwareVersion }, -// // // } = this.accessory.context.cachedDeviceInformation; -// // // set accessory information -// // this.accessory.getService(this.hap.Service.AccessoryInformation)! -// // // .removeAllListeners(CharacteristicEventTypes.SET) -// // // .removeAllListeners(CharacteristicEventTypes.GET) -// // .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') -// // // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) -// // // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) -// // // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') -// // // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') - - -// // this.accessory.getService(this.hap.Service.AccessoryInformation)! -// // .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); -// // } - -// // addConfiguredNameCharacteristic() { -// // if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { -// // this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) -// // .onSet(this.setConfiguredName.bind(this)); -// // } else { -// // this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) -// // .onSet(this.setConfiguredName.bind(this)); -// // } -// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); - -// // } - -// // initializeCharacteristics() { - -// // // const cachedDeviceInformation = this.controller.getCachedDeviceInformation(); -// // // if (cachedDeviceInformation) { -// // // this.accessory.context.accessoryState = accessoryState; -// // // } else { -// // // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; -// // // } -// // // const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; - -// // this.addAccessoryInformationCharacteristic(); - -// // // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); -// // this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); -// // this.addHueCharacteristic(); -// // this.addSaturationCharacteristic(); -// // this.addBrightnessCharacteristic(); -// // this.addOnCharacteristic(); -// // this.addConfiguredNameCharacteristic(); -// // } -// // } +import type { Service, CharacteristicValue, HAP } from 'homebridge'; + +import { AnimationAccessory, DEFAULT_ACCESSORY_STATE, IAccessoryState } from './misc/types'; +// import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; +import { BaseController, AnimationController } from 'magichome-platform'; +import { Logs } from './logs'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; + +const LISTENING_TIMEOUT_MS: number = 300; + +export class HomebridgeAnimationAccessory { + + protected service: Service; + protected service2: Service; + + protected accessoryState: IAccessoryState; + protected animationController: AnimationController; + protected isRecoding = false; + protected numToggles = 0; + listeningTimeout: NodeJS.Timeout; + listenCount: number = 0; + countTimeout: NodeJS.Timeout; + isListening: boolean = false; + isTurnedOn: number = 0; + //================================================= + // Start Constructor // + + constructor( + protected hap: HAP, + protected logs, + protected api, + protected accessory: AnimationAccessory, + protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], + protected animationLoop + ) { + this.accessoryState = DEFAULT_ACCESSORY_STATE; + // this.logs = logs; + // this.controller = controller; + this.hap = api.hap; + this.api = api; + // this.config = config; + this.initializeCharacteristics(); + this.animationController = new AnimationController(); + } + + //================================================= + // End Constructor // + + //================================================= + // Start Setters // + async setOn(value: CharacteristicValue) { + this.accessoryState.isOn = value as boolean; + if (this.animationController.isActive || !value) this.animationController.clearAnimations(); + clearTimeout(this.listeningTimeout); + this.listenCount++; + if (this.listenCount == 2) { + this.logs.info("Listening for new devices.") + this.isListening = true; + // this.service2.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, true); + } else if (this.listenCount == 3) { + this.listeningTimeout = setTimeout(async () => { + this.listenCount = 0; + this.isListening = false; + + this.logs.info("Assigning new devices.") + const filteredAccessories = this.accessoriesList.filter(accessory => { + return accessory.isReadyToAnimate(); + }); + for (const accessory of filteredAccessories) { + if(!this.accessory.context.activeControllerList)this.accessory.context.activeControllerList = []; + this.accessory.context.activeControllerList.push(accessory.getController()) + } + }, LISTENING_TIMEOUT_MS); + } else if (this.listenCount >= 5) { + this.isListening = false; + this.listenCount = 0; + this.accessory.context.activeControllerList = []; + } else { + this.listeningTimeout = setTimeout(async () => { + this.listenCount = 0; + if (value) { + + await this.animationController.animateAsynchronously(this.accessory.context.activeControllerList, this.animationLoop).catch(e => { }) + } + }, LISTENING_TIMEOUT_MS); + } + } + + /** + * Handle requests to get the current value of the "Status Low Battery" characteristic + */ + + setConfiguredName(value: CharacteristicValue) { + + const name: string = value.toString(); + this.logs.warn('Renaming device to %o', name); + this.accessory.context.displayName = name; + this.api.updatePlatformAccessories([this.accessory]); + } + + //================================================= + // End Setters // + + //================================================= + // Start Getters // + + async getOn() { + const { isOn } = this.accessoryState; + return isOn; + } + + + //================================================= + // End LightEffects // + + initializeCharacteristics() { + this.addAccessoryInformationCharacteristic(); + + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding "Switch" service to accessory.`); + this.service = this.accessory.getService(this.hap.Service.Outlet) ?? this.accessory.addService(this.hap.Service.Outlet); + this.addOnCharacteristic(); + this.addConfiguredNameCharacteristic(); + } + + addOnCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.On) + .onSet(this.setOn.bind(this)) + .onGet(this.getOn.bind(this)); + } + + addAccessoryInformationCharacteristic() { + + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') + // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) + // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) + // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') + // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') + .removeAllListeners(this.hap.CharacteristicEventTypes.SET) + .removeAllListeners(this.hap.CharacteristicEventTypes.GET); + + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); + } + + addConfiguredNameCharacteristic() { + if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { + this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } else { + this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + + } +} diff --git a/src/misc/types.ts b/src/misc/types.ts index 29561f9..1f8618b 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -34,6 +34,8 @@ export interface AnimationAccessory extends PlatformAccessory { export interface IAnimationContext { animationLoop: IAnimationLoop; + activeControllerList: BaseController[]; + displayName?: string; } export interface IAccessoryContext { @@ -93,13 +95,15 @@ export interface IConfigOptions { colorWhiteSimultaniousSaturationLevel?: number, } -/*----------------------[DEFAULT VALIES]----------------------*/ +/*----------------------[DEFAULT VALIUES]----------------------*/ export const COLOR_COMMAND_MODES = { CCT: 'CCT', HSV: 'HSV', }; - +export const DEFAULT_ANIMATION_STATE = { + isOn: false, +}; export const DEFAULT_ACCESSORY_STATE: IAccessoryState = { isOn: true, HSV: { @@ -108,7 +112,7 @@ export const DEFAULT_ACCESSORY_STATE: IAccessoryState = { value: 100, }, TB: { - temperature: 0, + temperature: 140, brightness: 100 } }; @@ -122,7 +126,7 @@ export const DEFAULT_ACCESSORY_COMMAND: IAccessoryCommand = { value: 0, }, TB: { - temperature: 0, + temperature: 140, brightness: 0 } }; \ No newline at end of file diff --git a/src/misc/utils.ts b/src/misc/utils.ts index b125f08..ba965a3 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -158,8 +158,6 @@ export function TBtoCCT(TB: IColorTB): IColorCCT { let warmWhite = 0, coldWhite = 0; const { temperature, brightness } = TB; - console.log(`TEMP: ${temperature}, BRIGHT: ${brightness}`) - if (temperature <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue multiplier = ((temperature / 90)); coldWhite = Math.round((255 * multiplier)); diff --git a/src/platform.ts b/src/platform.ts index 88ecbd5..b96b682 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -14,6 +14,7 @@ import { ControllerGenerator } from 'magichome-platform'; // import { AnimationGenerator } from './AnimationGenerator' import { AnimationAccessory, MagicHomeAccessory } from './misc/types'; import { AccessoryGenerator } from './AccessoryGenerator'; +import { AnimationGenerator } from './AnimationGenerator'; import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; /** */ @@ -82,7 +83,9 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); this.log.info(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); } else { - const homebridgeUUID = accessory.context.animationLoop.name; + const homebridgeUUID = this.hap.uuid.generate(accessory.context.animationLoop.name); + + // const homebridgeUUID = accessory.context.animationLoop; this.animationsFromDiskMap.set(homebridgeUUID, accessory); } @@ -106,8 +109,8 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); const activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] = await accesssoryGenerator.discoverDevices(); - // const animationGenerator = new AnimationGenerator(this.api, this.log, this.hbLogger, this.config, this.animationsFromDiskMap, activeAccessories); - // animationGenerator.generateActiveAccessories(); + const animationGenerator = new AnimationGenerator(this.api, this.log, this.hbLogger, this.config, this.animationsFromDiskMap, activeAccessories); + animationGenerator.generateActiveAccessories(); // this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); } diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index f262e0d..3be6d78 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -3,16 +3,15 @@ import type { CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, } from 'homebridge'; - import { temperatureToCCT, clamp, TBtoCCT, HSVtoRGB, RGBtoHSV, CCTtoTB } from './misc/utils'; -import { DEFAULT_ACCESSORY_COMMAND, DEFAULT_ACCESSORY_STATE, IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB, IConfigOptions, IPartialAccessoryCommand, MagicHomeAccessory } from './misc/types'; +import { AnimationAccessory, DEFAULT_ACCESSORY_COMMAND, DEFAULT_ACCESSORY_STATE, IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB, IConfigOptions, IPartialAccessoryCommand, MagicHomeAccessory } from './misc/types'; // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE, COLOR_MASKS } from 'magichome-platform'; import { Logs } from './logs'; const WHITE_MODE = 'WHITE_MODE'; const COLOR_MODE = 'COLOR_MODE'; - +const RECENT_CONTROLLED_TIMEOUT_MS = 30 * 1000; /** * Platform Accessory * An instance of this class is created for each accessory your platform registers @@ -39,12 +38,19 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected deviceReadStatus = 'ready'; protected readRequestLevel = 0; + protected recentlyControlled: boolean = false; + protected currentlyAnimating: boolean = false; + protected currentAnimator: AnimationAccessory = null; + protected queue; protected slowQueueRetry = false; protected lastValue: number; lastHue: number; lastBrightness: number; waitingSendoff: boolean; + resistOff: boolean; + brightnessTimeout: NodeJS.Timeout; + powerTimeout: NodeJS.Timeout; //================================================= // Start Constructor // @@ -75,19 +81,18 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // Start Setters // setOn(value: CharacteristicValue) { - const partialAccessoryCommand: IPartialAccessoryCommand = { isOn: value as boolean, isPowerCommand: true }; - this.processAccessoryCommand(partialAccessoryCommand); + this.powerTimeout = setTimeout(() => { + if (!this.resistOff) { + const partialAccessoryCommand: IPartialAccessoryCommand = { isOn: value as boolean, isPowerCommand: true }; + this.processAccessoryCommand(partialAccessoryCommand); + } + }, 100); } setHue(value: CharacteristicValue) { - let partialAccessoryCommand: IPartialAccessoryCommand; - if (this.colorCommandMode == COLOR_MODE) { - this.accessoryState.HSV.hue = value as number; - partialAccessoryCommand = { HSV: { hue: value as number } }; - } else { - this.accessoryState.TB.temperature = value as number; - partialAccessoryCommand = { TB: { temperature: value as number } }; - } + this.accessoryState.HSV.hue = value as number; + const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { hue: value as number } }; + this.processAccessoryCommand(partialAccessoryCommand); } @@ -99,21 +104,19 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } setBrightness(value: CharacteristicValue) { - - let partialAccessoryCommand: IPartialAccessoryCommand; - if (this.colorCommandMode == COLOR_MODE) { - this.accessoryState.HSV.value = value as number; - partialAccessoryCommand = { HSV: { value: value as number } }; - } else { - this.accessoryState.TB.brightness = value as number; - partialAccessoryCommand = { TB: { brightness: value as number } }; - } - + clearTimeout(this.brightnessTimeout) + clearTimeout(this.powerTimeout) + this.resistOff = true; + this.brightnessTimeout = setTimeout(() => { + this.resistOff = false; + }, 100); + + this.accessoryState.HSV.value = value as number; + const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { value: value as number } }; this.processAccessoryCommand(partialAccessoryCommand); } // setColorTemperature(value: CharacteristicValue) { - // this.ColorCommandMode = CCT; // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; // this.processAccessoryCommand(accessoryCommand); @@ -122,14 +125,12 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { setConfiguredName(value: CharacteristicValue) { const name: string = value.toString(); - this.logs.warn('Renaming device to %o', name); + this.logs.warn(`Renaming device to ${name}`,); this.accessory.context.displayName = name; - console.log(this.accessory.context.displayName) this.api.updatePlatformAccessories([this.accessory]); } identifyLight() { - this.flashEffect(); } @@ -141,14 +142,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getHue() { const { HSV: { hue }, TB: { temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - - let _hue; - if (this.colorCommandMode == COLOR_MODE) _hue = hue; - else _hue = temperature; - this.fetchAndUpdateState(2); - return _hue; - + return hue; } // getColorTemperature() { @@ -161,12 +156,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { getBrightness() { const { HSV: { value }, TB: { brightness } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - let _brightness; - if (this.colorCommandMode == COLOR_MODE) _brightness = value; - else _brightness = brightness; - this.fetchAndUpdateState(2); - return _brightness; + return value; } /** @@ -190,34 +181,26 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //TODO, Severe! Bundle commands so that close consecutive changes in hue, sat, and brightness aren't sent as separate commands protected processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { + try { - overwriteDeep(this.newAccessoryCommand, partialAccessoryCommand); - if (!this.waitingSendoff) { - this.waitingSendoff = true; - - return new Promise((resolve, reject) => { - setTimeout(async () => { - - - const sanitizedAcessoryCommand = this.completeAccessoryCommand(this.newAccessoryCommand); - this.newAccessoryCommand = {}; - const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); - - const completeResponse: ICompleteResponse | void = await this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand).catch(e => { }); - resolve(completeResponse); - return; - }, 20); - }) + this.setRecentlyControlled(); + this.waitingSendoff = false; + const sanitizedAcessoryCommand = this.completeAccessoryCommand(partialAccessoryCommand); + if (partialAccessoryCommand.isPowerCommand) { + this.controller.setOn(sanitizedAcessoryCommand.isOn); + } else { + const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); + this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand); + } + } catch (error) { + console.log('processAccessoryCommand: ', error) } - - } protected completeAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand): IAccessoryCommand { this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, partialAccessoryCommand, this.accessoryState); - // console.log(partialAccessoryCommand, this.accessoryState) if (partialAccessoryCommand.hasOwnProperty('isOn') && !(partialAccessoryCommand.hasOwnProperty('HSV') || partialAccessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; } @@ -228,56 +211,49 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { let { isOn, HSV: { hue, saturation, value }, TB } = accessoryCommand; const { temperature, brightness } = TB; + if (Math.max(brightness, value) > 0) isOn = true; - const commandOptions: ICommandOptions = { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; + const commandOptions: ICommandOptions = { colorAssist: true, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; let red, green, blue, warmWhite, coldWhite, colorMask = null; + colorMask = COLOR_MASKS.BOTH if (saturation < 95) { - this.colorCommandMode = WHITE_MODE; - ({ warmWhite, coldWhite } = TBtoCCT(TB)); - - ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value })); + ({ warmWhite, coldWhite } = TBtoCCT({ temperature: hue, brightness: value })); + ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value: this.lastValue })); if (saturation < 5) { red = 0, green = 0, blue = 0; colorMask = COLOR_MASKS.WHITE } } else { - colorMask = COLOR_MASKS.COLOR - this.colorCommandMode = COLOR_MODE; + colorMask = COLOR_MASKS.COLOR; + this.lastValue = value; ({ red, green, blue } = HSVtoRGB({ hue, saturation, value })); warmWhite = 0; coldWhite = 0; } - console.log(this.colorCommandMode) const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, colorMask, CCT: { warmWhite, coldWhite } }; - console.log(deviceCommand) return { deviceCommand, commandOptions }; } - protected async sendCommand(deviceCommand: IDeviceCommand, commandOptions: ICommandOptions, accessoryCommand: IAccessoryCommand): Promise { - + protected sendCommand(deviceCommand: IDeviceCommand, commandOptions: ICommandOptions, accessoryCommand) { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); - - let response; - if (!accessoryCommand.isPowerCommand) response = await this.controller.setAllValues(deviceCommand, commandOptions).catch(e => { }); - else response = await this.controller.setOn(deviceCommand.isOn).catch(e => { }); - - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`, response); - return response; + try { + this.controller.setAllValues(deviceCommand, commandOptions).catch(e => {this.logs.warn(e)}) + } catch (error) { + console.log(error) + } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`); } protected async updateLocalState(requestLevel, deviceState) { - if (!deviceState) deviceState = await this.controller.fetchState().catch(e => { - console.log('updateLocalState Error: ', e) - return; - }); + if (!deviceState) deviceState = await this.controller.fetchState().then(res => res).catch(e => { this.logs.warn(e) }); this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; @@ -298,35 +274,19 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { accessoryState = { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } }; break; } - this.accessoryState = accessoryState; // console.log(accessoryState) - - - this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); } - - } updateHomekitState() { - const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - - let _hue, _brightness - - if (this.colorCommandMode = COLOR_MODE) { - _hue = hue; - _brightness = value; - } else { - _hue = temperature; - _brightness = brightness; - } + let { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); - // this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); - this.service.updateCharacteristic(this.hap.Characteristic.Hue, _hue); - this.service.updateCharacteristic(this.hap.Characteristic.Brightness, _brightness); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSV.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); + this.service.updateCharacteristic(this.hap.Characteristic.Brightness, value); } deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { @@ -334,9 +294,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { let { RGB, CCT, isOn } = deviceState; const HSV: IColorHSV = RGBtoHSV(RGB); const TB: IColorTB = CCTtoTB(CCT); - HSV.saturation = clamp(HSV.saturation - TB.brightness, 0, 100) - // if(HSV.saturation < 95) this.colorCommandMode = WHITE_MODE - console.log(RGB, CCT, HSV, TB) const accessoryState: IAccessoryState = { HSV, TB, isOn }; return accessoryState; } @@ -344,11 +301,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { initializeCharacteristics() { const cachedDeviceInformation = this.controller.getCachedDeviceInformation(); - // if (cachedDeviceInformation) { - // this.accessory.context.accessoryState = accessoryState; - // } else { - // cachedDeviceInformation = this.accessory.context.cachedDeviceInformation; - // } const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; this.addAccessoryInformationCharacteristic(); @@ -464,6 +416,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.accessory.getService(this.hap.Service.AccessoryInformation)! .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); + } addConfiguredNameCharacteristic() { @@ -477,44 +430,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); } + setRecentlyControlled() { + this.recentlyControlled = true; + setTimeout(() => { + this.recentlyControlled = false; + }, RECENT_CONTROLLED_TIMEOUT_MS); + } + + public isReadyToAnimate() { + return this.recentlyControlled; + } + + + - /* - // Add the garage door service if it doesn't already exist - this.service = - this.accessory.getService(this.hapServ.GarageDoorOpener) || - this.accessory.addService(this.hapServ.GarageDoorOpener) - - // Add some extra Eve characteristics - if (!this.service.testCharacteristic(this.eveChar.LastActivation)) { - this.service.addCharacteristic(this.eveChar.LastActivation) - } - if (!this.service.testCharacteristic(this.eveChar.ResetTotal)) { - this.service.addCharacteristic(this.eveChar.ResetTotal) - } - if (!this.service.testCharacteristic(this.eveChar.TimesOpened)) { - this.service.addCharacteristic(this.eveChar.TimesOpened) - } - - // Add the set handler to the garage door target state characteristic - this.service - .getCharacteristic(this.hapChar.TargetDoorState) - .onSet(value => this.internalTargetUpdate(value)) - this.cacheTarget = this.service.getCharacteristic(this.hapChar.TargetDoorState).value - this.cacheCurrent = this.service.getCharacteristic(this.hapChar.CurrentDoorState).value - - // Add the set handler to the garage door reset total characteristic - this.service.getCharacteristic(this.eveChar.ResetTotal).onSet(value => { - this.service.updateCharacteristic(this.eveChar.TimesOpened, 0) - }) - - // Update the obstruction detected to false on plugin load - this.service.updateCharacteristic(this.hapChar.ObstructionDetected, false) - - // Pass the accessory to Fakegato to set up with Eve - this.accessory.eveService = new platform.eveService('door', this.accessory, { - log: platform.config.debugFakegato ? this.log : () => {} - }) - */ } // ZackneticMagichomePlatformAccessory class From 57520b3e6e4ea36697d68962924f28302a181ecc Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Tue, 27 Dec 2022 23:28:53 -0500 Subject: [PATCH 38/42] logic update for multiple classes --- .eslintrc | 34 - .gitignore | 246 +- .npmignore | 272 +- LICENSE | 350 +- README.md | 166 +- config.schema.json | 278 +- nodemon.json | 16 +- package-lock.json | 13582 +++++++++++++++---------------- package.json | 166 +- src/AccessoryGenerator.ts | 12 +- src/AnimationGenerator.ts | 246 +- src/accessories/CCTStrip.ts | 76 +- src/accessories/DimmerStrip.ts | 60 +- src/accessories/GRBStrip.ts | 104 +- src/accessories/RGBStrip.ts | 66 +- src/accessories/RGBWBulb.ts | 152 +- src/accessories/RGBWStrip.ts | 170 +- src/accessories/RGBWWBulb.ts | 188 +- src/accessories/RGBWWStrip.ts | 220 +- src/accessories/Switch.ts | 34 +- src/animationAccessory.ts | 316 +- src/index.ts | 36 +- src/logs.ts | 89 +- src/misc/types.ts | 262 +- src/misc/utils.ts | 896 +- src/platform.ts | 246 +- src/platformAccessory.ts | 441 +- src/settings.ts | 18 +- tsconfig.json | 54 +- 29 files changed, 9282 insertions(+), 9514 deletions(-) delete mode 100644 .eslintrc diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index aa29d6a..0000000 --- a/.eslintrc +++ /dev/null @@ -1,34 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended" // uses the recommended rules from the @typescript-eslint/eslint-plugin - ], - "parserOptions": { - "ecmaVersion": 2018, - "sourceType": "module" - }, - "ignorePatterns": [ - "dist" - ], - "rules": { - "quotes": ["warn", "single"], - //"indent": ["warn", 2, { "SwitchCase": 1 }], - "linebreak-style": ["error", "unix"], - "semi": ["warn", "always"], - "comma-dangle": ["warn", "always-multiline"], - "dot-notation": "warn", - "curly": ["warn", "all"], - "brace-style": ["warn"], - "prefer-arrow-callback": ["warn"], - "no-console": ["warn"], // use the provided Homebridge log method instead - "lines-between-class-members": ["warn", "always", {"exceptAfterSingleLine": true}], - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/explicit-module-boundary-types": "off" - - } -} diff --git a/.gitignore b/.gitignore index 5f7814b..9658dcc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,123 +1,123 @@ -# Ignore compiled code -dist - -# ------------- Defaults ------------- # - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 - -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.pnp.* - -.homebridge-dev/* -!.homebridge-dev/config.json +# Ignore compiled code +dist + +# ------------- Defaults ------------- # + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.pnp.* + +.homebridge-dev/* +!.homebridge-dev/config.json diff --git a/.npmignore b/.npmignore index 82a1de5..b033388 100644 --- a/.npmignore +++ b/.npmignore @@ -1,136 +1,136 @@ -# Ignore source code -src - -# ------------- Defaults ------------- # - -# eslint -.eslintrc - -# typescript -tsconfig.json - -# vscode -.vscode - -# nodemon -nodemon.json - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 - -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.pnp.* - -.github/ -.homebridge-dev/ -test/ +# Ignore source code +src + +# ------------- Defaults ------------- # + +# eslint +.eslintrc + +# typescript +tsconfig.json + +# vscode +.vscode + +# nodemon +nodemon.json + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.pnp.* + +.github/ +.homebridge-dev/ +test/ diff --git a/LICENSE b/LICENSE index 2bb9ad2..21254fc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,176 +1,176 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.md b/README.md index 6f03d59..d132564 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,83 @@ - -

- - - -

- - -# Homebridge MagicHome Dynamic Platform -[![Sponsor](https://img.shields.io/badge/Sponsor-GitHub-%23181717?style=for-the-badge&logo=GitHub)](https://github.com/sponsors/Zacknetic) -[![Donate](https://img.shields.io/badge/Donate-PayPal-%2300457C?style=for-the-badge&logo=PayPal)](https://www.paypal.com/paypalme/zacharyavino) -[![Discord](https://img.shields.io/badge/Chat-Discord-%237289DA?style=for-the-badge&logo=Discord)](https://discord.gg/c8xpmZSNZC) - -### Join the [Official MagicHome Discord Channel](https://discord.gg/c8xpmZSNZC) for tech support and to chat with other MagicHome users - -## About - -A Homebridge plugin for a range of Magic Home Wi-Fi lights and LED controllers. - -## Installation - -First, install the plugin globally. - -```` -npm install -g homebridge-magichome-dynamic-platform -```` - -## Use - -* This plugin automatically detects MagicHome bulbs and controllers just like the Magichome app, and it should do so when you first run Homebridge. No more setting individual IP addresses per device. - -* If a device has changed its IP Address, such as after a power outage, this plugin will update that device with the new IP on the next restart. Maintaining the device's associated timers, scenes, etc. - -* If you'd like to remove an individual device, add the word 'delete' to any part of its name in Homekit and restart homebridge. This can be useful if you are intentionally taking a device offline or if you would simply like to reset it. Keep in mind, if it is still turned on during the homebridge restart, it will be detected and added again. - -## User Interface - -When the retical moves closer to the center of the color wheel, the saturation % drops. Once the retical passes the threshold (default 50%) it will switch to white mode or color and white mode depending on the device and config settings. See below for more details. - -* **RGBWW 5 Channel LED Strip Controller (RGB and Two Whites)** In the color wheel, move the retical from cyan to red. This will transition the LEDs in this pattern: -```Color-Only>Color and Cold-White>Cold-White Only>Cold-White and Warm-White>Warm-White Only>Color and Warm-White>Color-Only``` - -* **RGBWW 5 Channel LED Lightbulb (RGB and Two Whites)** In the color wheel, move the retical from cyan to red. This will transition the LEDs in this pattern: -```Color-OnlyCold-White Only>Cold-White and Warm-White>Warm-White Only>Color-Only``` - -* **RGBWW 4 Channel LED Strip Controller (RGB and One White)** In the color wheel, move the retical from cyan to red. This will transition the LEDs in this pattern: -```Color-Only>Color and White>White Only>Color and White>Color-Only``` - -* **RGBW 4 Channel LED Lightbulb (RGB and One White)** In the color wheel, move the retical from cyan to red. This will transition the LEDs in this pattern: -```Color-Only>White-Only>Color-Only``` - -* **RGB 3 Channel (RGB Only)** Normal RGB functionality. - -## Configuration - -Please setup your config in Config UI X under ```Plugins>Homebridge MagicHome Dynamic Platform>Settings.``` -However the default settings should suffice. Please read below to learn more about the settings before changing anything. - -### Settings - -#### Pruning - -* `pruneMissingCachedAccessories` - **true** / **false** "Prune" or remove accessories once they have been missing for n restarts. Associated names, timers, and scenes will be lost for those accessories. - -* `restartsBeforeMissingAccessoriesPruned` - ***number*** The number of homebridge restarts that an accessory can be not seen before being pruned. Will not occur if `pruneMissingCachedAccessories` is set to false. - -* `pruneAllAccessoriesNextRestart` - **true** / **false** "Prune" or remove all accessories next restart. Use this if you would like to remove all your magichome accessories next restart. Be sure to set to false after you restart otherwise the cached accessories and associated names, timers, and scenes will be lost. - -#### White Effects - -* `simultaniousDevicesColorWhite` - **true** / **false** Allow simultanious color and white LEDs on compatible devices. - -* `colorWhiteThreshold` - **number** The saturation threshold from color-only to white-only for non-simultanious devices. - -* `colorWhiteThresholdSimultaniousDevices` - **number** The saturation threshold from color-only to color and white for simulanious devices. - -* `colorOffThresholdSimultaniousDevices` - **number** The saturation threshold from color and white to white only for simultanious devices. - -#### Device Management - -* `blacklistOrWhitelist` - **blacklist** / **whitelist** Whether the listed Unique IDs are blacklisted or whitelisted. - -* `blacklistedUniqueIDs` - **Alphanumeric** Unique IDs of devices you wish this plugin to ignore/delete. Can be found in the Magichome app under "MAC Address" or in the logs under "Unique ID". **i.e. 6001940EDC1F** + +

+ + + +

+ + +# Homebridge MagicHome Dynamic Platform +[![Sponsor](https://img.shields.io/badge/Sponsor-GitHub-%23181717?style=for-the-badge&logo=GitHub)](https://github.com/sponsors/Zacknetic) +[![Donate](https://img.shields.io/badge/Donate-PayPal-%2300457C?style=for-the-badge&logo=PayPal)](https://www.paypal.com/paypalme/zacharyavino) +[![Discord](https://img.shields.io/badge/Chat-Discord-%237289DA?style=for-the-badge&logo=Discord)](https://discord.gg/c8xpmZSNZC) + +### Join the [Official MagicHome Discord Channel](https://discord.gg/c8xpmZSNZC) for tech support and to chat with other MagicHome users + +## About + +A Homebridge plugin for a range of Magic Home Wi-Fi lights and LED controllers. + +## Installation + +First, install the plugin globally. + +```` +npm install -g homebridge-magichome-dynamic-platform +```` + +## Use + +* This plugin automatically detects MagicHome bulbs and controllers just like the Magichome app, and it should do so when you first run Homebridge. No more setting individual IP addresses per device. + +* If a device has changed its IP Address, such as after a power outage, this plugin will update that device with the new IP on the next restart. Maintaining the device's associated timers, scenes, etc. + +* If you'd like to remove an individual device, add the word 'delete' to any part of its name in Homekit and restart homebridge. This can be useful if you are intentionally taking a device offline or if you would simply like to reset it. Keep in mind, if it is still turned on during the homebridge restart, it will be detected and added again. + +## User Interface + +When the retical moves closer to the center of the color wheel, the saturation % drops. Once the retical passes the threshold (default 50%) it will switch to white mode or color and white mode depending on the device and config settings. See below for more details. + +* **RGBWW 5 Channel LED Strip Controller (RGB and Two Whites)** In the color wheel, move the retical from cyan to red. This will transition the LEDs in this pattern: +```Color-Only>Color and Cold-White>Cold-White Only>Cold-White and Warm-White>Warm-White Only>Color and Warm-White>Color-Only``` + +* **RGBWW 5 Channel LED Lightbulb (RGB and Two Whites)** In the color wheel, move the retical from cyan to red. This will transition the LEDs in this pattern: +```Color-OnlyCold-White Only>Cold-White and Warm-White>Warm-White Only>Color-Only``` + +* **RGBWW 4 Channel LED Strip Controller (RGB and One White)** In the color wheel, move the retical from cyan to red. This will transition the LEDs in this pattern: +```Color-Only>Color and White>White Only>Color and White>Color-Only``` + +* **RGBW 4 Channel LED Lightbulb (RGB and One White)** In the color wheel, move the retical from cyan to red. This will transition the LEDs in this pattern: +```Color-Only>White-Only>Color-Only``` + +* **RGB 3 Channel (RGB Only)** Normal RGB functionality. + +## Configuration + +Please setup your config in Config UI X under ```Plugins>Homebridge MagicHome Dynamic Platform>Settings.``` +However the default settings should suffice. Please read below to learn more about the settings before changing anything. + +### Settings + +#### Pruning + +* `pruneMissingCachedAccessories` - **true** / **false** "Prune" or remove accessories once they have been missing for n restarts. Associated names, timers, and scenes will be lost for those accessories. + +* `restartsBeforeMissingAccessoriesPruned` - ***number*** The number of homebridge restarts that an accessory can be not seen before being pruned. Will not occur if `pruneMissingCachedAccessories` is set to false. + +* `pruneAllAccessoriesNextRestart` - **true** / **false** "Prune" or remove all accessories next restart. Use this if you would like to remove all your magichome accessories next restart. Be sure to set to false after you restart otherwise the cached accessories and associated names, timers, and scenes will be lost. + +#### White Effects + +* `simultaniousDevicesColorWhite` - **true** / **false** Allow simultanious color and white LEDs on compatible devices. + +* `colorWhiteThreshold` - **number** The saturation threshold from color-only to white-only for non-simultanious devices. + +* `colorWhiteThresholdSimultaniousDevices` - **number** The saturation threshold from color-only to color and white for simulanious devices. + +* `colorOffThresholdSimultaniousDevices` - **number** The saturation threshold from color and white to white only for simultanious devices. + +#### Device Management + +* `blacklistOrWhitelist` - **blacklist** / **whitelist** Whether the listed Unique IDs are blacklisted or whitelisted. + +* `blacklistedUniqueIDs` - **Alphanumeric** Unique IDs of devices you wish this plugin to ignore/delete. Can be found in the Magichome app under "MAC Address" or in the logs under "Unique ID". **i.e. 6001940EDC1F** diff --git a/config.schema.json b/config.schema.json index 8fb05c9..162be36 100644 --- a/config.schema.json +++ b/config.schema.json @@ -1,140 +1,140 @@ -{ - "pluginAlias": "homebridge-magichome-dynamic-platform", - "pluginType": "platform", - "singular": true, - "schema": { - "type": "object", - "properties": { - "pruning": { - "type": "object", - "properties": { - "pruneMissingCachedAccessories": { - "title": "Prune Missing Accesories Next Restart", - "type": "boolean", - "default" : false, - "required": true - - }, - "restartsBeforeMissingAccessoriesPruned": { - "title": "Number Restarts Before Missing Accessories Are Pruned", - "type": "integer", - "default" : 3, - "required": true - }, - "pruneAllAccessoriesNextRestart": { - "title": " Prune All MagicHome Accessories Next Restart (WARNING: Dangerous!)", - "type": "boolean", - "default" : false, - "required": true - } - } - }, - "whiteEffects": { - "type": "object", - "properties": { - "simultaniousDevicesColorWhite": { - "title": "Allow Simultaneous Color and White for Compatible Devices", - "type": "boolean", - "default" : true, - "required": true - }, - "colorWhiteThreshold": { - "title": "Saturation Threshold Between Color and White for Non-Simnultanious Devices", - "type": "integer", - "default" : 10, - "required": true - }, - "colorWhiteThresholdSimultaniousDevices": { - "title": "Saturation Threshold Between Color and White for Simultaneous Devices", - "type": "integer", - "default" : 50, - "required": true - }, - "colorOffThresholdSimultaniousDevices": { - "title": "Color Off Threshold for Simultaneous Devices", - "type": "integer", - "default" : 5, - "required": true - } - } - }, - "deviceManagement": { - "type": "object", - "properties": { - "blacklistOrWhitelist": { - "title": "Blacklist / Whitelist", - "type": "string", - "default": "blacklist", - "oneOf": [ - { "title": "Blacklist", "enum": ["blacklist"] }, - { "title": "Whitelist", "enum": ["whitelist"] } - ], - "required": true - }, - "blacklistedUniqueIDs": { - "title": "Blacklisted Unique ID", - "type": "array", - "items" : { - "title": "Unique ID", - "type": "string", - "default":[ - ] - } - } - - } - }, - "advancedOptions": { - "type": "object", - "properties": { - "namesWithMacAddress": { - "title": "Device names with MAC address.", - "description": "When this option is enabled, upon device registering each device name will contain the lst 6 digits of its MAC address, just like the default the MagicHome App gives. For example, when option is enabled a new lamp may get name of 'Bulb 22F481' instead of the default 'RGBW Non-Simultaneous'.", - "type": "boolean", - "default": false, - "required": true - }, - "logLevel": { - "title": "Log Level:", - "type": "integer", - "default": 3, - "oneOf": [ - { - "title": "1 - Errors", - "enum": [ - 1 - ] - }, - { - "title": "2 - Warnings", - "enum": [ - 2 - ] - }, - { - "title": "3 - Info (Default)", - "enum": [ - 3 - ] - }, - { - "title": "4 - Debug", - "enum": [ - 4 - ] - }, - { - "title": "5 - Trace", - "enum": [ - 5 - ] - } - ], - "required": true - } - } - } - } - } -} +{ + "pluginAlias": "homebridge-magichome-dynamic-platform", + "pluginType": "platform", + "singular": true, + "schema": { + "type": "object", + "properties": { + "pruning": { + "type": "object", + "properties": { + "pruneMissingCachedAccessories": { + "title": "Prune Missing Accesories Next Restart", + "type": "boolean", + "default" : false, + "required": true + + }, + "restartsBeforeMissingAccessoriesPruned": { + "title": "Number Restarts Before Missing Accessories Are Pruned", + "type": "integer", + "default" : 3, + "required": true + }, + "pruneAllAccessoriesNextRestart": { + "title": " Prune All MagicHome Accessories Next Restart (WARNING: Dangerous!)", + "type": "boolean", + "default" : false, + "required": true + } + } + }, + "whiteEffects": { + "type": "object", + "properties": { + "simultaniousDevicesColorWhite": { + "title": "Allow Simultaneous Color and White for Compatible Devices", + "type": "boolean", + "default" : true, + "required": true + }, + "colorWhiteThreshold": { + "title": "Saturation Threshold Between Color and White for Non-Simnultanious Devices", + "type": "integer", + "default" : 10, + "required": true + }, + "colorWhiteThresholdSimultaniousDevices": { + "title": "Saturation Threshold Between Color and White for Simultaneous Devices", + "type": "integer", + "default" : 50, + "required": true + }, + "colorOffThresholdSimultaniousDevices": { + "title": "Color Off Threshold for Simultaneous Devices", + "type": "integer", + "default" : 5, + "required": true + } + } + }, + "deviceManagement": { + "type": "object", + "properties": { + "blacklistOrWhitelist": { + "title": "Blacklist / Whitelist", + "type": "string", + "default": "blacklist", + "oneOf": [ + { "title": "Blacklist", "enum": ["blacklist"] }, + { "title": "Whitelist", "enum": ["whitelist"] } + ], + "required": true + }, + "blacklistedUniqueIDs": { + "title": "Blacklisted Unique ID", + "type": "array", + "items" : { + "title": "Unique ID", + "type": "string", + "default":[ + ] + } + } + + } + }, + "advancedOptions": { + "type": "object", + "properties": { + "namesWithMacAddress": { + "title": "Device names with MAC address.", + "description": "When this option is enabled, upon device registering each device name will contain the lst 6 digits of its MAC address, just like the default the MagicHome App gives. For example, when option is enabled a new lamp may get name of 'Bulb 22F481' instead of the default 'RGBW Non-Simultaneous'.", + "type": "boolean", + "default": false, + "required": true + }, + "logLevel": { + "title": "Log Level:", + "type": "integer", + "default": 3, + "oneOf": [ + { + "title": "1 - Errors", + "enum": [ + 1 + ] + }, + { + "title": "2 - Warnings", + "enum": [ + 2 + ] + }, + { + "title": "3 - Info (Default)", + "enum": [ + 3 + ] + }, + { + "title": "4 - Debug", + "enum": [ + 4 + ] + }, + { + "title": "5 - Trace", + "enum": [ + 5 + ] + } + ], + "required": true + } + } + } + } + } +} \ No newline at end of file diff --git a/nodemon.json b/nodemon.json index 86914d2..37e9e17 100644 --- a/nodemon.json +++ b/nodemon.json @@ -1,8 +1,8 @@ -{ - "watch": [ - "src" - ], - "ext": "ts", - "ignore": [], - "exec": "tsc && homebridge -I -D" -} +{ + "watch": [ + "src" + ], + "ext": "ts", + "ignore": [], + "exec": "tsc && homebridge -I -D" +} diff --git a/package-lock.json b/package-lock.json index af78405..19d5be3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6987 +1,6595 @@ -{ - "name": "homebridge-magichome-dynamic-platform", - "version": "1.9.3-beta.4", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "homebridge-magichome-dynamic-platform", - "version": "1.9.3-beta.4", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/Zacknetic" - }, - { - "type": "paypal", - "url": "https://www.paypal.com/paypalme/ZacharyAvino" - } - ], - "license": "Apache-2.0", - "dependencies": { - "color-convert": "^2.0.1", - "homebridge-lib": "^5.1.14" - }, - "devDependencies": { - "@types/expect": "^24.3.0", - "@types/mocha": "^9.1.1", - "@types/node": "^16.10.9", - "@typescript-eslint/eslint-plugin": "^5.0.0", - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^8.0.1", - "homebridge": "^1.5.0", - "mocha": "^10.0.0", - "nodemon": "^2.0.13", - "rimraf": "^3.0.2", - "ts-mocha": "^10.0.0", - "ts-node": "^10.3.0", - "typescript": "^4.4.4" - }, - "engines": { - "homebridge": ">=1.0.0", - "node": ">=10.17.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.3.2", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@homebridge/ciao": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", - "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0" - }, - "bin": { - "ciao-bcs": "lib/bonjour-conformance-testing.js" - } - }, - "node_modules/@homebridge/dbus-native": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.4.1.tgz", - "integrity": "sha512-8h6MkoJykY37THOyRXWCIKpzbhIn4WWKZBunlXTH75Cb6vBcmhyIhZ3SvzqJAjJCEdhLg7wawfn7/Mpko7eREQ==", - "dev": true, - "dependencies": { - "@homebridge/long": "^5.2.1", - "event-stream": "^4.0.0", - "hexy": "^0.2.10", - "optimist": "^0.6.1", - "put": "0.0.6", - "safe-buffer": "^5.1.1", - "xml2js": "^0.4.17" - }, - "bin": { - "dbus2js": "bin/dbus2js.js" - } - }, - "node_modules/@homebridge/long": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", - "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", - "dev": true - }, - "node_modules/@homebridge/plugin-ui-utils": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", - "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", - "dev": true, - "dependencies": { - "jest-get-type": "^28.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.28", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz", - "integrity": "sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow==", - "dev": true - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "node_modules/@types/expect": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", - "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", - "deprecated": "This is a stub types definition. expect provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "expect": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/json-schema": { - "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/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true, - "optional": true - }, - "node_modules/@types/mocha": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", - "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", - "dev": true - }, - "node_modules/@types/node": { - "version": "16.11.48", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.48.tgz", - "integrity": "sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.11", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.11.tgz", - "integrity": "sha512-aB4y9UDUXTSMxmM4MH+YnuR0g5Cph3FLQBoWoMB21DSvFVAxRVEHEMx3TLh+zUZYMCQtKiqazz0Q4Rre31f/OA==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz", - "integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/type-utils": "5.33.0", - "@typescript-eslint/utils": "5.33.0", - "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz", - "integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/typescript-estree": "5.33.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz", - "integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/visitor-keys": "5.33.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz", - "integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "5.33.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz", - "integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz", - "integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/visitor-keys": "5.33.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz", - "integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/typescript-estree": "5.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz", - "integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.33.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bonjour-hap": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.3.tgz", - "integrity": "sha512-qyLU96ICCYbpOFiMCjA3aNYH5Jc83XH1YX6+EXWukyyiNXzXH2LZv8AVmGW33FceF3gfUM4jYoKX2xChtNDUnA==", - "dependencies": { - "array-flatten": "^2.1.2", - "deep-equal": "^2.0.5", - "ip": "^1.1.5", - "multicast-dns": "^7.2.3", - "multicast-dns-service-types": "^1.1.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", - "dev": true - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-equal": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", - "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", - "dependencies": { - "call-bind": "^1.0.0", - "es-get-iterator": "^1.1.1", - "get-intrinsic": "^1.0.1", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.1.1", - "isarray": "^2.0.5", - "object-is": "^1.1.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3", - "which-boxed-primitive": "^1.0.1", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-packet": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", - "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", - "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", - "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", - "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "node_modules/expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fast-srp-hap": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", - "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", - "dev": true - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "dev": true - }, - "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/futoin-hkdf": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", - "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/hap-nodejs": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.10.2.tgz", - "integrity": "sha512-rmCKoNoBqpcOz/wG5iTtS7JIkLjobEZj+oXGW/Z4I4eJGk14VfKjITA8plaAm6gWIZEAajASzzUdEZnIKEvzdg==", - "dev": true, - "dependencies": { - "@homebridge/ciao": "^1.1.4", - "@homebridge/dbus-native": "^0.4.1", - "bonjour-hap": "~3.6.3", - "debug": "^4.3.4", - "fast-srp-hap": "2.0.4", - "futoin-hkdf": "~1.4.3", - "node-persist": "^0.0.11", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0", - "tweetnacl": "^1.0.3" - }, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/hexy": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", - "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", - "dev": true, - "bin": { - "hexy": "bin/hexy_cmd.js" - } - }, - "node_modules/homebridge": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.5.0.tgz", - "integrity": "sha512-0t8WNBKz9NFCab5obBfJMnxFgkg4uJZqON+iM/uZpIyiMRWH9ycCHd1pYAPMk9vDdfDu8/VpxYafWsYx6luHtg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "commander": "5.1.0", - "fs-extra": "^10.1.0", - "hap-nodejs": "^0.10.2", - "qrcode-terminal": "^0.12.0", - "semver": "^7.3.7", - "source-map-support": "^0.5.21" - }, - "bin": { - "homebridge": "bin/homebridge" - }, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/homebridge-lib": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.4.tgz", - "integrity": "sha512-R0/Kv2sgXThbAZogvB/H3O2Lqqi4n8T7gCXVq8Nx5UB4gXSjkOd/+8oc9l/U9EhoD19OSXFrE8VGKZcERal+yQ==", - "dependencies": { - "@homebridge/plugin-ui-utils": "~0.0.19", - "bonjour-hap": "^3.6.3", - "chalk": "^4.1.2", - "semver": "^7.3.7" - }, - "bin": { - "hap": "cli/hap.js", - "json": "cli/json.js", - "sysinfo": "cli/sysinfo.js", - "upnp": "cli/upnp.js" - }, - "engines": { - "homebridge": "^1.5.0", - "node": "^16.16.0" - } - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", - "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "optional": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/json5/node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true, - "optional": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "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.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true - }, - "node_modules/mkdirp": { - "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.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mkdirp/node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", - "dev": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/mocha/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/node-persist": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", - "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", - "dev": true, - "dependencies": { - "mkdirp": "~0.5.1", - "q": "~1.1.1" - } - }, - "node_modules/nodemon": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", - "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", - "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", - "dev": true, - "dependencies": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "dev": true, - "dependencies": { - "through": "~2.3" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/put": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz", - "integrity": "sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==", - "dev": true, - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/q": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", - "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qrcode-terminal": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", - "dev": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/simple-update-notifier": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", - "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", - "dev": true, - "dependencies": { - "semver": "~7.0.0" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", - "dev": true, - "dependencies": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/ts-mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", - "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", - "dev": true, - "dependencies": { - "ts-node": "7.0.1" - }, - "bin": { - "ts-mocha": "bin/ts-mocha" - }, - "engines": { - "node": ">= 6.X.X" - }, - "optionalDependencies": { - "tsconfig-paths": "^3.5.0" - }, - "peerDependencies": { - "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X" - } - }, - "node_modules/ts-mocha/node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/ts-mocha/node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/ts-mocha/node_modules/ts-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", - "dev": true, - "dependencies": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" - }, - "bin": { - "ts-node": "dist/bin.js" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/ts-mocha/node_modules/yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "optional": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true, - "optional": true - }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", - "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", - "dev": true - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - } - }, - "@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.3.2", - "globals": "^13.15.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@homebridge/ciao": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", - "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", - "dev": true, - "requires": { - "debug": "^4.3.4", - "fast-deep-equal": "^3.1.3", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0" - } - }, - "@homebridge/dbus-native": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.4.1.tgz", - "integrity": "sha512-8h6MkoJykY37THOyRXWCIKpzbhIn4WWKZBunlXTH75Cb6vBcmhyIhZ3SvzqJAjJCEdhLg7wawfn7/Mpko7eREQ==", - "dev": true, - "requires": { - "@homebridge/long": "^5.2.1", - "event-stream": "^4.0.0", - "hexy": "^0.2.10", - "optimist": "^0.6.1", - "put": "0.0.6", - "safe-buffer": "^5.1.1", - "xml2js": "^0.4.17" - } - }, - "@homebridge/long": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", - "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", - "dev": true - }, - "@homebridge/plugin-ui-utils": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", - "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" - }, - "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@jest/expect-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", - "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", - "dev": true, - "requires": { - "jest-get-type": "^28.0.2" - } - }, - "@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@leichtgewicht/ip-codec": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", - "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sinclair/typebox": { - "version": "0.24.28", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.28.tgz", - "integrity": "sha512-dgJd3HLOkLmz4Bw50eZx/zJwtBq65nms3N9VBYu5LTjJ883oBFkTyXRlCB/ZGGwqYpJJHA5zW2Ibhl5ngITfow==", - "dev": true - }, - "@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", - "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", - "dev": true - }, - "@types/expect": { - "version": "24.3.0", - "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", - "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", - "dev": true, - "requires": { - "expect": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/json-schema": { - "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/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true, - "optional": true - }, - "@types/mocha": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", - "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", - "dev": true - }, - "@types/node": { - "version": "16.11.48", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.48.tgz", - "integrity": "sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/yargs": { - "version": "17.0.11", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.11.tgz", - "integrity": "sha512-aB4y9UDUXTSMxmM4MH+YnuR0g5Cph3FLQBoWoMB21DSvFVAxRVEHEMx3TLh+zUZYMCQtKiqazz0Q4Rre31f/OA==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz", - "integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/type-utils": "5.33.0", - "@typescript-eslint/utils": "5.33.0", - "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz", - "integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/typescript-estree": "5.33.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz", - "integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/visitor-keys": "5.33.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz", - "integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "5.33.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz", - "integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz", - "integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/visitor-keys": "5.33.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz", - "integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.33.0", - "@typescript-eslint/types": "5.33.0", - "@typescript-eslint/typescript-estree": "5.33.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz", - "integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.33.0", - "eslint-visitor-keys": "^3.3.0" - } - }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bonjour-hap": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.3.tgz", - "integrity": "sha512-qyLU96ICCYbpOFiMCjA3aNYH5Jc83XH1YX6+EXWukyyiNXzXH2LZv8AVmGW33FceF3gfUM4jYoKX2xChtNDUnA==", - "requires": { - "array-flatten": "^2.1.2", - "deep-equal": "^2.0.5", - "ip": "^1.1.5", - "multicast-dns": "^7.2.3", - "multicast-dns-service-types": "^1.1.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - }, - "deep-equal": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", - "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", - "requires": { - "call-bind": "^1.0.0", - "es-get-iterator": "^1.1.1", - "get-intrinsic": "^1.0.1", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.1.1", - "isarray": "^2.0.5", - "object-is": "^1.1.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3", - "which-boxed-primitive": "^1.0.1", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.2" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-sequences": { - "version": "28.1.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", - "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "dns-packet": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", - "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", - "requires": { - "@leichtgewicht/ip-codec": "^2.0.1" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - } - }, - "es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", - "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", - "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "event-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", - "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "expect": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", - "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", - "dev": true, - "requires": { - "@jest/expect-utils": "^28.1.3", - "jest-get-type": "^28.0.2", - "jest-matcher-utils": "^28.1.3", - "jest-message-util": "^28.1.3", - "jest-util": "^28.1.3" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fast-srp-hap": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", - "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==", - "dev": true - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "dev": true - }, - "fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" - }, - "futoin-hkdf": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", - "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "hap-nodejs": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.10.2.tgz", - "integrity": "sha512-rmCKoNoBqpcOz/wG5iTtS7JIkLjobEZj+oXGW/Z4I4eJGk14VfKjITA8plaAm6gWIZEAajASzzUdEZnIKEvzdg==", - "dev": true, - "requires": { - "@homebridge/ciao": "^1.1.4", - "@homebridge/dbus-native": "^0.4.1", - "bonjour-hap": "~3.6.3", - "debug": "^4.3.4", - "fast-srp-hap": "2.0.4", - "futoin-hkdf": "~1.4.3", - "node-persist": "^0.0.11", - "source-map-support": "^0.5.21", - "tslib": "^2.4.0", - "tweetnacl": "^1.0.3" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "hexy": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", - "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", - "dev": true - }, - "homebridge": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.5.0.tgz", - "integrity": "sha512-0t8WNBKz9NFCab5obBfJMnxFgkg4uJZqON+iM/uZpIyiMRWH9ycCHd1pYAPMk9vDdfDu8/VpxYafWsYx6luHtg==", - "dev": true, - "requires": { - "chalk": "^4.1.2", - "commander": "5.1.0", - "fs-extra": "^10.1.0", - "hap-nodejs": "^0.10.2", - "qrcode-terminal": "^0.12.0", - "semver": "^7.3.7", - "source-map-support": "^0.5.21" - } - }, - "homebridge-lib": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.6.4.tgz", - "integrity": "sha512-R0/Kv2sgXThbAZogvB/H3O2Lqqi4n8T7gCXVq8Nx5UB4gXSjkOd/+8oc9l/U9EhoD19OSXFrE8VGKZcERal+yQ==", - "requires": { - "@homebridge/plugin-ui-utils": "~0.0.19", - "bonjour-hap": "^3.6.3", - "chalk": "^4.1.2", - "semver": "^7.3.7" - } - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", - "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0" - } - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "jest-diff": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", - "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^28.1.1", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - } - }, - "jest-get-type": { - "version": "28.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", - "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", - "dev": true - }, - "jest-matcher-utils": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", - "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^28.1.3", - "jest-get-type": "^28.0.2", - "pretty-format": "^28.1.3" - } - }, - "jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", - "dev": true, - "requires": { - "@jest/types": "^28.1.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true, - "optional": true - } - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "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.2", - "picomatch": "^2.3.1" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "dev": true - }, - "mkdirp": { - "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.6" - }, - "dependencies": { - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - } - } - }, - "mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", - "dev": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "requires": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node-persist": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", - "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", - "dev": true, - "requires": { - "mkdirp": "~0.5.1", - "q": "~1.1.1" - } - }, - "nodemon": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz", - "integrity": "sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==", - "dev": true, - "requires": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz", - "integrity": "sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "dev": true, - "requires": { - "through": "~2.3" - } - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "put": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz", - "integrity": "sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==", - "dev": true - }, - "q": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", - "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", - "dev": true - }, - "qrcode-terminal": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", - "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "requires": { - "lru-cache": "^6.0.0" - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "simple-update-notifier": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz", - "integrity": "sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==", - "dev": true, - "requires": { - "semver": "~7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2" - } - }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "optional": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "requires": { - "nopt": "~1.0.10" - } - }, - "ts-mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", - "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", - "dev": true, - "requires": { - "ts-node": "7.0.1", - "tsconfig-paths": "^3.5.0" - }, - "dependencies": { - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "ts-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", - "dev": true, - "requires": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" - } - }, - "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", - "dev": true - } - } - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, - "tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "optional": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true, - "optional": true - } - } - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", - "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", - "for-each": "^0.3.3", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "dev": true - }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "dev": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} +{ + "name": "homebridge-magichome-dynamic-platform", + "version": "1.9.3-beta.4", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "homebridge-magichome-dynamic-platform", + "version": "1.9.3-beta.4", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Zacknetic" + }, + { + "type": "paypal", + "url": "https://www.paypal.com/paypalme/ZacharyAvino" + } + ], + "license": "Apache-2.0", + "dependencies": { + "homebridge-lib": "^5.1.14" + }, + "devDependencies": { + "@types/expect": "^24.3.0", + "@types/mocha": "^9.1.1", + "@types/node": "^16.10.9", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^8.0.1", + "homebridge": "^1.5.0", + "mocha": "^10.0.0", + "nodemon": "^2.0.13", + "rimraf": "^3.0.2", + "ts-mocha": "^10.0.0", + "ts-node": "^10.3.0", + "typescript": "^4.4.4" + }, + "engines": { + "homebridge": "^1.5.0 || 2.0.0-beta.0", + "node": "^14.21.1 || ^16.18.1 || ^18.12.1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", + "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@homebridge/ciao": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", + "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "fast-deep-equal": "^3.1.3", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0" + }, + "bin": { + "ciao-bcs": "lib/bonjour-conformance-testing.js" + } + }, + "node_modules/@homebridge/dbus-native": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.0.tgz", + "integrity": "sha512-ei0jyHE/uNDl/6D6heRwsqnESrrXuSlfp+xlwGfg3mo1OqhKvyb/Kp73uxQyOJ3f1T1ocLSyA5uzoR1AbfaXIQ==", + "dev": true, + "dependencies": { + "@homebridge/long": "^5.2.1", + "@homebridge/put": "~0.0.8", + "event-stream": "^4.0.0", + "hexy": "^0.2.10", + "minimist": "^1.2.6", + "safe-buffer": "^5.1.1", + "xml2js": "^0.4.17" + }, + "bin": { + "dbus2js": "bin/dbus2js.js" + } + }, + "node_modules/@homebridge/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", + "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", + "dev": true + }, + "node_modules/@homebridge/plugin-ui-utils": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", + "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + }, + "node_modules/@homebridge/put": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@homebridge/put/-/put-0.0.8.tgz", + "integrity": "sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jest/expect-utils": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", + "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.2.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", + "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/expect": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", + "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", + "deprecated": "This is a stub types definition. expect provides its own type definitions, so you do not need this installed.", + "dev": true, + "dependencies": { + "expect": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "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/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "optional": true + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.18.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.10.tgz", + "integrity": "sha512-XU1+v7h81p7145ddPfjv7jtWvkSilpcnON3mQ+bDi9Yuf7OI56efOglXRyXWgQ57xH3fEQgh7WOJMncRHVew5w==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.17", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.17.tgz", + "integrity": "sha512-72bWxFKTK6uwWJAVT+3rF6Jo6RTojiJ27FQo8Rf60AL+VZbzoVPnMFhKsUnbjR8A3BTCYQ7Mv3hnl8T0A+CX9g==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", + "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/type-utils": "5.47.0", + "@typescript-eslint/utils": "5.47.0", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", + "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/typescript-estree": "5.47.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", + "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/visitor-keys": "5.47.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", + "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/utils": "5.47.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", + "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", + "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/visitor-keys": "5.47.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", + "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/typescript-estree": "5.47.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", + "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.47.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bonjour-hap": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.4.tgz", + "integrity": "sha512-a76r95/qTAP5hOEZZhRoiosyFSVPPRSVev09Jh8yDf3JDKyrzELLf0vpQCuEXFueb9DcV9UJf2Jv3dktyuPBng==", + "dependencies": { + "array-flatten": "^2.1.2", + "deep-equal": "^2.0.5", + "ip": "^1.1.8", + "multicast-dns": "^7.2.5", + "multicast-dns-service-types": "^1.1.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "dependencies": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", + "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", + "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, + "node_modules/expect": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", + "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.3.1", + "jest-get-type": "^29.2.0", + "jest-matcher-utils": "^29.3.1", + "jest-message-util": "^29.3.1", + "jest-util": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-srp-hap": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", + "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/fastq": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/futoin-hkdf": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", + "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/hap-nodejs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.0.tgz", + "integrity": "sha512-ZKSc/DIECXH1vSlruv6tBVcO+LF/BDtjdVk7IIiAAS+KKjw9PylkXbtdU23mmLhM69BsWl9u+BuToAfkf0voSw==", + "dev": true, + "dependencies": { + "@homebridge/ciao": "^1.1.5", + "@homebridge/dbus-native": "^0.5.0", + "bonjour-hap": "~3.6.4", + "debug": "^4.3.4", + "fast-srp-hap": "~2.0.4", + "futoin-hkdf": "~1.4.3", + "node-persist": "^0.0.11", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0", + "tweetnacl": "^1.0.3" + }, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "dev": true, + "bin": { + "hexy": "bin/hexy_cmd.js" + } + }, + "node_modules/homebridge": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.6.0.tgz", + "integrity": "sha512-n47db4ndrBOSxuF6zRFbBypuhW7dZjCoGJz03O9PfGrwsqjyzJyxkzSIAjT9HgbTdvNYDNGz/tMXSLoX0m5zGw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "commander": "5.1.0", + "fs-extra": "^10.1.0", + "hap-nodejs": "~0.11.0", + "qrcode-terminal": "^0.12.0", + "semver": "^7.3.7", + "source-map-support": "^0.5.21" + }, + "bin": { + "homebridge": "bin/homebridge" + }, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/homebridge-lib": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.7.2.tgz", + "integrity": "sha512-pEaDnO9IUcLyaPpxc+qWLBuOisZuNpYK4qg4mx7EffG4tat7XdZ17H+lHPvD8+lLNOwf9MT3yF68AraS6k7blQ==", + "dependencies": { + "@homebridge/plugin-ui-utils": "~0.0.19", + "bonjour-hap": "^3.6.4", + "chalk": "^4.1.2", + "semver": "^7.3.8" + }, + "bin": { + "hap": "cli/hap.js", + "json": "cli/json.js", + "sysinfo": "cli/sysinfo.js", + "upnp": "cli/upnp.js" + }, + "engines": { + "homebridge": "^1.5.1", + "node": "^18.12.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jest-diff": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", + "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.3.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", + "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", + "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.3.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", + "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.3.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.3.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", + "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "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.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "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.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==" + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/node-persist": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", + "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", + "dev": true, + "dependencies": { + "mkdirp": "~0.5.1", + "q": "~1.1.1" + } + }, + "node_modules/nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "dependencies": { + "through": "~2.3" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", + "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", + "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", + "dev": true, + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qrcode-terminal": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", + "dev": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", + "dev": true, + "dependencies": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", + "dev": true, + "dependencies": { + "ts-node": "7.0.1" + }, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "optionalDependencies": { + "tsconfig-paths": "^3.5.0" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X" + } + }, + "node_modules/ts-mocha/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ts-mocha/node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-mocha/node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "optional": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@eslint/eslintrc": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", + "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@homebridge/ciao": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.1.5.tgz", + "integrity": "sha512-ZI9tcbPfX2d8oP1PNeLzrZLXISAIDUtJQWk4JVVJKCxktC6tQ3JyWXT9t1FbB5xtl82M1jdCgyAbWbjhUtRWcA==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "fast-deep-equal": "^3.1.3", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0" + } + }, + "@homebridge/dbus-native": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@homebridge/dbus-native/-/dbus-native-0.5.0.tgz", + "integrity": "sha512-ei0jyHE/uNDl/6D6heRwsqnESrrXuSlfp+xlwGfg3mo1OqhKvyb/Kp73uxQyOJ3f1T1ocLSyA5uzoR1AbfaXIQ==", + "dev": true, + "requires": { + "@homebridge/long": "^5.2.1", + "@homebridge/put": "~0.0.8", + "event-stream": "^4.0.0", + "hexy": "^0.2.10", + "minimist": "^1.2.6", + "safe-buffer": "^5.1.1", + "xml2js": "^0.4.17" + } + }, + "@homebridge/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz", + "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==", + "dev": true + }, + "@homebridge/plugin-ui-utils": { + "version": "0.0.19", + "resolved": "https://registry.npmjs.org/@homebridge/plugin-ui-utils/-/plugin-ui-utils-0.0.19.tgz", + "integrity": "sha512-axFX7lN2Yd7bz/6SlD7dzq5sY/N9+XYuLHPukuiyHQRDtNMRL1uDqJhOx6RVaN2tYDHB75h7YxRQWP7U44Mgzg==" + }, + "@homebridge/put": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@homebridge/put/-/put-0.0.8.tgz", + "integrity": "sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jest/expect-utils": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", + "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", + "dev": true, + "requires": { + "jest-get-type": "^29.2.0" + } + }, + "@jest/schemas": { + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", + "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/types": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", + "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@types/expect": { + "version": "24.3.0", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-24.3.0.tgz", + "integrity": "sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ==", + "dev": true, + "requires": { + "expect": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "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/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "optional": true + }, + "@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, + "@types/node": { + "version": "16.18.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.10.tgz", + "integrity": "sha512-XU1+v7h81p7145ddPfjv7jtWvkSilpcnON3mQ+bDi9Yuf7OI56efOglXRyXWgQ57xH3fEQgh7WOJMncRHVew5w==", + "dev": true + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.17", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.17.tgz", + "integrity": "sha512-72bWxFKTK6uwWJAVT+3rF6Jo6RTojiJ27FQo8Rf60AL+VZbzoVPnMFhKsUnbjR8A3BTCYQ7Mv3hnl8T0A+CX9g==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", + "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/type-utils": "5.47.0", + "@typescript-eslint/utils": "5.47.0", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", + "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/typescript-estree": "5.47.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", + "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/visitor-keys": "5.47.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", + "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/utils": "5.47.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", + "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", + "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/visitor-keys": "5.47.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", + "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.47.0", + "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/typescript-estree": "5.47.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.47.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", + "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.47.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bonjour-hap": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.6.4.tgz", + "integrity": "sha512-a76r95/qTAP5hOEZZhRoiosyFSVPPRSVev09Jh8yDf3JDKyrzELLf0vpQCuEXFueb9DcV9UJf2Jv3dktyuPBng==", + "requires": { + "array-flatten": "^2.1.2", + "deep-equal": "^2.0.5", + "ip": "^1.1.8", + "multicast-dns": "^7.2.5", + "multicast-dns-service-types": "^1.1.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "ci-info": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-equal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", + "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", + "requires": { + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.8" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "diff-sequences": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", + "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", + "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.4.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "event-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", + "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "from": "^0.1.7", + "map-stream": "0.0.7", + "pause-stream": "^0.0.11", + "split": "^1.0.1", + "stream-combiner": "^0.2.2", + "through": "^2.3.8" + } + }, + "expect": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", + "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", + "dev": true, + "requires": { + "@jest/expect-utils": "^29.3.1", + "jest-get-type": "^29.2.0", + "jest-matcher-utils": "^29.3.1", + "jest-message-util": "^29.3.1", + "jest-util": "^29.3.1" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-srp-hap": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-2.0.4.tgz", + "integrity": "sha512-lHRYYaaIbMrhZtsdGTwPN82UbqD9Bv8QfOlKs+Dz6YRnByZifOh93EYmf2iEWFtkOEIqR2IK8cFD0UN5wLIWBQ==", + "dev": true + }, + "fastq": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, + "futoin-hkdf": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/futoin-hkdf/-/futoin-hkdf-1.4.3.tgz", + "integrity": "sha512-K4MIe2xSVRMYxsA4w0ap5fp1C2hA9StA2Ad1JZHX57VMCdHIRB5BSrd1FhuadTQG9MkjggaTCrw7v5XXFyY3/w==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "hap-nodejs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.11.0.tgz", + "integrity": "sha512-ZKSc/DIECXH1vSlruv6tBVcO+LF/BDtjdVk7IIiAAS+KKjw9PylkXbtdU23mmLhM69BsWl9u+BuToAfkf0voSw==", + "dev": true, + "requires": { + "@homebridge/ciao": "^1.1.5", + "@homebridge/dbus-native": "^0.5.0", + "bonjour-hap": "~3.6.4", + "debug": "^4.3.4", + "fast-srp-hap": "~2.0.4", + "futoin-hkdf": "~1.4.3", + "node-persist": "^0.0.11", + "source-map-support": "^0.5.21", + "tslib": "^2.4.0", + "tweetnacl": "^1.0.3" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hexy": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", + "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", + "dev": true + }, + "homebridge": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-1.6.0.tgz", + "integrity": "sha512-n47db4ndrBOSxuF6zRFbBypuhW7dZjCoGJz03O9PfGrwsqjyzJyxkzSIAjT9HgbTdvNYDNGz/tMXSLoX0m5zGw==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "commander": "5.1.0", + "fs-extra": "^10.1.0", + "hap-nodejs": "~0.11.0", + "qrcode-terminal": "^0.12.0", + "semver": "^7.3.7", + "source-map-support": "^0.5.21" + } + }, + "homebridge-lib": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/homebridge-lib/-/homebridge-lib-5.7.2.tgz", + "integrity": "sha512-pEaDnO9IUcLyaPpxc+qWLBuOisZuNpYK4qg4mx7EffG4tat7XdZ17H+lHPvD8+lLNOwf9MT3yF68AraS6k7blQ==", + "requires": { + "@homebridge/plugin-ui-utils": "~0.0.19", + "bonjour-hap": "^3.6.4", + "chalk": "^4.1.2", + "semver": "^7.3.8" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ip": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", + "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" + }, + "is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jest-diff": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", + "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.3.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + } + }, + "jest-get-type": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", + "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", + "dev": true + }, + "jest-matcher-utils": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", + "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.3.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.3.1" + } + }, + "jest-message-util": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", + "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.3.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.3.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", + "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", + "dev": true, + "requires": { + "@jest/types": "^29.3.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "map-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", + "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "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.2", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, + "mkdirp": { + "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.6" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==" + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node-persist": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", + "integrity": "sha512-J3EPzQDgPxPBID7TqHSd5KkpTULFqJUvYDoISfOWg9EihpeVCH3b6YQeDeubzVuc4e6+aiVmkz2sdkWI4K+ghA==", + "dev": true, + "requires": { + "mkdirp": "~0.5.1", + "q": "~1.1.1" + } + }, + "nodemon": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz", + "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "requires": { + "through": "~2.3" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "pretty-format": { + "version": "29.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", + "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "q": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", + "integrity": "sha512-ROtylwux7Vkc4C07oKE/ReigUmb33kVoLtcR4SJ1QVqwaZkBEDL3vX4/kwFzIERQ5PfCl0XafbU8u2YUhyGgVA==", + "dev": true + }, + "qrcode-terminal": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dev": true, + "requires": { + "through": "2" + } + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", + "dev": true, + "requires": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "optional": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "ts-mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", + "dev": true, + "requires": { + "ts-node": "7.0.1", + "tsconfig-paths": "^3.5.0" + }, + "dependencies": { + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + } + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true + } + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "optional": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "dev": true + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "requires": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/package.json b/package.json index 4d7da08..399f05c 100644 --- a/package.json +++ b/package.json @@ -1,82 +1,84 @@ -{ - "private": false, - "displayName": "Homebridge MagicHome Dynamic Platform", - "name": "homebridge-magichome-dynamic-platform", - "contributors": [ - "Zachary Avino ZackAvino@Zacknetic.org", - "Igor Ramos" - ], - "version": "1.9.3-beta.4", - "description": "Dynamically Discover and Add MagicHome Bulbs and Controllers to Homebrige.", - "license": "Apache-2.0", - "files": [ - "LICENSE", - "dist" - ], - "repository": { - "type": "git", - "url": "https://github.com/Zacknetic/HomebridgeMagicHome-DynamicPlatform" - }, - "bugs": { - "url": "https://github.com/Zacknetic/HomebridgeMagicHome-DynamicPlatform/issues" - }, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/Zacknetic" - }, - { - "type": "paypal", - "url": "https://www.paypal.com/paypalme/ZacharyAvino" - } - ], - "engines": { - "node": ">=10.17.0", - "homebridge": ">=1.0.0" - }, - "main": "dist/index.js", - "scripts": { - "lint": "eslint src/**.ts", - "watch": "npm run build && nodemon", - "build": "rimraf ./dist && tsc", - "prepublishOnly": "npm run lint && npm run build", - "test:watch": "ts-mocha --timeout 10000 --watch-extensions ts --watch --watch-files src 'src/specs/*.spec.ts'" - }, - "keywords": [ - "homebridge-plugin", - "hoobs", - "magichome", - "magic", - "home", - "lednet", - "Magic Home", - "magic home", - "outlet", - "dimmer", - "rgb", - "rgbw", - "rgbww", - "LEDnet", - "wowled", - "flux_led", - "smart lights" - ], - "dependencies": { - "homebridge-lib": "^5.1.14" - }, - "devDependencies": { - "@types/expect": "^24.3.0", - "@types/mocha": "^9.1.1", - "@types/node": "^16.10.9", - "@typescript-eslint/eslint-plugin": "^5.0.0", - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^8.0.1", - "homebridge": "^1.5.0", - "mocha": "^10.0.0", - "nodemon": "^2.0.13", - "rimraf": "^3.0.2", - "ts-mocha": "^10.0.0", - "ts-node": "^10.3.0", - "typescript": "^4.4.4" - } -} +{ + "private": false, + "displayName": "Homebridge MagicHome Dynamic Platform", + "name": "homebridge-magichome-dynamic-platform", + "contributors": [ + "Zachary Avino ZackAvino@Zacknetic.org", + "Igor Ramos" + ], + "version": "1.9.3-beta.4", + "description": "Dynamically Discover and Add MagicHome Bulbs and Controllers to Homebrige.", + "license": "Apache-2.0", + "files": [ + "LICENSE", + "dist" + ], + "repository": { + "type": "git", + "url": "https://github.com/Zacknetic/HomebridgeMagicHome-DynamicPlatform" + }, + "bugs": { + "url": "https://github.com/Zacknetic/HomebridgeMagicHome-DynamicPlatform/issues" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/Zacknetic" + }, + { + "type": "paypal", + "url": "https://www.paypal.com/paypalme/ZacharyAvino" + } + ], + + "main": "dist/index.js", + "engines": { + "homebridge": "^1.5.0 || 2.0.0-beta.0", + "node": "^14.21.1 || ^16.18.1 || ^18.12.1" + }, + "scripts": { + "rebuild": "rm package-lock.json && rm -r node_modules/ && npm install", + "lint": "eslint src/**.ts", + "watch": "npm run build && nodemon", + "build": "rimraf ./dist && tsc", + "prepublishOnly": "npm run lint && npm run build", + "test:watch": "ts-mocha --timeout 10000 --watch-extensions ts --watch --watch-files src 'src/specs/*.spec.ts'" + }, + "keywords": [ + "homebridge-plugin", + "hoobs", + "magichome", + "magic", + "home", + "lednet", + "Magic Home", + "magic home", + "outlet", + "dimmer", + "rgb", + "rgbw", + "rgbww", + "LEDnet", + "wowled", + "flux_led", + "smart lights" + ], + "dependencies": { + "homebridge-lib": "^5.1.14" + }, + "devDependencies": { + "@types/expect": "^24.3.0", + "@types/mocha": "^9.1.1", + "@types/node": "^16.10.9", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^8.0.1", + "homebridge": "^1.5.0", + "mocha": "^10.0.0", + "nodemon": "^2.0.13", + "rimraf": "^3.0.2", + "ts-mocha": "^10.0.0", + "ts-node": "^10.3.0", + "typescript": "^4.4.4" + } +} diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index 8b5791a..f13be24 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -37,8 +37,16 @@ export class AccessoryGenerator { this.logs.info('Scanning network for MagicHome accessories...'); try { - const completeDevices: ICompleteDevice[] = await this.controllerGenerator.discoverCompleteDevices(); + let completeDevices: ICompleteDevice[] = await this.controllerGenerator.discoverCompleteDevices(); + completeDevices = completeDevices.filter((device) => { + //if the device.completeDeviceInfo includes "ABCD" + if (device.completeDeviceInfo.protoDevice.uniqueId.includes('DC4F22CF7C31')) { + return true; + } else { + return false; + } + }); const controllers: BaseController[] = await this.controllerGenerator.generateControllers(completeDevices); const activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] = await this.generateActiveAccessories(controllers); @@ -145,7 +153,7 @@ export class AccessoryGenerator { // console.log(newAccessory) newAccessory.context = { displayName: description as string, deviceMetaData, protoDevice, latestUpdate: Date.now() }; // new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); - const hBAccessory = new HomebridgeMagichomeDynamicPlatformAccessory(this.api, newAccessory, this.config, controller, this.hbLogger, this.logs) + const hBAccessory = new HomebridgeMagichomeDynamicPlatformAccessory(this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); this.activeAccessoriesList.push(hBAccessory); return newAccessory; diff --git a/src/AnimationGenerator.ts b/src/AnimationGenerator.ts index 1b95b2e..fd29940 100644 --- a/src/AnimationGenerator.ts +++ b/src/AnimationGenerator.ts @@ -1,124 +1,124 @@ -import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave } from 'magichome-platform'; -import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; -import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; -import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; - -// import { homekitInterface } from './misc/types'; -import { Logs } from './logs'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -import { HomebridgeAnimationAccessory } from './animationAccessory'; - -const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; -const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; -const animationLoops = [colorWave, thunderStruck] -export class AnimationGenerator { - - public readonly animationsFromDiskMap: Map = new Map(); - public readonly activeAnimationAcessoriesMap: Map = new Map(); - public readonly cachedAccessoriesMap: Map = new Map(); - private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]; - private hap: HAP; - private api: API; - private hbLogger; - private config: PlatformConfig; - private logs: Logs; - constructor( - api: API, - logs: Logs, - hbLogger, - config, - animationsFromDiskMap, - activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]) { - this.api = api; - this.hap = api.hap; - this.hbLogger = hbLogger; - this.logs = logs; - this.config = config; - this.animationsFromDiskMap = animationsFromDiskMap; - this.activeAccessories = activeAccessories; - } - - - - async generateActiveAccessories() { - - const newAccessoriesList: AnimationAccessory[] = []; - const existingAccessoriesList: AnimationAccessory[] = []; - - - for (const animationLoop of animationLoops) { - const homebridgeUUID = this.hap.uuid.generate(animationLoop.name); - console.log(animationLoop.name) - try { - if (this.animationsFromDiskMap.has(homebridgeUUID)) { - const existingAnimationAccessory = this.animationsFromDiskMap.get(homebridgeUUID); - this.animationsFromDiskMap.delete(homebridgeUUID); - this.logs.info(`[${animationLoop.name}] - Found existing accessory. Updating...`); - const existingAccessory = this.processOnlineAccessory(existingAnimationAccessory, animationLoop); - existingAccessoriesList.push(existingAccessory); - - } else if (!this.activeAnimationAcessoriesMap.has(homebridgeUUID)) { //if the accessory is not a duplicate active device - const newAccessory: AnimationAccessory = this.createNewAnimation(animationLoop); - this.logs.info(`[${animationLoop.name}] - Found new accessory. Registering...`); - newAccessoriesList.push(newAccessory); //add it to new accessory list - - - this.activeAnimationAcessoriesMap.set(homebridgeUUID, newAccessory); - - } - - - } catch (e) { - this.logs.error(e) - } - } - - this.registerNewAccessories(newAccessoriesList); //register new accessories from scan - this.updateExistingAccessories(existingAccessoriesList); - } - - createNewAnimation(animationLoop: IAnimationLoop): AnimationAccessory { - let homebridgeUUID = this.hap.uuid.generate(animationLoop.name); - console.log(homebridgeUUID, animationLoop.name) - const newAccessory: AnimationAccessory = new this.api.platformAccessory(animationLoop.name, homebridgeUUID) as AnimationAccessory; - newAccessory.context.animationLoop = animationLoop; - new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); - return newAccessory; - } - - processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationLoop) { - - - // const { name, pattern, accessoryOffsetMS } = animationLoop; - - - try { - new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationLoop); - // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); - } catch (error) { - // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); - } - return existingAccessory; - } - - registerNewAccessories(newAccessories: AnimationAccessory[]) { - - // link the accessory to your platform - this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); - - } - - updateExistingAccessories(existingAccessories: AnimationAccessory[]) { - this.api.updatePlatformAccessories(existingAccessories); - } - - unregisterAccessory(existingAnimationAccessory) { - - // this.activeAnimationAcessoriesMap.delete(uuid); - this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAnimationAccessory]); - // this.logs.warn(reason); - } - - // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; - +import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave } from 'magichome-platform'; +import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; +import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; +import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; + +// import { homekitInterface } from './misc/types'; +import { Logs } from './logs'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +import { HomebridgeAnimationAccessory } from './animationAccessory'; + +const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; +const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; +const animationLoops = [colorWave, thunderStruck] +export class AnimationGenerator { + + public readonly animationsFromDiskMap: Map = new Map(); + public readonly activeAnimationAcessoriesMap: Map = new Map(); + public readonly cachedAccessoriesMap: Map = new Map(); + private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]; + private hap: HAP; + private api: API; + private hbLogger; + private config: PlatformConfig; + private logs: Logs; + constructor( + api: API, + logs: Logs, + hbLogger, + config, + animationsFromDiskMap, + activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]) { + this.api = api; + this.hap = api.hap; + this.hbLogger = hbLogger; + this.logs = logs; + this.config = config; + this.animationsFromDiskMap = animationsFromDiskMap; + this.activeAccessories = activeAccessories; + } + + + + async generateActiveAccessories() { + + const newAccessoriesList: AnimationAccessory[] = []; + const existingAccessoriesList: AnimationAccessory[] = []; + + + for (const animationLoop of animationLoops) { + const homebridgeUUID = this.hap.uuid.generate(animationLoop.name); + console.log(animationLoop.name) + try { + if (this.animationsFromDiskMap.has(homebridgeUUID)) { + const existingAnimationAccessory = this.animationsFromDiskMap.get(homebridgeUUID); + this.animationsFromDiskMap.delete(homebridgeUUID); + this.logs.info(`[${animationLoop.name}] - Found existing accessory. Updating...`); + const existingAccessory = this.processOnlineAccessory(existingAnimationAccessory, animationLoop); + existingAccessoriesList.push(existingAccessory); + + } else if (!this.activeAnimationAcessoriesMap.has(homebridgeUUID)) { //if the accessory is not a duplicate active device + const newAccessory: AnimationAccessory = this.createNewAnimation(animationLoop); + this.logs.info(`[${animationLoop.name}] - Found new accessory. Registering...`); + newAccessoriesList.push(newAccessory); //add it to new accessory list + + + this.activeAnimationAcessoriesMap.set(homebridgeUUID, newAccessory); + + } + + + } catch (e) { + this.logs.error(e) + } + } + + this.registerNewAccessories(newAccessoriesList); //register new accessories from scan + this.updateExistingAccessories(existingAccessoriesList); + } + + createNewAnimation(animationLoop: IAnimationLoop): AnimationAccessory { + let homebridgeUUID = this.hap.uuid.generate(animationLoop.name); + console.log(homebridgeUUID, animationLoop.name) + const newAccessory: AnimationAccessory = new this.api.platformAccessory(animationLoop.name, homebridgeUUID) as AnimationAccessory; + newAccessory.context.animationLoop = animationLoop; + new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); + return newAccessory; + } + + processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationLoop) { + + + // const { name, pattern, accessoryOffsetMS } = animationLoop; + + + try { + new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationLoop); + // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); + } catch (error) { + // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); + } + return existingAccessory; + } + + registerNewAccessories(newAccessories: AnimationAccessory[]) { + + // link the accessory to your platform + this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); + + } + + updateExistingAccessories(existingAccessories: AnimationAccessory[]) { + this.api.updatePlatformAccessories(existingAccessories); + } + + unregisterAccessory(existingAnimationAccessory) { + + // this.activeAnimationAcessoriesMap.delete(uuid); + this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAnimationAccessory]); + // this.logs.warn(reason); + } + + // const accessory = new this.api.platformAccessory(deviceQueryData.lightParameters.convenientName, generatedUUID) as MagicHomeAccessory; + } \ No newline at end of file diff --git a/src/accessories/CCTStrip.ts b/src/accessories/CCTStrip.ts index 3f73ac8..b44d6bf 100644 --- a/src/accessories/CCTStrip.ts +++ b/src/accessories/CCTStrip.ts @@ -1,39 +1,39 @@ -// import { clamp } from '../misc/utils'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -// export class CCTStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - -// async updateDeviceState(_timeout = 200) { - -// // //**** local variables ****\\ -// // const CCT = this.lightState.CCT; - -// //we default the mask to turn on color. Other values can still be set, they just wont turn on - -// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed -// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) -// //const ww = Math.round(((clamp(whites.warmWhite, 0, 127) / 100) * brightness)); -// //const cw = Math.round(((clamp(whites.coldWhite, 0, 127) / 100) * brightness)); - - -// //await this.send([0x31, 0x00, 0x00, 0x00, ww, cw, 0xFF, 0x0F], true, _timeout); //9th byte checksum calculated later in send() -// // await this.send([0x35, 0xb1, ww, cw, 0x00, 0x00, 0x00, 0x03], true, _timeout); //9th byte checksum calculated later in send() - - -// }//setColor - - -// async updateHomekitState() { -// // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); -// // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); -// //this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); -// // if (this.lightState.isOn){ -// // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(( -// // (this.lightState.whiteValues.coldWhite/1.27) -// // + (this.lightState.whiteValues.warmWhite/1.27)), 0, 100)); -// // } - -// //this.cacheCurrentLightState(); -// } - +// import { clamp } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +// export class CCTStrip extends HomebridgeMagichomeDynamicPlatformAccessory { + +// async updateDeviceState(_timeout = 200) { + +// // //**** local variables ****\\ +// // const CCT = this.lightState.CCT; + +// //we default the mask to turn on color. Other values can still be set, they just wont turn on + +// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// //const ww = Math.round(((clamp(whites.warmWhite, 0, 127) / 100) * brightness)); +// //const cw = Math.round(((clamp(whites.coldWhite, 0, 127) / 100) * brightness)); + + +// //await this.send([0x31, 0x00, 0x00, 0x00, ww, cw, 0xFF, 0x0F], true, _timeout); //9th byte checksum calculated later in send() +// // await this.send([0x35, 0xb1, ww, cw, 0x00, 0x00, 0x00, 0x03], true, _timeout); //9th byte checksum calculated later in send() + + +// }//setColor + + +// async updateHomekitState() { +// // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); +// // this.service.updateCharacteristic(this.platform.Characteristic.Hue, this.lightState.HSL.hue); +// //this.service.updateCharacteristic(this.platform.Characteristic.Saturation, this.lightState.HSL.saturation); +// // if (this.lightState.isOn){ +// // this.service.updateCharacteristic(this.platform.Characteristic.Brightness,clamp(( +// // (this.lightState.whiteValues.coldWhite/1.27) +// // + (this.lightState.whiteValues.warmWhite/1.27)), 0, 100)); +// // } + +// //this.cacheCurrentLightState(); +// } + // } \ No newline at end of file diff --git a/src/accessories/DimmerStrip.ts b/src/accessories/DimmerStrip.ts index d541467..5e5c29c 100644 --- a/src/accessories/DimmerStrip.ts +++ b/src/accessories/DimmerStrip.ts @@ -1,31 +1,31 @@ -// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -// export class DimmerStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - -// // /** -// // ** @updateHomekitState -// // * send state to homekit -// // */ -// // async updateHomekitState() { - -// // this.lightState.brightness = this.lightState.RGB.red / 2.5; //create local constant for brightness -// // //this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - -// // if( this.lightState.isOn ){ -// // //this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); -// // } - -// // } - -// // async setColor() { - -// // //**** local variables ****\\ -// // const brightness = Math.round((2.5 * this.lightState.brightness)); - -// // //await this.send([0x31, brightness, 0x00, 0x00, 0x03, 0x01, 0x0F]); //8th byte checksum calculated later in send() - - -// // }//setColor - - +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +// export class DimmerStrip extends HomebridgeMagichomeDynamicPlatformAccessory { + +// // /** +// // ** @updateHomekitState +// // * send state to homekit +// // */ +// // async updateHomekitState() { + +// // this.lightState.brightness = this.lightState.RGB.red / 2.5; //create local constant for brightness +// // //this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + +// // if( this.lightState.isOn ){ +// // //this.service.updateCharacteristic(this.platform.Characteristic.Brightness, this.lightState.brightness); +// // } + +// // } + +// // async setColor() { + +// // //**** local variables ****\\ +// // const brightness = Math.round((2.5 * this.lightState.brightness)); + +// // //await this.send([0x31, brightness, 0x00, 0x00, 0x03, 0x01, 0x0F]); //8th byte checksum calculated later in send() + + +// // }//setColor + + // } \ No newline at end of file diff --git a/src/accessories/GRBStrip.ts b/src/accessories/GRBStrip.ts index 22b816a..cbe9b5a 100644 --- a/src/accessories/GRBStrip.ts +++ b/src/accessories/GRBStrip.ts @@ -1,52 +1,52 @@ -// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -// import { convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, HSVtoRGB, RGBtoHSV } from '../misc/utils'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - - - -// export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - - -// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - -// const { isOn, HSV, colorTemperature, brightness } = accessoryCommand; -// const { hue, saturation, value } = HSV; -// const { red, green, blue }: IColorRGB = HSVtoRGB(HSV); - - -// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed -// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) -// const _green = Math.round((red / 100) * brightness); -// const _red = Math.round((green / 100) * brightness); -// const _blue = Math.round((blue / 100) * brightness); - - -// const deviceCommand: IDeviceCommand = { isOn, RGB: { red: _red, green: _green, blue: _blue }, CCT: { warmWhite: 0, coldWhite: 0 }, colorMask: 0xF0 }; -// return deviceCommand; -// }//setColor - -// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - -// const { RGB: { red, green, blue }, isOn } = deviceState; -// const RGB: IColorRGB = { red: green, green: red, blue }; -// // eslint-disable-next-line prefer-const -// let { hue, saturation, value } = RGBtoHSV(RGB); -// let brightness = 0; - -// //Brightness -// if (isOn) { -// brightness = value; -// } - - -// const accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; -// return accessoryState; -// } - - -// } - - - - +// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// import { convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, HSVtoRGB, RGBtoHSV } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + + + +// export class GRBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { + + +// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + +// const { isOn, HSV, colorTemperature, brightness } = accessoryCommand; +// const { hue, saturation, value } = HSV; +// const { red, green, blue }: IColorRGB = HSVtoRGB(HSV); + + +// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// const _green = Math.round((red / 100) * brightness); +// const _red = Math.round((green / 100) * brightness); +// const _blue = Math.round((blue / 100) * brightness); + + +// const deviceCommand: IDeviceCommand = { isOn, RGB: { red: _red, green: _green, blue: _blue }, CCT: { warmWhite: 0, coldWhite: 0 }, colorMask: 0xF0 }; +// return deviceCommand; +// }//setColor + +// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// const { RGB: { red, green, blue }, isOn } = deviceState; +// const RGB: IColorRGB = { red: green, green: red, blue }; +// // eslint-disable-next-line prefer-const +// let { hue, saturation, value } = RGBtoHSV(RGB); +// let brightness = 0; + +// //Brightness +// if (isOn) { +// brightness = value; +// } + + +// const accessoryState = { HSV: { hue, saturation, value }, isOn, brightness }; +// return accessoryState; +// } + + +// } + + + + diff --git a/src/accessories/RGBStrip.ts b/src/accessories/RGBStrip.ts index 76e00cf..5ef933f 100644 --- a/src/accessories/RGBStrip.ts +++ b/src/accessories/RGBStrip.ts @@ -1,34 +1,34 @@ -// import { clamp } from '../misc/utils'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -// export class RGBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { -// // public eightByteProtocol = 2; -// // async updateDeviceState() { - -// // //**** local variables ****\\ -// // const hsl = this.lightState.HSL; -// // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB -// // const brightness = this.lightState.brightness; - -// // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); -// // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); - -// // const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) -// // //we default the mask to turn on color. Other values can still be set, they just wont turn on - -// // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed -// // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) -// // const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); -// // const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); -// // const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); - -// // if(this.eightByteProtocol == 0){ -// // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() -// // } else if(this.eightByteProtocol == 1){ -// // // await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); -// // } else if (this.eightByteProtocol == 2){ -// // //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; -// // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() -// // } -// // }//setColor +// import { clamp } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +// export class RGBStrip extends HomebridgeMagichomeDynamicPlatformAccessory { +// // public eightByteProtocol = 2; +// // async updateDeviceState() { + +// // //**** local variables ****\\ +// // const hsl = this.lightState.HSL; +// // const [red, green, blue] = convertHSLtoRGB(hsl); //convert HSL to RGB +// // const brightness = this.lightState.brightness; + +// // //this.platform.log.debug('Current HSL and Brightness: h:%o s:%o l:%o br:%o', hsl.hue, hsl.saturation, hsl.luminance, brightness); +// // //this.platform.log.debug('Converted RGB: r:%o g:%o b:%o', red, green, blue); + +// // const mask = 0xF0; // the 'mask' byte tells the controller which LEDs to turn on color(0xF0), white (0x0F), or both (0xFF) +// // //we default the mask to turn on color. Other values can still be set, they just wont turn on + +// // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// // const r = Math.round(((clamp(red, 0, 255) / 100) * brightness)); +// // const g = Math.round(((clamp(green, 0, 255) / 100) * brightness)); +// // const b = Math.round(((clamp(blue, 0, 255) / 100) * brightness)); + +// // if(this.eightByteProtocol == 0){ +// // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() +// // } else if(this.eightByteProtocol == 1){ +// // // await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F]); +// // } else if (this.eightByteProtocol == 2){ +// // //this.eightByteProtocol = (await this.send([0x31, r, g, b, 0x00, 0x00, mask, 0x0F])) == undefined ? 0 : 1; +// // //await this.send([0x31, r, g, b, 0x00, mask, 0x0F]); //8th byte checksum calculated later in send() +// // } +// // }//setColor // } \ No newline at end of file diff --git a/src/accessories/RGBWBulb.ts b/src/accessories/RGBWBulb.ts index 9b5ffc7..52e72d7 100644 --- a/src/accessories/RGBWBulb.ts +++ b/src/accessories/RGBWBulb.ts @@ -1,77 +1,77 @@ -// import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -// import { clamp, convertHueToColorCCT, whiteTemperatureToCCT } from '../misc/utils'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -// export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - -// // protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - -// // const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; -// // const { hue, saturation } = HSL; -// // const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); - -// // let { red, green, blue } = RGB; -// // let warmWhite; -// // let colorMask = 0xF0; - - - -// // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed -// // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) -// // // red = Math.round((red / 100) * brightness); -// // // green = Math.round((green / 100) * brightness); -// // // blue = Math.round((blue / 100) * brightness); -// // warmWhite = Math.round(2.55 * brightness); - -// // if (hue == 31 && saturation == 33) { - -// // red = 0; -// // green = 0; -// // blue = 0; -// // colorMask = 0x0F; - -// // } else if (saturation < 20) { - -// // red = 0; -// // green = 0; -// // blue = 0; -// // colorMask = 0x0F; - -// // } else { -// // warmWhite = 0; -// // } - -// // const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; -// // return deviceCommand; - -// // }//setColor - -// // deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - -// // const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; -// // // eslint-disable-next-line prefer-const -// // let { hue, saturation, luminance } = convertRGBtoHSL(RGB); -// // let brightness = 0; -// // let colorTemperature = 140; -// // if (luminance > 0 && isOn) { -// // brightness = luminance; -// // } else if (isOn) { -// // brightness = clamp(warmWhite / 2.55, 0, 100); -// // } - -// // if (warmWhite > 0) { -// // saturation = luminance; -// // colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); -// // if (saturation <= 2) { -// // const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); -// // hue = hueSat[0]; -// // saturation = 10; -// // } -// // } - -// // const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; -// // return accessoryState; -// // } - +// import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// import { clamp, convertHueToColorCCT, whiteTemperatureToCCT } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +// export class RGBWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { + +// // protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + +// // const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; +// // const { hue, saturation } = HSL; +// // const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); + +// // let { red, green, blue } = RGB; +// // let warmWhite; +// // let colorMask = 0xF0; + + + +// // //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// // //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// // // red = Math.round((red / 100) * brightness); +// // // green = Math.round((green / 100) * brightness); +// // // blue = Math.round((blue / 100) * brightness); +// // warmWhite = Math.round(2.55 * brightness); + +// // if (hue == 31 && saturation == 33) { + +// // red = 0; +// // green = 0; +// // blue = 0; +// // colorMask = 0x0F; + +// // } else if (saturation < 20) { + +// // red = 0; +// // green = 0; +// // blue = 0; +// // colorMask = 0x0F; + +// // } else { +// // warmWhite = 0; +// // } + +// // const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; +// // return deviceCommand; + +// // }//setColor + +// // deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// // const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; +// // // eslint-disable-next-line prefer-const +// // let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// // let brightness = 0; +// // let colorTemperature = 140; +// // if (luminance > 0 && isOn) { +// // brightness = luminance; +// // } else if (isOn) { +// // brightness = clamp(warmWhite / 2.55, 0, 100); +// // } + +// // if (warmWhite > 0) { +// // saturation = luminance; +// // colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); +// // if (saturation <= 2) { +// // const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// // hue = hueSat[0]; +// // saturation = 10; +// // } +// // } + +// // const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; +// // return accessoryState; +// // } + // } \ No newline at end of file diff --git a/src/accessories/RGBWStrip.ts b/src/accessories/RGBWStrip.ts index 28c95c3..67fef54 100644 --- a/src/accessories/RGBWStrip.ts +++ b/src/accessories/RGBWStrip.ts @@ -1,86 +1,86 @@ -// // import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -// // import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -// // import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp, convertMiredColorTemperatureToHueSat, whiteTemperatureToCCT } from '../misc/utils'; -// // import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - - -// export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - -// // protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - -// // const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; -// // const { hue, saturation } = HSL; -// // const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); -// // let { red, green, blue } = RGB, warmWhite; - -// // let colorMask = 0xFF; - -// // warmWhite = Math.round(2.55 * brightness); - -// // if (hue == 31 && saturation == 33) { - -// // red = 0; -// // green = 0; -// // blue = 0; -// // colorMask = 0x0F; - -// // } else if (saturation < this.colorOffSaturationLevel) { -// // red = 0; -// // green = 0; -// // blue = 0; - -// // /** -// // * else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" -// // * set RGB to 100% saturation and 100% brightness -// // * this allows brightness to only affect the white colors, creating beautiful white+color balance -// // * we've set the color saturation to 100% because the higher the white level the more washed out the colors become -// // * the white brightness effectively acts as the saturation value -// // */ - -// // } else if (saturation < this.colorWhiteSimultaniousSaturationLevel) { - -// // const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation -// // red = _RGB.red; -// // green = _RGB.green; -// // blue = _RGB.blue; - -// // red = Math.round((red / 100) * (saturation * 2)); -// // green = Math.round((green / 100) * (saturation * 2)); -// // blue = Math.round((blue / 100) * (saturation * 2)); - -// // } else { -// // warmWhite = 0; -// // } - -// // const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; -// // return deviceCommand; -// // } - -// // deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - -// // const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; -// // // eslint-disable-next-line prefer-const -// // let { hue, saturation, luminance } = convertRGBtoHSL(RGB); -// // let brightness = 0; -// // let colorTemperature = 140; -// // if (luminance > 0 && isOn) { -// // brightness = luminance; -// // if (coldWhite > 0 || warmWhite > 0) { -// // saturation = 25; -// // brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); -// // } -// // } else { -// // if (isOn) { -// // brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); -// // } -// // colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); -// // const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); -// // hue = hueSat[0]; -// // saturation = 10; - -// // } - -// // const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; -// // return accessoryState; -// // } +// // import { IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// // import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// // import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, clamp, convertMiredColorTemperatureToHueSat, whiteTemperatureToCCT } from '../misc/utils'; +// // import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + + +// export class RGBWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { + +// // protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + +// // const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; +// // const { hue, saturation } = HSL; +// // const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); +// // let { red, green, blue } = RGB, warmWhite; + +// // let colorMask = 0xFF; + +// // warmWhite = Math.round(2.55 * brightness); + +// // if (hue == 31 && saturation == 33) { + +// // red = 0; +// // green = 0; +// // blue = 0; +// // colorMask = 0x0F; + +// // } else if (saturation < this.colorOffSaturationLevel) { +// // red = 0; +// // green = 0; +// // blue = 0; + +// // /** +// // * else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" +// // * set RGB to 100% saturation and 100% brightness +// // * this allows brightness to only affect the white colors, creating beautiful white+color balance +// // * we've set the color saturation to 100% because the higher the white level the more washed out the colors become +// // * the white brightness effectively acts as the saturation value +// // */ + +// // } else if (saturation < this.colorWhiteSimultaniousSaturationLevel) { + +// // const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation +// // red = _RGB.red; +// // green = _RGB.green; +// // blue = _RGB.blue; + +// // red = Math.round((red / 100) * (saturation * 2)); +// // green = Math.round((green / 100) * (saturation * 2)); +// // blue = Math.round((blue / 100) * (saturation * 2)); + +// // } else { +// // warmWhite = 0; +// // } + +// // const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite: 0 }, colorMask }; +// // return deviceCommand; +// // } + +// // deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// // const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; +// // // eslint-disable-next-line prefer-const +// // let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// // let brightness = 0; +// // let colorTemperature = 140; +// // if (luminance > 0 && isOn) { +// // brightness = luminance; +// // if (coldWhite > 0 || warmWhite > 0) { +// // saturation = 25; +// // brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// // } +// // } else { +// // if (isOn) { +// // brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// // } +// // colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); +// // const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// // hue = hueSat[0]; +// // saturation = 10; + +// // } + +// // const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; +// // return accessoryState; +// // } // } \ No newline at end of file diff --git a/src/accessories/RGBWWBulb.ts b/src/accessories/RGBWWBulb.ts index 4c8bd10..9bce620 100644 --- a/src/accessories/RGBWWBulb.ts +++ b/src/accessories/RGBWWBulb.ts @@ -1,95 +1,95 @@ -// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -// import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -// export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { - -// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - -// const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; -// const { hue, saturation } = HSL; - -// const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); -// // let _CCT: IColorCCT; -// // if (this.ColorCommandMode == 'HSL') { -// const _CCT: IColorCCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" -// // } else { -// // _CCT = cctToWhiteTemperature(colorTemperature); -// // } -// let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; - -// let colorMask = 0xF0; - - - -// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed -// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) -// red = Math.round((red / 100) * brightness); -// green = Math.round((green / 100) * brightness); -// blue = Math.round((blue / 100) * brightness); -// warmWhite = Math.round((warmWhite / 100) * brightness); -// coldWhite = Math.round((coldWhite / 100) * brightness); - - -// if (hue == 31 && saturation == 33) { - -// red = 0; -// green = 0; -// blue = 0; -// coldWhite = 0; -// colorMask = 0x0F; -// } else if (hue == 208 && saturation == 17) { - -// red = 0; -// green = 0; -// blue = 0; -// warmWhite = 0; -// colorMask = 0x0F; - -// //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). -// //White colors were already calculated above -// } else if (saturation < 20) { - -// red = 0; -// green = 0; -// blue = 0; - -// colorMask = 0x0F; -// } else { -// warmWhite = 0; -// coldWhite = 0; -// } - -// const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; -// return deviceCommand; - -// }//setColor - -// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { -// const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; -// // eslint-disable-next-line prefer-const -// let { hue, saturation, luminance } = convertRGBtoHSL(RGB); -// let brightness = 0; -// let colorTemperature = 140; -// if (luminance > 0 && isOn) { -// brightness = luminance; -// if (coldWhite > 0 || warmWhite > 0) { -// saturation = 25; -// brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); -// } -// } else { -// if (isOn) { -// brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); -// } -// colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); -// const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); -// hue = hueSat[0]; -// saturation = 10; - -// } -// const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; -// return accessoryState; -// } - +// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// import { clamp, convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +// export class RGBWWBulb extends HomebridgeMagichomeDynamicPlatformAccessory { + +// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + +// const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; +// const { hue, saturation } = HSL; + +// const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); +// // let _CCT: IColorCCT; +// // if (this.ColorCommandMode == 'HSL') { +// const _CCT: IColorCCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "calculateWhiteColor()" +// // } else { +// // _CCT = cctToWhiteTemperature(colorTemperature); +// // } +// let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; + +// let colorMask = 0xF0; + + + +// //sanitize our color/white values with Math.round and clamp between 0 and 255, not sure if either is needed +// //next determine brightness by dividing by 100 and multiplying it back in as brightness (0-100) +// red = Math.round((red / 100) * brightness); +// green = Math.round((green / 100) * brightness); +// blue = Math.round((blue / 100) * brightness); +// warmWhite = Math.round((warmWhite / 100) * brightness); +// coldWhite = Math.round((coldWhite / 100) * brightness); + + +// if (hue == 31 && saturation == 33) { + +// red = 0; +// green = 0; +// blue = 0; +// coldWhite = 0; +// colorMask = 0x0F; +// } else if (hue == 208 && saturation == 17) { + +// red = 0; +// green = 0; +// blue = 0; +// warmWhite = 0; +// colorMask = 0x0F; + +// //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). +// //White colors were already calculated above +// } else if (saturation < 20) { + +// red = 0; +// green = 0; +// blue = 0; + +// colorMask = 0x0F; +// } else { +// warmWhite = 0; +// coldWhite = 0; +// } + +// const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; +// return deviceCommand; + +// }//setColor + +// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { +// const { RGB, CCT: { coldWhite, warmWhite }, isOn } = deviceState; +// // eslint-disable-next-line prefer-const +// let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// let brightness = 0; +// let colorTemperature = 140; +// if (luminance > 0 && isOn) { +// brightness = luminance; +// if (coldWhite > 0 || warmWhite > 0) { +// saturation = 25; +// brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// } +// } else { +// if (isOn) { +// brightness = clamp(((coldWhite / 2.55) + (warmWhite / 2.55)), 0, 100); +// } +// colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite: 0 }); +// const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// hue = hueSat[0]; +// saturation = 10; + +// } +// const accessoryState: IAccessoryState = { HSL: { hue, saturation, luminance }, isOn, colorTemperature: 140, brightness }; +// return accessoryState; +// } + // } \ No newline at end of file diff --git a/src/accessories/RGBWWStrip.ts b/src/accessories/RGBWWStrip.ts index 55c5680..c53ae47 100644 --- a/src/accessories/RGBWWStrip.ts +++ b/src/accessories/RGBWWStrip.ts @@ -1,110 +1,110 @@ -// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; -// import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; -// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -// export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { - -// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { - -// const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; - -// const { hue, saturation } = HSL; -// const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); - -// // let _CCT: IColorCCT; -// // if (this.ColorCommandMode == 'HSL') { -// const _CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "convertHueToColorCCT()" -// // } else { -// // _CCT = cctToWhiteTemperature(colorTemperature); -// // } -// let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; -// let colorMask = 0xFF; - -// warmWhite = Math.round((warmWhite / 100) * brightness); -// coldWhite = Math.round((coldWhite / 100) * brightness); - -// if (hue == 31 && saturation == 33) { - -// red = 0; -// green = 0; -// blue = 0; -// coldWhite = 0; -// colorMask = 0x0F; - -// } else if (hue == 208 && saturation == 17) { -// red = 0; -// green = 0; -// blue = 0; -// warmWhite = 0; -// colorMask = 0x0F; - -// //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). -// //White colors were already calculated above -// } else if (saturation <= 2) { - -// red = 0; -// green = 0; -// blue = 0; - -// //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" -// //set RGB to 100% saturation and 100% brightness -// //this allows brightness to only affect the white colors, creating beautiful white+color balance -// //we've set the color saturation to 100% because the higher the white level the more washed out the colors become -// //the white brightness effectively acts as the saturation value -// } else if (saturation <= 50) { - -// const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation -// red = _RGB.red; -// green = _RGB.green; -// blue = _RGB.blue; - -// red = Math.round((red / 100) * (saturation * 2)); -// green = Math.round((green / 100) * (saturation * 2)); -// blue = Math.round((blue / 100) * (saturation * 2)); - - -// //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs -// } else { -// warmWhite = 0; -// coldWhite = 0; -// } - -// const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; -// return deviceCommand; -// }//setColor - -// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - -// const { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } = deviceState; - -// // eslint-disable-next-line prefer-const -// let { hue, saturation, luminance } = convertRGBtoHSL(RGB); -// let brightness = 0; -// let colorTemperature = 140; - -// //Brightness -// if (isOn) { -// if (coldWhite == 0 && warmWhite == 0) { -// brightness = luminance; -// } else { -// brightness = clamp((Math.max(coldWhite / 2.55), (warmWhite / 2.55)), 0, 100); -// } -// } -// //Hue && Saturation -// if (coldWhite > 0 || warmWhite > 0) { -// saturation = luminance; -// colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); -// if (saturation <= 2) { -// const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); -// hue = hueSat[0]; -// saturation = 10; -// } -// } - -// const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; -// return accessoryState; -// } -// } - - +// import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +// import { IAccessoryCommand, IAccessoryState } from '../misc/types'; +// import { convertHSLtoRGB, convertRGBtoHSL, convertHueToColorCCT, cctToWhiteTemperature, clamp, whiteTemperatureToCCT, convertMiredColorTemperatureToHueSat } from '../misc/utils'; +// import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +// export class RGBWWStrip extends HomebridgeMagichomeDynamicPlatformAccessory { + +// protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): IDeviceCommand { + +// const { isOn, HSL, colorTemperature, brightness } = accessoryCommand; + +// const { hue, saturation } = HSL; +// const RGB: IColorRGB = convertHSLtoRGB({ hue, saturation, luminance: brightness }); + +// // let _CCT: IColorCCT; +// // if (this.ColorCommandMode == 'HSL') { +// const _CCT = convertHueToColorCCT(HSL.hue); //calculate the white colors as a function of hue and saturation. See "convertHueToColorCCT()" +// // } else { +// // _CCT = cctToWhiteTemperature(colorTemperature); +// // } +// let { red, green, blue } = RGB, { warmWhite, coldWhite } = _CCT; +// let colorMask = 0xFF; + +// warmWhite = Math.round((warmWhite / 100) * brightness); +// coldWhite = Math.round((coldWhite / 100) * brightness); + +// if (hue == 31 && saturation == 33) { + +// red = 0; +// green = 0; +// blue = 0; +// coldWhite = 0; +// colorMask = 0x0F; + +// } else if (hue == 208 && saturation == 17) { +// red = 0; +// green = 0; +// blue = 0; +// warmWhite = 0; +// colorMask = 0x0F; + +// //if saturation is below config set threshold, set rgb to 0 and set the mask to white (0x0F). +// //White colors were already calculated above +// } else if (saturation <= 2) { + +// red = 0; +// green = 0; +// blue = 0; + +// //else if saturation is less than config set "colorWhiteThreshold" AND above "colorOffThreshold" +// //set RGB to 100% saturation and 100% brightness +// //this allows brightness to only affect the white colors, creating beautiful white+color balance +// //we've set the color saturation to 100% because the higher the white level the more washed out the colors become +// //the white brightness effectively acts as the saturation value +// } else if (saturation <= 50) { + +// const _RGB = convertHSLtoRGB({ hue, saturation: 100 }); //re-generate rgb with full saturation +// red = _RGB.red; +// green = _RGB.green; +// blue = _RGB.blue; + +// red = Math.round((red / 100) * (saturation * 2)); +// green = Math.round((green / 100) * (saturation * 2)); +// blue = Math.round((blue / 100) * (saturation * 2)); + + +// //else saturation is greater than "colorWhiteThreshold" so we set ww and cw to 0 and only display the color LEDs +// } else { +// warmWhite = 0; +// coldWhite = 0; +// } + +// const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, CCT: { warmWhite, coldWhite }, colorMask }; +// return deviceCommand; +// }//setColor + +// deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + +// const { RGB, RGB: { red, green, blue }, CCT: { coldWhite, warmWhite }, isOn } = deviceState; + +// // eslint-disable-next-line prefer-const +// let { hue, saturation, luminance } = convertRGBtoHSL(RGB); +// let brightness = 0; +// let colorTemperature = 140; + +// //Brightness +// if (isOn) { +// if (coldWhite == 0 && warmWhite == 0) { +// brightness = luminance; +// } else { +// brightness = clamp((Math.max(coldWhite / 2.55), (warmWhite / 2.55)), 0, 100); +// } +// } +// //Hue && Saturation +// if (coldWhite > 0 || warmWhite > 0) { +// saturation = luminance; +// colorTemperature = whiteTemperatureToCCT({ warmWhite, coldWhite }); +// if (saturation <= 2) { +// const hueSat = convertMiredColorTemperatureToHueSat(colorTemperature); +// hue = hueSat[0]; +// saturation = 10; +// } +// } + +// const accessoryState = { HSL: { hue, saturation, luminance }, isOn, brightness }; +// return accessoryState; +// } +// } + + diff --git a/src/accessories/Switch.ts b/src/accessories/Switch.ts index e487e2c..3ac52de 100644 --- a/src/accessories/Switch.ts +++ b/src/accessories/Switch.ts @@ -1,18 +1,18 @@ -import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; - -export class Switch extends HomebridgeMagichomeDynamicPlatformAccessory { - - // /** - // ** @updateHomekitState - // * send state to homekit - // */ - // async updateHomekitState() { - - // // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); - - // } - - - - +import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; + +export class Switch extends HomebridgeMagichomeDynamicPlatformAccessory { + + // /** + // ** @updateHomekitState + // * send state to homekit + // */ + // async updateHomekitState() { + + // // this.service.updateCharacteristic(this.platform.Characteristic.On, this.lightState.isOn); + + // } + + + + } \ No newline at end of file diff --git a/src/animationAccessory.ts b/src/animationAccessory.ts index bb0b4fd..4ba15fc 100644 --- a/src/animationAccessory.ts +++ b/src/animationAccessory.ts @@ -1,158 +1,158 @@ -import type { Service, CharacteristicValue, HAP } from 'homebridge'; - -import { AnimationAccessory, DEFAULT_ACCESSORY_STATE, IAccessoryState } from './misc/types'; -// import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, AnimationController } from 'magichome-platform'; -import { Logs } from './logs'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; - -const LISTENING_TIMEOUT_MS: number = 300; - -export class HomebridgeAnimationAccessory { - - protected service: Service; - protected service2: Service; - - protected accessoryState: IAccessoryState; - protected animationController: AnimationController; - protected isRecoding = false; - protected numToggles = 0; - listeningTimeout: NodeJS.Timeout; - listenCount: number = 0; - countTimeout: NodeJS.Timeout; - isListening: boolean = false; - isTurnedOn: number = 0; - //================================================= - // Start Constructor // - - constructor( - protected hap: HAP, - protected logs, - protected api, - protected accessory: AnimationAccessory, - protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], - protected animationLoop - ) { - this.accessoryState = DEFAULT_ACCESSORY_STATE; - // this.logs = logs; - // this.controller = controller; - this.hap = api.hap; - this.api = api; - // this.config = config; - this.initializeCharacteristics(); - this.animationController = new AnimationController(); - } - - //================================================= - // End Constructor // - - //================================================= - // Start Setters // - async setOn(value: CharacteristicValue) { - this.accessoryState.isOn = value as boolean; - if (this.animationController.isActive || !value) this.animationController.clearAnimations(); - clearTimeout(this.listeningTimeout); - this.listenCount++; - if (this.listenCount == 2) { - this.logs.info("Listening for new devices.") - this.isListening = true; - // this.service2.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, true); - } else if (this.listenCount == 3) { - this.listeningTimeout = setTimeout(async () => { - this.listenCount = 0; - this.isListening = false; - - this.logs.info("Assigning new devices.") - const filteredAccessories = this.accessoriesList.filter(accessory => { - return accessory.isReadyToAnimate(); - }); - for (const accessory of filteredAccessories) { - if(!this.accessory.context.activeControllerList)this.accessory.context.activeControllerList = []; - this.accessory.context.activeControllerList.push(accessory.getController()) - } - }, LISTENING_TIMEOUT_MS); - } else if (this.listenCount >= 5) { - this.isListening = false; - this.listenCount = 0; - this.accessory.context.activeControllerList = []; - } else { - this.listeningTimeout = setTimeout(async () => { - this.listenCount = 0; - if (value) { - - await this.animationController.animateAsynchronously(this.accessory.context.activeControllerList, this.animationLoop).catch(e => { }) - } - }, LISTENING_TIMEOUT_MS); - } - } - - /** - * Handle requests to get the current value of the "Status Low Battery" characteristic - */ - - setConfiguredName(value: CharacteristicValue) { - - const name: string = value.toString(); - this.logs.warn('Renaming device to %o', name); - this.accessory.context.displayName = name; - this.api.updatePlatformAccessories([this.accessory]); - } - - //================================================= - // End Setters // - - //================================================= - // Start Getters // - - async getOn() { - const { isOn } = this.accessoryState; - return isOn; - } - - - //================================================= - // End LightEffects // - - initializeCharacteristics() { - this.addAccessoryInformationCharacteristic(); - - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding "Switch" service to accessory.`); - this.service = this.accessory.getService(this.hap.Service.Outlet) ?? this.accessory.addService(this.hap.Service.Outlet); - this.addOnCharacteristic(); - this.addConfiguredNameCharacteristic(); - } - - addOnCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.On) - .onSet(this.setOn.bind(this)) - .onGet(this.getOn.bind(this)); - } - - addAccessoryInformationCharacteristic() { - - this.accessory.getService(this.hap.Service.AccessoryInformation)! - .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') - // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) - // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) - // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') - // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') - .removeAllListeners(this.hap.CharacteristicEventTypes.SET) - .removeAllListeners(this.hap.CharacteristicEventTypes.GET); - - this.accessory.getService(this.hap.Service.AccessoryInformation)! - .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); - } - - addConfiguredNameCharacteristic() { - if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { - this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) - .onSet(this.setConfiguredName.bind(this)); - } else { - this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) - .onSet(this.setConfiguredName.bind(this)); - } - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); - - } -} +import type { Service, CharacteristicValue, HAP } from 'homebridge'; + +import { AnimationAccessory, DEFAULT_ACCESSORY_STATE, IAccessoryState } from './misc/types'; +// import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; +import { BaseController, AnimationController } from 'magichome-platform'; +import { Logs } from './logs'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; + +const LISTENING_TIMEOUT_MS: number = 300; + +export class HomebridgeAnimationAccessory { + + protected service: Service; + protected service2: Service; + + protected accessoryState: IAccessoryState; + protected animationController: AnimationController; + protected isRecoding = false; + protected numToggles = 0; + listeningTimeout: NodeJS.Timeout; + listenCount: number = 0; + countTimeout: NodeJS.Timeout; + isListening: boolean = false; + isTurnedOn: number = 0; + //================================================= + // Start Constructor // + + constructor( + protected hap: HAP, + protected logs, + protected api, + protected accessory: AnimationAccessory, + protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], + protected animationLoop + ) { + this.accessoryState = DEFAULT_ACCESSORY_STATE; + // this.logs = logs; + // this.controller = controller; + this.hap = api.hap; + this.api = api; + // this.config = config; + this.initializeCharacteristics(); + this.animationController = new AnimationController(); + } + + //================================================= + // End Constructor // + + //================================================= + // Start Setters // + async setOn(value: CharacteristicValue) { + this.accessoryState.isOn = value as boolean; + if (this.animationController.isActive || !value) this.animationController.clearAnimations(); + clearTimeout(this.listeningTimeout); + this.listenCount++; + if (this.listenCount == 2) { + this.logs.info("Listening for new devices.") + this.isListening = true; + // this.service2.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, true); + } else if (this.listenCount == 3) { + this.listeningTimeout = setTimeout(async () => { + this.listenCount = 0; + this.isListening = false; + + this.logs.info("Assigning new devices.") + const filteredAccessories = this.accessoriesList.filter(accessory => { + return accessory.isReadyToAnimate(); + }); + for (const accessory of filteredAccessories) { + if(!this.accessory.context.activeControllerList)this.accessory.context.activeControllerList = []; + this.accessory.context.activeControllerList.push(accessory.getController()) + } + }, LISTENING_TIMEOUT_MS); + } else if (this.listenCount >= 5) { + this.isListening = false; + this.listenCount = 0; + this.accessory.context.activeControllerList = []; + } else { + this.listeningTimeout = setTimeout(async () => { + this.listenCount = 0; + if (value) { + + await this.animationController.animateAsynchronously(this.accessory.context.activeControllerList, this.animationLoop).catch(e => { }) + } + }, LISTENING_TIMEOUT_MS); + } + } + + /** + * Handle requests to get the current value of the "Status Low Battery" characteristic + */ + + setConfiguredName(value: CharacteristicValue) { + + const name: string = value.toString(); + this.logs.warn('Renaming device to %o', name); + this.accessory.context.displayName = name; + this.api.updatePlatformAccessories([this.accessory]); + } + + //================================================= + // End Setters // + + //================================================= + // Start Getters // + + async getOn() { + const { isOn } = this.accessoryState; + return isOn; + } + + + //================================================= + // End LightEffects // + + initializeCharacteristics() { + this.addAccessoryInformationCharacteristic(); + + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding "Switch" service to accessory.`); + this.service = this.accessory.getService(this.hap.Service.Outlet) ?? this.accessory.addService(this.hap.Service.Outlet); + this.addOnCharacteristic(); + this.addConfiguredNameCharacteristic(); + } + + addOnCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.On) + .onSet(this.setOn.bind(this)) + .onGet(this.getOn.bind(this)); + } + + addAccessoryInformationCharacteristic() { + + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') + // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) + // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) + // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') + // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') + .removeAllListeners(this.hap.CharacteristicEventTypes.SET) + .removeAllListeners(this.hap.CharacteristicEventTypes.GET); + + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); + } + + addConfiguredNameCharacteristic() { + if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { + this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } else { + this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + + } +} diff --git a/src/index.ts b/src/index.ts index c7ed50e..007c697 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,18 +1,18 @@ - -import { - API, - HAP, - PlatformAccessory, -} from 'homebridge'; - -let hap: HAP; -import { PLATFORM_NAME } from './settings'; -import { HomebridgeMagichomeDynamicPlatform } from './platform'; - -let Accessory: typeof PlatformAccessory; -export = (api: API) => { - hap = api.hap; - Accessory = api.platformAccessory; - - api.registerPlatform(PLATFORM_NAME, HomebridgeMagichomeDynamicPlatform); -}; + +import { + API, + HAP, + PlatformAccessory, +} from 'homebridge'; + +let hap: HAP; +import { PLATFORM_NAME } from './settings'; +import { HomebridgeMagichomeDynamicPlatform } from './platform'; + +let Accessory: typeof PlatformAccessory; +export = (api: API) => { + hap = api.hap; + Accessory = api.platformAccessory; + + api.registerPlatform(PLATFORM_NAME, HomebridgeMagichomeDynamicPlatform); +}; diff --git a/src/logs.ts b/src/logs.ts index 53075c2..1241d78 100644 --- a/src/logs.ts +++ b/src/logs.ts @@ -1,44 +1,45 @@ -import { Logging } from 'homebridge'; - -export class Logs { - constructor(private hbLogger: Logging, private readonly level = 3) { - // logs = this; - this.level = level; - } - - trace(message, ...parameters: any[]) { - if (this.level >= 5) { - this.hbLogger.info('[Trace]', message, ...parameters); - } - } - - debug(message, ...parameters: any[]) { - if (this.level >= 4) { - this.hbLogger.info('[Debug]', message, ...parameters); - } - } - - info(message, ...parameters: any[]) { - if (this.level >= 3) { - this.hbLogger.info('[Info]', message, ...parameters); - } - } - - warn(message, ...parameters: any[]) { - if (this.level >= 2) { - this.hbLogger.warn('[Warning]', message, ...parameters); - } - } - - error(message, ...parameters: any[]) { - if (this.level >= 1) { - this.hbLogger.error('[Error]', message, ...parameters); - } - } -} - -let logs: Logs; - -export function getLogs() { - return logs; -} \ No newline at end of file +import { Logging } from 'homebridge'; + +export class Logs { + constructor(private hbLogger: Logging, private readonly level = 3) { + // logs = this; + this.level = level; + } + + trace(message, ...parameters: any[]) { + if (this.level >= 5) { + this.hbLogger.info('[Trace]', message, ...parameters); + } + } + + debug(message, ...parameters: any[]) { + if (this.level >= 4) { + this.hbLogger.info('[Debug]', message, ...parameters); + } + } + + info(message, ...parameters: any[]) { + if (this.level >= 3) { + this.hbLogger.info('[Info]', message, ...parameters); + } + } + + warn(message, ...parameters: any[]) { + if (this.level >= 2) { + this.hbLogger.warn('[Warning]', message, ...parameters); + } + } + + error(message, ...parameters: any[]) { + if (this.level >= 1) { + this.hbLogger.error('[Error]', message, ...parameters); + } + } +} + +let logs: Logs; + +export function getLogs() { + return logs; +} + diff --git a/src/misc/types.ts b/src/misc/types.ts index 1f8618b..a64e48c 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -1,132 +1,132 @@ -import type { PlatformAccessory } from 'homebridge'; -import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation, IDeviceMetaData, IProtoDevice, IAnimationLoop } from 'magichome-platform'; - -// import { Switch } from '../accessories/Switch'; -// import { DimmerStrip } from '../accessories/DimmerStrip'; -// import { RGBStrip } from '../accessories/RGBStrip'; -// import { GRBStrip } from '../accessories/GRBStrip'; -// import { RGBWBulb } from '../accessories/RGBWBulb'; -// import { RGBWWBulb } from '../accessories/RGBWWBulb'; -// import { RGBWStrip } from '../accessories/RGBWStrip'; -// import { RGBWWStrip } from '../accessories/RGBWWStrip'; -// import { CCTStrip } from '../accessories/CCTStrip'; - - -// export const homekitInterface = { -// // 'Power Socket': Switch, -// // 'Dimmer': DimmerStrip, -// // 'GRB Strip': GRBStrip, -// // 'RGB Strip': RGBStrip, -// 'RGBW Non-Simultaneous': RGBWBulb, -// 'RGBWW Non-Simultaneous': RGBWWBulb, -// 'RGBW Simultaneous': RGBWStrip, -// 'RGBWW Simultaneous': RGBWWStrip, -// // 'CCT Strip': CCTStrip, -// }; - -export interface MagicHomeAccessory extends PlatformAccessory { - context: IAccessoryContext; -} - -export interface AnimationAccessory extends PlatformAccessory { - context: IAnimationContext; -} - -export interface IAnimationContext { - animationLoop: IAnimationLoop; - activeControllerList: BaseController[]; - displayName?: string; -} - -export interface IAccessoryContext { - displayName?: string; - deviceMetaData: IDeviceMetaData; - protoDevice: IProtoDevice; - latestUpdate: number; -} - -export interface IAccessoryState { - isOn: boolean, - HSV: IColorHSV, - TB: IColorTB -} -export interface IPartialAccessoryCommand { - isOn?: boolean, - HSV?: IPartialColorHSV, - TB?: IPartialColorTB, - colorTemperature?: number, - isPowerCommand?: boolean, -} - -export interface IAccessoryCommand { - isOn: boolean, - HSV: IColorHSV, - TB: IColorTB - isPowerCommand: boolean, -} - -export interface IColorHSV { - hue: number; - saturation: number; - value: number; -} - -export interface IColorTB { - temperature: number; - brightness: number; -} - -export interface IPartialColorTB { - temperature?: number; - brightness?: number; -} - -export interface IPartialColorHSV { - hue?: number; - saturation?: number; - value?: number; -} - - -export interface IConfigOptions { - logLevel: number, - colorWhiteInterfaceMode: string, - colorOffSaturationLevel: number, - colorWhiteSimultaniousSaturationLevel?: number, -} - -/*----------------------[DEFAULT VALIUES]----------------------*/ - -export const COLOR_COMMAND_MODES = { - CCT: 'CCT', - HSV: 'HSV', -}; -export const DEFAULT_ANIMATION_STATE = { - isOn: false, -}; -export const DEFAULT_ACCESSORY_STATE: IAccessoryState = { - isOn: true, - HSV: { - hue: 0, - saturation: 0, - value: 100, - }, - TB: { - temperature: 140, - brightness: 100 - } -}; - -export const DEFAULT_ACCESSORY_COMMAND: IAccessoryCommand = { - isOn: false, - isPowerCommand: false, - HSV: { - hue: 0, - saturation: 0, - value: 0, - }, - TB: { - temperature: 140, - brightness: 0 - } +import type { PlatformAccessory } from 'homebridge'; +import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation, IDeviceMetaData, IProtoDevice, IAnimationLoop } from 'magichome-platform'; + +// import { Switch } from '../accessories/Switch'; +// import { DimmerStrip } from '../accessories/DimmerStrip'; +// import { RGBStrip } from '../accessories/RGBStrip'; +// import { GRBStrip } from '../accessories/GRBStrip'; +// import { RGBWBulb } from '../accessories/RGBWBulb'; +// import { RGBWWBulb } from '../accessories/RGBWWBulb'; +// import { RGBWStrip } from '../accessories/RGBWStrip'; +// import { RGBWWStrip } from '../accessories/RGBWWStrip'; +// import { CCTStrip } from '../accessories/CCTStrip'; + + +// export const homekitInterface = { +// // 'Power Socket': Switch, +// // 'Dimmer': DimmerStrip, +// // 'GRB Strip': GRBStrip, +// // 'RGB Strip': RGBStrip, +// 'RGBW Non-Simultaneous': RGBWBulb, +// 'RGBWW Non-Simultaneous': RGBWWBulb, +// 'RGBW Simultaneous': RGBWStrip, +// 'RGBWW Simultaneous': RGBWWStrip, +// // 'CCT Strip': CCTStrip, +// }; + +export interface MagicHomeAccessory extends PlatformAccessory { + context: IAccessoryContext; +} + +export interface AnimationAccessory extends PlatformAccessory { + context: IAnimationContext; +} + +export interface IAnimationContext { + animationLoop: IAnimationLoop; + activeControllerList: BaseController[]; + displayName?: string; +} + +export interface IAccessoryContext { + displayName?: string; + deviceMetaData: IDeviceMetaData; + protoDevice: IProtoDevice; + latestUpdate: number; +} + +export interface IAccessoryState { + isOn: boolean, + HSV: IColorHSV, + TB: IColorTB +} +export interface IPartialAccessoryCommand { + isOn?: boolean, + HSV?: IPartialColorHSV, + TB?: IPartialColorTB, + colorTemperature?: number, + isPowerCommand?: boolean, +} + +export interface IAccessoryCommand { + isOn: boolean, + HSV: IColorHSV, + TB: IColorTB + isPowerCommand: boolean, +} + +export interface IColorHSV { + hue: number; + saturation: number; + value: number; +} + +export interface IColorTB { + temperature: number; + brightness: number; +} + +export interface IPartialColorTB { + temperature?: number; + brightness?: number; +} + +export interface IPartialColorHSV { + hue?: number; + saturation?: number; + value?: number; +} + + +export interface IConfigOptions { + logLevel: number, + colorWhiteInterfaceMode: string, + colorOffSaturationLevel: number, + colorWhiteSimultaniousSaturationLevel?: number, +} + +/*----------------------[DEFAULT VALIUES]----------------------*/ + +export const COLOR_COMMAND_MODES = { + CCT: 'CCT', + HSV: 'HSV', +}; +export const DEFAULT_ANIMATION_STATE = { + isOn: false, +}; +export const DEFAULT_ACCESSORY_STATE: IAccessoryState = { + isOn: true, + HSV: { + hue: 0, + saturation: 0, + value: 100, + }, + TB: { + temperature: 140, + brightness: 100 + } +}; + +export const DEFAULT_ACCESSORY_COMMAND: IAccessoryCommand = { + isOn: false, + isPowerCommand: false, + HSV: { + hue: 0, + saturation: 0, + value: 0, + }, + TB: { + temperature: 140, + brightness: 0 + } }; \ No newline at end of file diff --git a/src/misc/utils.ts b/src/misc/utils.ts index ba965a3..caff4b7 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -1,428 +1,470 @@ -import { existsSync, readFileSync } from 'fs'; -import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; -import { IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB } from './types'; - - -export function clamp(value: number, min: number, max: number) { - return Math.min(max, Math.max(min, value)); -} - - -//================================================= -// Start checksum // - - - -/** - * @checksum - * a checksum is needed at the end of the byte array otherwise the message is rejected by the device - * add all bytes and chop off the beginning by & with 0xFF - * @param buffer - * @returns checksum number - */ -export function checksum(buffer: Uint8Array) { - let chk = 0; - - for (const byte of buffer) { - chk += byte; - } - - return chk & 0xff; -} - -//================================================= -// Start Convert RGBtoHSL // -// export function convertRGBtoHSL(RGB: IColorRGB) { - -// const { red, green, blue } = RGB; - - -// const r = red / 255; -// const g = green / 255; -// const b = blue / 255; - -// let h, s, l; -// h = s = l = 0; - -// const max = Math.max(r, g, b); -// const min = Math.min(r, g, b); -// const C = max - min; -// if (C == 0) { -// h = 0; -// } else if (max == r) { -// h = ((g - b) / C) % 6; -// } else if (max == g) { -// h = (b - r) / C + 2; -// } else { -// h = (r - g) / C + 4; -// } -// h *= 60; -// if (h < 0) { -// h += 360; -// } -// l = max; -// if (l == 0) { -// s = 0; -// } else { -// s = C / l; -// } -// s *= 100; -// l *= 100; - -// const HSL: IColorHSL = { hue: Math.floor(h), saturation: Math.floor(s), luminance: Math.floor(l) }; -// return HSL; -// } - -//================================================= -// End Convert RGBtoHSL // - - -//================================================= -// Start Convert HSLtoRGB // -// export function convertHSLtoRGB(HSL: IColorHSL) { - -// const { hue, saturation, luminance } = HSL; - -// const h = hue; -// const s = saturation / 100.0; -// const l = luminance / 100.0; - -// const C = l * s; -// const hh = h / 60.0; -// const X = C * (1.0 - Math.abs((hh % 2) - 1.0)); - -// let r, g, b; -// r = g = b = 0; - -// if (hh >= 0 && hh < 1) { -// r = C; -// g = X; -// } else if (hh >= 1 && hh < 2) { -// r = X; -// g = C; -// } else if (hh >= 2 && hh < 3) { -// g = C; -// b = X; -// } else if (hh >= 3 && hh < 4) { -// g = X; -// b = C; -// } else if (hh >= 4 && hh < 5) { -// r = X; -// b = C; -// } else { -// r = C; -// b = X; -// } - -// const m = l - C; -// r += m; -// g += m; -// b += m; -// r *= 255.0; -// g *= 255.0; -// b *= 255.0; -// r = Math.floor(r); -// g = Math.floor(g); -// b = Math.floor(b); - -// let RGB = Object.assign({}, { red: r, green: g, blue: b }); -// return RGB; -// } -//================================================= -// End Convert HSLtoRGB // - -export function parseJson(value: string, replacement: T): T { - try { - return JSON.parse(value); - } catch (_error) { - return replacement; - } -} - -export function loadJson(file: string, replacement: T): T { - if (!existsSync(file)) { - return replacement; - } - return parseJson(readFileSync(file).toString(), replacement); -} - -/** - ** @calculateWhiteColor - * determine warmWhite/coldWhite values from hue - * the closer to 0/360 the weaker coldWhite brightness becomes - * the closer to 180 the weaker warmWhite brightness becomes - * the closer to 90/270 the stronger both warmWhite and coldWhite become simultaniously - */ -export function TBtoCCT(TB: IColorTB): IColorCCT { - let multiplier = 1; - let warmWhite = 0, coldWhite = 0; - const { temperature, brightness } = TB; - - if (temperature <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue - multiplier = ((temperature / 90)); - coldWhite = Math.round((255 * multiplier)); - warmWhite = 255; - } else if (temperature > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue - multiplier = (1 - (temperature - 270) / 90); - coldWhite = Math.round((255 * multiplier)); - warmWhite = 255; - } else if (temperature > 180 && temperature <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue - multiplier = ((temperature - 180) / 90); - warmWhite = Math.round((255 * multiplier)); - coldWhite = 255; - - } else if (temperature > 90 && temperature <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue - multiplier = (1 - (temperature - 90) / 90); - warmWhite = Math.round((255 * multiplier)); - coldWhite = 255; - } - const CCT = { warmWhite: Math.round((warmWhite * brightness) / 100), coldWhite: Math.round((coldWhite * brightness) / 100) } - return CCT -} //TBtoCCT - -/* -HSV to RGB conversion formula -When 0 ≤ H < 360, 0 ≤ S ≤ 1 and 0 ≤ V ≤ 1: -C = V × S -X = C × (1 - |(H / 60°) mod 2 - 1|) -m = V - C -(R,G,B) = ((R'+m)×255, (G'+m)×255, (B'+m)×255) -*/ - -export function HSVtoRGB(HSV: IColorHSV): IColorRGB { - const { hue, saturation, value }: IColorHSV = HSV; - let [H, S, V] = [hue, saturation, value]; - H = clamp(H, 0, 360) - S = clamp(S, 0, 100) - V = clamp(V, 0, 100) - - // console.log("-- SENDING -- H: ", H, "S: ", S, "V: ", V) - S /= 100.0 - V /= 100.0 - const C = V * S; - const X = C * (1 - Math.abs(((H / 60) % 2) - 1)); - const m = V - C; - - - let order; - if (H < 60) order = [C, X, 0]; - else if (H < 120) order = [X, C, 0]; - else if (H < 180) order = [0, C, X]; - else if (H < 240) order = [0, X, C]; - else if (H < 300) order = [X, 0, C]; - else if (H <= 360) order = [C, 0, X]; - - const [dR, dG, dB] = order; - const [red, green, blue] = [Math.round((dR + m) * 255), Math.round((dG + m) * 255), Math.round((dB + m) * 255)] - - // console.log(`--SENDING-- RED: ${red} GREEN: ${green} BLUE: ${blue}`) - return { red, green, blue }; -} - -export function RGBtoHSV(RGB: IColorRGB): IColorHSV { - - const { red, green, blue }: IColorRGB = RGB; - - // console.log(`--RECEIVING-- RED: ${red} GREEN: ${green} BLUE: ${blue}`) - - const [R, G, B] = [red, green, blue]; - const [dR, dG, dB] = [R / 255, G / 255, B / 255]; - - const Dmax = Math.max(dR, dG, dB); - const Dmin = Math.min(dR, dG, dB); - const D = Dmax - Dmin; - - let H, S, V; - if (D === 0) H = 0; - else if (Dmax === dR) H = ((dG - dB) / D) % 6; - else if (Dmax === dG) H = ((dB - dR) / D) + 2; - else H = ((dR - dG) / D) + 4 - H *= 60; - if (H < 0) H += 360; - V = Dmax; - if (V === 0) S = 0; - else S = D / V; - - - S *= 100; - V *= 100; - // console.log("-- RECEIVED -- H: ", H, "S: ", S, "V: ", V) - - return { hue: H, saturation: S, value: V }; -} - -export function temperatureToCCT(temperature: number, multiplier = 0): { warmWhite: number, coldWhite: number } { - let warmWhite, coldWhite; - - const threshold = 110; - if (temperature >= threshold) { - warmWhite = 127; - multiplier = (1 - ((temperature - threshold) / (360 - threshold))); - coldWhite = Math.round((127 * multiplier)); - } else { - coldWhite = 127; - multiplier = (temperature / threshold); - warmWhite = Math.round((127 * multiplier)); - } - - return { warmWhite, coldWhite }; -} - -export function CCTtoTB(CCT: IColorCCT): IColorTB { - const { warmWhite, coldWhite } = CCT; - const temperature = Math.round(coldWhite * 1.4117); - const brightness = Math.round(Math.max(warmWhite, coldWhite) / 2.55) - return { temperature, brightness }; -} - -/* -export function delayToSpeed(delay: never) { - let clamped = clamp(delay, 1, 31); - clamped -= 1; // bring into interval [0, 30] - return 100 - (clamped / 30) * 100; -} - -export function speedToDelay(speed: never) { - const clamped = clamp(speed, 0, 100); - return 30 - (clamped / 100) * 30 + 1; -} -*/ -// export function convertMiredColorTemperatureToHueSat(temperature: number): [number, number] { -// const xy = convertMiredColorTemperatureToXY(500 - temperature); -// return convertXyToHueSat(xy[0], xy[1]); -// } - -// export function convertXyToHueSat(x: number, y: number): [number, number] { -// // Based on: https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/ -// const z: number = 1.0 - x - y; -// const Y = 1.0; -// const X: number = (Y / y) * x; -// const Z: number = (Y / y) * z; - -// // sRGB D65 conversion -// let r: number = (X * 1.656492) - (Y * 0.354851) - (Z * 0.255038); -// let g: number = (-X * 0.707196) + (Y * 1.655397) + (Z * 0.036152); -// let b: number = (X * 0.051713) - (Y * 0.121364) + (Z * 1.011530); - -// // Remove negative values -// const m = Math.min(r, g, b); -// if (m < 0.0) { -// r -= m; -// g -= m; -// b -= m; -// } - -// // Normalize -// if (r > b && r > g && r > 1.0) { -// // red is too big -// g = g / r; -// b = b / r; -// r = 1.0; -// } else if (g > b && g > r && g > 1.0) { -// // green is too big -// r = r / g; -// b = b / g; -// g = 1.0; -// } else if (b > r && b > g && b > 1.0) { -// // blue is too big -// r = r / b; -// g = g / b; -// b = 1.0; -// } - -// // Gamma correction -// r = reverseGammaCorrection(r); -// g = reverseGammaCorrection(g); -// b = reverseGammaCorrection(b); - -// // Maximize -// const max = Math.max(r, g, b); -// r = (r === max) ? 255 : (255 * (r / max)); -// g = (g === max) ? 255 : (255 * (g / max)); -// b = (b === max) ? 255 : (255 * (b / max)); - -// const RGB: IColorRGB = { red: r, green: g, blue: b }; -// const HSL = convertRGBtoHSL(RGB); - -// const hsv = [HSL.hue, HSL.saturation]; - -// return [hsv[0], hsv[1]]; -// } - -function convertMiredColorTemperatureToXY(temperature: number): [number, number] { - // Based on MiredColorTemperatureToXY from: - // https://github.com/dresden-elektronik/deconz-rest-plugin/blob/78939ac4ee4b0646fbf542a0f6e83ee995f1a875/colorspace.cpp - const TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD = 4000; - - const TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD = 2222; - const TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD = 4000; - - const TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION = 17440695910400; - const TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION = 15358885888; - const TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION = 57520658; - const TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION = 11790; - - const TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION = 198301902438400; - const TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION = 138086835814; - const TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION = 14590587; - const TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION = 15754; - - const TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION = 18126; - const TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION = 22087; - const TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION = 35808; - const TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION = 3312; - - const TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION = 15645; - const TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION = 22514; - const TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION = 34265; - const TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION = 2744; - - const TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION = 50491; - const TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION = 96229; - const TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION = 61458; - const TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION = 6062; - - let localX = 0; - let localY = 0; - const temp = 1000000 / temperature; - - if (TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD > temp) { - localX = TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION / temp + - TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION - - TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION / temp / temp - - TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION / temp / temp / temp; - } else { - localX = TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION / temp / temp + - TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION / temp + - TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION - - TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION / temp / temp / temp; - } - - if (TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD > temp) { - localY = TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION * localX / 65536 - - TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION * localX * localX * localX / 281474976710656 - - TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION * localX * localX / 4294967296 - - TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION; - } else if (TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD > temp) { - localY = TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION * localX / 65536 - - TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION * localX * localX * localX / 281474976710656 - - TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION * localX * localX / 4294967296 - - TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION; - } else { - localY = TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION * localX / 65536 + - TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION * localX * localX * localX / 281474976710656 - - TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION * localX * localX / 4294967296 - - TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION; - } - - localY *= 4; - - localX /= 0xFFFF; - localY /= 0xFFFF; - - return [Math.round(localX * 10000) / 10000, Math.round(localY * 10000) / 10000]; -} - -function reverseGammaCorrection(v: number): number { - return (v <= 0.0031308) ? 12.92 * v : (1.0 + 0.055) * Math.pow(v, (1.0 / 2.4)) - 0.055; +import { existsSync, readFileSync } from 'fs'; +import { IColorCCT, IColorRGB, IDeviceCommand, IDeviceState } from 'magichome-platform'; +import { IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB } from './types'; + + +export function clamp(value: number, min: number, max: number) { + return Math.min(max, Math.max(min, value)); +} + + +//================================================= +// Start checksum // + + + +/** + * @checksum + * a checksum is needed at the end of the byte array otherwise the message is rejected by the device + * add all bytes and chop off the beginning by & with 0xFF + * @param buffer + * @returns checksum number + */ +export function checksum(buffer: Uint8Array) { + let chk = 0; + + for (const byte of buffer) { + chk += byte; + } + + return chk & 0xff; +} + +//================================================= +// Start Convert RGBtoHSL // +// export function convertRGBtoHSL(RGB: IColorRGB) { + +// const { red, green, blue } = RGB; + + +// const r = red / 255; +// const g = green / 255; +// const b = blue / 255; + +// let h, s, l; +// h = s = l = 0; + +// const max = Math.max(r, g, b); +// const min = Math.min(r, g, b); +// const C = max - min; +// if (C == 0) { +// h = 0; +// } else if (max == r) { +// h = ((g - b) / C) % 6; +// } else if (max == g) { +// h = (b - r) / C + 2; +// } else { +// h = (r - g) / C + 4; +// } +// h *= 60; +// if (h < 0) { +// h += 360; +// } +// l = max; +// if (l == 0) { +// s = 0; +// } else { +// s = C / l; +// } +// s *= 100; +// l *= 100; + +// const HSL: IColorHSL = { hue: Math.floor(h), saturation: Math.floor(s), luminance: Math.floor(l) }; +// return HSL; +// } + +//================================================= +// End Convert RGBtoHSL // + + +//================================================= +// Start Convert HSLtoRGB // +// export function convertHSLtoRGB(HSL: IColorHSL) { + +// const { hue, saturation, luminance } = HSL; + +// const h = hue; +// const s = saturation / 100.0; +// const l = luminance / 100.0; + +// const C = l * s; +// const hh = h / 60.0; +// const X = C * (1.0 - Math.abs((hh % 2) - 1.0)); + +// let r, g, b; +// r = g = b = 0; + +// if (hh >= 0 && hh < 1) { +// r = C; +// g = X; +// } else if (hh >= 1 && hh < 2) { +// r = X; +// g = C; +// } else if (hh >= 2 && hh < 3) { +// g = C; +// b = X; +// } else if (hh >= 3 && hh < 4) { +// g = X; +// b = C; +// } else if (hh >= 4 && hh < 5) { +// r = X; +// b = C; +// } else { +// r = C; +// b = X; +// } + +// const m = l - C; +// r += m; +// g += m; +// b += m; +// r *= 255.0; +// g *= 255.0; +// b *= 255.0; +// r = Math.floor(r); +// g = Math.floor(g); +// b = Math.floor(b); + +// let RGB = Object.assign({}, { red: r, green: g, blue: b }); +// return RGB; +// } +//================================================= +// End Convert HSLtoRGB // + +export function parseJson(value: string, replacement: T): T { + try { + return JSON.parse(value); + } catch (_error) { + return replacement; + } +} + +export function loadJson(file: string, replacement: T): T { + if (!existsSync(file)) { + return replacement; + } + return parseJson(readFileSync(file).toString(), replacement); +} + +/** + ** @calculateWhiteColor + * determine warmWhite/coldWhite values from hue + * the closer to 0/360 the weaker coldWhite brightness becomes + * the closer to 180 the weaker warmWhite brightness becomes + * the closer to 90/270 the stronger both warmWhite and coldWhite become simultaniously + */ +export function TBtoCCT(TB: IColorTB): IColorCCT { + let multiplier = 1; + let warmWhite = 0, coldWhite = 0; + let { temperature, brightness } = TB; + temperature -= 140; + + if (temperature <= 90) { //if hue is <= 90, warmWhite value is full and we determine the coldWhite value based on Hue + multiplier = ((temperature / 90)); + coldWhite = Math.round((255 * multiplier)); + warmWhite = 255; + } else if (temperature > 270) { //if hue is >270, warmWhite value is full and we determine the coldWhite value based on Hue + multiplier = (1 - (temperature - 270) / 90); + coldWhite = Math.round((255 * multiplier)); + warmWhite = 255; + } else if (temperature > 180 && temperature <= 270) { //if hue is > 180 and <= 270, coldWhite value is full and we determine the warmWhite value based on Hue + multiplier = ((temperature - 180) / 90); + warmWhite = Math.round((255 * multiplier)); + coldWhite = 255; + + } else if (temperature > 90 && temperature <= 180) {//if hue is > 90 and <= 180, coldWhite value is full and we determine the warmWhite value based on Hue + multiplier = (1 - (temperature - 90) / 90); + warmWhite = Math.round((255 * multiplier)); + coldWhite = 255; + } + const CCT = { warmWhite: Math.round((warmWhite * brightness) / 100), coldWhite: Math.round((coldWhite * brightness) / 100) } + return CCT +} //TBtoCCT + +export function CCTtoTB(CCT: IColorCCT): IColorTB { + const { warmWhite, coldWhite } = CCT; + let temperature = 0; + let brightness = 0; + + // Calculate the total CCT value + const totalCCT = warmWhite + coldWhite; + + // Calculate the temperature based on the total CCT value + if (totalCCT <= 255) { + temperature = 90 + Math.round((totalCCT / 255) * 90); + } else if (totalCCT > 255 && totalCCT <= 510) { + temperature = 180 + Math.round(((totalCCT - 255) / 255) * 90); + } + + // Calculate the brightness based on the coldWhite value + brightness = Math.round((coldWhite / 255) * 100); + + // Return the temperature and brightness as a TB value + return { temperature, brightness }; +} + + +/* +HSV to RGB conversion formula +When 0 ≤ H < 360, 0 ≤ S ≤ 1 and 0 ≤ V ≤ 1: +C = V × S +X = C × (1 - |(H / 60°) mod 2 - 1|) +m = V - C +(R,G,B) = ((R'+m)×255, (G'+m)×255, (B'+m)×255) +*/ + +export function HSVtoRGB(HSV: IColorHSV): IColorRGB { + const { hue, saturation, value }: IColorHSV = HSV; + let [H, S, V] = [hue, saturation, value]; + H = clamp(H, 0, 360) + S = clamp(S, 0, 100) + V = clamp(V, 0, 100) + + // console.log("-- SENDING -- H: ", H, "S: ", S, "V: ", V) + S /= 100.0 + V /= 100.0 + const C = V * S; + const X = C * (1 - Math.abs(((H / 60) % 2) - 1)); + const m = V - C; + + + let order; + if (H < 60) order = [C, X, 0]; + else if (H < 120) order = [X, C, 0]; + else if (H < 180) order = [0, C, X]; + else if (H < 240) order = [0, X, C]; + else if (H < 300) order = [X, 0, C]; + else if (H <= 360) order = [C, 0, X]; + + const [dR, dG, dB] = order; + const [red, green, blue] = [Math.round((dR + m) * 255), Math.round((dG + m) * 255), Math.round((dB + m) * 255)] + + // console.log(`--SENDING-- RED: ${red} GREEN: ${green} BLUE: ${blue}`) + return { red, green, blue }; +} + +export function RGBtoHSV(RGB: IColorRGB): IColorHSV { + + const { red, green, blue }: IColorRGB = RGB; + + // console.log(`--RECEIVING-- RED: ${red} GREEN: ${green} BLUE: ${blue}`) + + const [R, G, B] = [red, green, blue]; + const [dR, dG, dB] = [R / 255, G / 255, B / 255]; + + const Dmax = Math.max(dR, dG, dB); + const Dmin = Math.min(dR, dG, dB); + const D = Dmax - Dmin; + + let H, S, V; + if (D === 0) H = 0; + else if (Dmax === dR) H = ((dG - dB) / D) % 6; + else if (Dmax === dG) H = ((dB - dR) / D) + 2; + else H = ((dR - dG) / D) + 4 + H *= 60; + if (H < 0) H += 360; + V = Dmax; + if (V === 0) S = 0; + else S = D / V; + + + S *= 100; + V *= 100; + // console.log("-- RECEIVED -- H: ", H, "S: ", S, "V: ", V) + + return { hue: H, saturation: S, value: V }; +} + +// export function TBtoCCT(tb: { temperature: number, brightness: number }): { warmWhite: number, coldWhite: number } { +// const minCCT = 0; +// const maxCCT = 255; +// const minTemperature = 140; +// const maxTemperature = 500; +// const minColdWhite = 0; +// const maxColdWhite = 255; +// const minBrightness = 0; +// const maxBrightness = 100; + +// const totalCCT = (tb.temperature - minTemperature) * (maxCCT - minCCT) / (maxTemperature - minTemperature) + minCCT; +// const coldWhite = (tb.brightness - minBrightness) * (maxColdWhite - minColdWhite) / (maxBrightness - minBrightness) + minColdWhite; +// const warmWhite = totalCCT - coldWhite; + +// return { warmWhite: warmWhite, coldWhite: coldWhite }; +// } + + +// export function CCTtoTB(cct: { warmWhite: number, coldWhite: number }): { temperature: number, brightness: number } { +// const minCCT = 0; +// const maxCCT = 255; +// const minTemperature = 140; +// const maxTemperature = 500; +// const minColdWhite = 0; +// const maxColdWhite = 255; +// const minBrightness = 0; +// const maxBrightness = 100; + +// const totalCCT = cct.warmWhite + cct.coldWhite; +// const temperature = (totalCCT - minCCT) * (maxTemperature - minTemperature) / (maxCCT - minCCT) + minTemperature; +// const brightness = (cct.coldWhite - minColdWhite) * (maxBrightness - minBrightness) / (maxColdWhite - minColdWhite) + minBrightness; + +// return { temperature, brightness }; +// } + +// export function CCTtoTB(CCT: IColorCCT): IColorTB { +// const { warmWhite, coldWhite } = CCT; +// const temperature = Math.round(coldWhite * 1.4117); +// const brightness = Math.round(Math.max(warmWhite, coldWhite) / 2.55) +// return { temperature, brightness }; +// } + +/* +export function delayToSpeed(delay: never) { + let clamped = clamp(delay, 1, 31); + clamped -= 1; // bring into interval [0, 30] + return 100 - (clamped / 30) * 100; +} + +export function speedToDelay(speed: never) { + const clamped = clamp(speed, 0, 100); + return 30 - (clamped / 100) * 30 + 1; +} +*/ +// export function convertMiredColorTemperatureToHueSat(temperature: number): [number, number] { +// const xy = convertMiredColorTemperatureToXY(500 - temperature); +// return convertXyToHueSat(xy[0], xy[1]); +// } + +// export function convertXyToHueSat(x: number, y: number): [number, number] { +// // Based on: https://developers.meethue.com/develop/application-design-guidance/color-conversion-formulas-rgb-to-xy-and-back/ +// const z: number = 1.0 - x - y; +// const Y = 1.0; +// const X: number = (Y / y) * x; +// const Z: number = (Y / y) * z; + +// // sRGB D65 conversion +// let r: number = (X * 1.656492) - (Y * 0.354851) - (Z * 0.255038); +// let g: number = (-X * 0.707196) + (Y * 1.655397) + (Z * 0.036152); +// let b: number = (X * 0.051713) - (Y * 0.121364) + (Z * 1.011530); + +// // Remove negative values +// const m = Math.min(r, g, b); +// if (m < 0.0) { +// r -= m; +// g -= m; +// b -= m; +// } + +// // Normalize +// if (r > b && r > g && r > 1.0) { +// // red is too big +// g = g / r; +// b = b / r; +// r = 1.0; +// } else if (g > b && g > r && g > 1.0) { +// // green is too big +// r = r / g; +// b = b / g; +// g = 1.0; +// } else if (b > r && b > g && b > 1.0) { +// // blue is too big +// r = r / b; +// g = g / b; +// b = 1.0; +// } + +// // Gamma correction +// r = reverseGammaCorrection(r); +// g = reverseGammaCorrection(g); +// b = reverseGammaCorrection(b); + +// // Maximize +// const max = Math.max(r, g, b); +// r = (r === max) ? 255 : (255 * (r / max)); +// g = (g === max) ? 255 : (255 * (g / max)); +// b = (b === max) ? 255 : (255 * (b / max)); + +// const RGB: IColorRGB = { red: r, green: g, blue: b }; +// const HSL = convertRGBtoHSL(RGB); + +// const hsv = [HSL.hue, HSL.saturation]; + +// return [hsv[0], hsv[1]]; +// } + +function convertMiredColorTemperatureToXY(temperature: number): [number, number] { + // Based on MiredColorTemperatureToXY from: + // https://github.com/dresden-elektronik/deconz-rest-plugin/blob/78939ac4ee4b0646fbf542a0f6e83ee995f1a875/colorspace.cpp + const TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD = 4000; + + const TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD = 2222; + const TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD = 4000; + + const TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION = 17440695910400; + const TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION = 15358885888; + const TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION = 57520658; + const TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION = 11790; + + const TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION = 198301902438400; + const TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION = 138086835814; + const TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION = 14590587; + const TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION = 15754; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION = 18126; + const TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION = 22087; + const TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION = 35808; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION = 3312; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION = 15645; + const TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION = 22514; + const TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION = 34265; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION = 2744; + + const TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION = 50491; + const TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION = 96229; + const TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION = 61458; + const TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION = 6062; + + let localX = 0; + let localY = 0; + const temp = 1000000 / temperature; + + if (TEMPERATURE_TO_X_TEMPERATURE_THRESHOLD > temp) { + localX = TEMPERATURE_TO_X_THIRD_FACTOR_FIRST_EQUATION / temp + + TEMPERATURE_TO_X_FOURTH_FACTOR_FIRST_EQUATION - + TEMPERATURE_TO_X_SECOND_FACTOR_FIRST_EQUATION / temp / temp - + TEMPERATURE_TO_X_FIRST_FACTOR_FIRST_EQUATION / temp / temp / temp; + } else { + localX = TEMPERATURE_TO_X_SECOND_FACTOR_SECOND_EQUATION / temp / temp + + TEMPERATURE_TO_X_THIRD_FACTOR_SECOND_EQUATION / temp + + TEMPERATURE_TO_X_FOURTH_FACTOR_SECOND_EQUATION - + TEMPERATURE_TO_X_FIRST_FACTOR_SECOND_EQUATION / temp / temp / temp; + } + + if (TEMPERATURE_TO_Y_FIRST_TEMPERATURE_THRESHOLD > temp) { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_FIRST_EQUATION * localX / 65536 - + TEMPERATURE_TO_Y_FIRST_FACTOR_FIRST_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_FIRST_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_FIRST_EQUATION; + } else if (TEMPERATURE_TO_Y_SECOND_TEMPERATURE_THRESHOLD > temp) { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_SECOND_EQUATION * localX / 65536 - + TEMPERATURE_TO_Y_FIRST_FACTOR_SECOND_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_SECOND_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_SECOND_EQUATION; + } else { + localY = TEMPERATURE_TO_Y_THIRD_FACTOR_THIRD_EQUATION * localX / 65536 + + TEMPERATURE_TO_Y_FIRST_FACTOR_THIRD_EQUATION * localX * localX * localX / 281474976710656 - + TEMPERATURE_TO_Y_SECOND_FACTOR_THIRD_EQUATION * localX * localX / 4294967296 - + TEMPERATURE_TO_Y_FOURTH_FACTOR_THIRD_EQUATION; + } + + localY *= 4; + + localX /= 0xFFFF; + localY /= 0xFFFF; + + return [Math.round(localX * 10000) / 10000, Math.round(localY * 10000) / 10000]; +} + +function reverseGammaCorrection(v: number): number { + return (v <= 0.0031308) ? 12.92 * v : (1.0 + 0.055) * Math.pow(v, (1.0 / 2.4)) - 0.055; } \ No newline at end of file diff --git a/src/platform.ts b/src/platform.ts index b96b682..e323b6c 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -1,124 +1,124 @@ -import { join } from 'path'; -import { loadJson } from './misc/utils'; -import { Logs } from './logs'; -import { - API, - APIEvent, - DynamicPlatformPlugin, - HAP, - Logging, - PlatformConfig, -} from 'homebridge'; - -import { ControllerGenerator } from 'magichome-platform'; -// import { AnimationGenerator } from './AnimationGenerator' -import { AnimationAccessory, MagicHomeAccessory } from './misc/types'; -import { AccessoryGenerator } from './AccessoryGenerator'; -import { AnimationGenerator } from './AnimationGenerator'; -import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; -/** - */ - -const controllerGenerator = new ControllerGenerator(); - -/** - * HomebridgePlatform - * This class is the main constructor for your plugin, this is where you should - * parse the user config and discover/register accessories with Homebridge. - */ -export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { - private readonly api: API; - // this is used to track restored cached accessories - - - public count = 1; - - private periodicDiscovery: NodeJS.Timeout | null = null; - protected hap: HAP; - - public readonly config: PlatformConfig; - public readonly accessoriesFromDiskMap: Map = new Map(); - private readonly hbLogger: Logging; - private readonly log: Logs; - animationsFromDiskMap:Map = new Map(); - constructor( - logging: Logging, - config: PlatformConfig, - api: API, - ) { - this.hbLogger = logging; - this.api = api; - this.hap = api.hap; - this.config = config; - this.log = new Logs(logging, config?.globalAccessoryOptions?.logLevel ?? 3); - //this.logs = getLogger(); - this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); - this.log.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); - - // When this event is fired it means Homebridge has restored all cached accessories from disk. - // Dynamic Platform plugins should only register new accessories after this event was fired, - // in order to ensure they weren't added to homebridge already. This event can also be used - // to start discovery of new accessories. - - api.on(APIEvent.DID_FINISH_LAUNCHING, () => { - this.log.debug('Homebridge Magichome Dynamic Platform didFinishLaunching'); - this.initializePlatform(); - }); - } - - - /** - * This function is invoked when homebridge restores cached accessories from disk at startup. - * It should be used to setup event handlers for characteristics and update respective values. - */ - configureAccessory(accessory) { - - // set cached accessory as not recently seen - // if found later to be a match with a discovered device, will change to true - // accessory.context.scansSinceSeen++; - // accessory.context.pendingRegistration = true; - // // add the restored accessory to the accessories cache so we can track if it has already been registered - if (typeof accessory.context.protoDevice != 'undefined') { - const homebridgeUUID = accessory.context.protoDevice?.uniqueId; - this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); - this.log.info(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); - } else { - const homebridgeUUID = this.hap.uuid.generate(accessory.context.animationLoop.name); - - // const homebridgeUUID = accessory.context.animationLoop; - - this.animationsFromDiskMap.set(homebridgeUUID, accessory); - } - - - } - - /** - * Accessories are added by one of three Methods: - * Method One: New devices that were seen after scanning the network and are registered for the first time - * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies - * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user - */ - async initializePlatform() { - // const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; - // const pendingUpdate = new Set(); - // const recentlyRegisteredDevices = new Set(); - - // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; - - - const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); - const activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] = await accesssoryGenerator.discoverDevices(); - const animationGenerator = new AnimationGenerator(this.api, this.log, this.hbLogger, this.config, this.animationsFromDiskMap, activeAccessories); - animationGenerator.generateActiveAccessories(); - // this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); - - } - - - // sanitizeConfig() { - // //recursive config sanitation - // } - - +import { join } from 'path'; +import { loadJson } from './misc/utils'; +import { Logs } from './logs'; +import { + API, + APIEvent, + DynamicPlatformPlugin, + HAP, + Logging, + PlatformConfig, +} from 'homebridge'; + +import { ControllerGenerator } from 'magichome-platform'; +// import { AnimationGenerator } from './AnimationGenerator' +import { AnimationAccessory, MagicHomeAccessory } from './misc/types'; +import { AccessoryGenerator } from './AccessoryGenerator'; +import { AnimationGenerator } from './AnimationGenerator'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; +/** + */ + +const controllerGenerator = new ControllerGenerator(); + +/** + * HomebridgePlatform + * This class is the main constructor for your plugin, this is where you should + * parse the user config and discover/register accessories with Homebridge. + */ +export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin { + private readonly api: API; + // this is used to track restored cached accessories + + + public count = 1; + + private periodicDiscovery: NodeJS.Timeout | null = null; + protected hap: HAP; + + public readonly config: PlatformConfig; + public readonly accessoriesFromDiskMap: Map = new Map(); + private readonly hbLogger: Logging; + private readonly log: Logs; + animationsFromDiskMap:Map = new Map(); + constructor( + logging: Logging, + config: PlatformConfig, + api: API, + ) { + this.hbLogger = logging; + this.api = api; + this.hap = api.hap; + this.config = config; + this.log = new Logs(logging, config?.globalAccessoryOptions?.logLevel ?? 3); + //this.logs = getLogger(); + this.log.warn('Finished initializing homebridge-magichome-dynamic-platform %o', loadJson(join(__dirname, '../package.json'), {}).version); + this.log.info('If this plugin brings you joy, consider visiting GitHub and giving it a ⭐.'); + + // When this event is fired it means Homebridge has restored all cached accessories from disk. + // Dynamic Platform plugins should only register new accessories after this event was fired, + // in order to ensure they weren't added to homebridge already. This event can also be used + // to start discovery of new accessories. + + api.on(APIEvent.DID_FINISH_LAUNCHING, () => { + this.log.debug('Homebridge Magichome Dynamic Platform didFinishLaunching'); + this.initializePlatform(); + }); + } + + + /** + * This function is invoked when homebridge restores cached accessories from disk at startup. + * It should be used to setup event handlers for characteristics and update respective values. + */ + configureAccessory(accessory) { + + // set cached accessory as not recently seen + // if found later to be a match with a discovered device, will change to true + // accessory.context.scansSinceSeen++; + // accessory.context.pendingRegistration = true; + // // add the restored accessory to the accessories cache so we can track if it has already been registered + if (typeof accessory.context.protoDevice != 'undefined') { + const homebridgeUUID = accessory.context.protoDevice?.uniqueId; + this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); + this.log.info(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); + } else { + const homebridgeUUID = this.hap.uuid.generate(accessory.context.animationLoop.name); + + // const homebridgeUUID = accessory.context.animationLoop; + + this.animationsFromDiskMap.set(homebridgeUUID, accessory); + } + + + } + + /** + * Accessories are added by one of three Methods: + * Method One: New devices that were seen after scanning the network and are registered for the first time + * Method Two: Cached devices that were seen after scanning the network and are added while checking for ip discrepancies + * Method Three: Cached devices that were not seen after scanning the network but are still added with a warning to the user + */ + async initializePlatform() { + // const { isValidDeviceModel } = HomebridgeMagichomeDynamicPlatform; + // const pendingUpdate = new Set(); + // const recentlyRegisteredDevices = new Set(); + + // let registeredDevices = 0, newDevices = 0, unseenDevices = 0, scans = 0; + + + const accesssoryGenerator = new AccessoryGenerator(this.api, this.log, this.hbLogger, this.config, this.accessoriesFromDiskMap, controllerGenerator); + const activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] = await accesssoryGenerator.discoverDevices(); + const animationGenerator = new AnimationGenerator(this.api, this.log, this.hbLogger, this.config, this.animationsFromDiskMap, activeAccessories); + animationGenerator.generateActiveAccessories(); + // this.periodicDiscovery = setInterval(() => accesssoryGenerator.rescanAccessories(), 30000); + + } + + + // sanitizeConfig() { + // //recursive config sanitation + // } + + }//ZackneticMagichomePlatform class \ No newline at end of file diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 3be6d78..c1ea036 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -3,7 +3,7 @@ import type { CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, } from 'homebridge'; -import { temperatureToCCT, clamp, TBtoCCT, HSVtoRGB, RGBtoHSV, CCTtoTB } from './misc/utils'; +import { clamp, TBtoCCT, HSVtoRGB, RGBtoHSV, CCTtoTB } from './misc/utils'; import { AnimationAccessory, DEFAULT_ACCESSORY_COMMAND, DEFAULT_ACCESSORY_STATE, IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB, IConfigOptions, IPartialAccessoryCommand, MagicHomeAccessory } from './misc/types'; // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE, COLOR_MASKS } from 'magichome-platform'; @@ -38,19 +38,22 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected deviceReadStatus = 'ready'; protected readRequestLevel = 0; - protected recentlyControlled: boolean = false; - protected currentlyAnimating: boolean = false; + protected recentlyControlled = false; + protected currentlyAnimating = false; protected currentAnimator: AnimationAccessory = null; protected queue; - protected slowQueueRetry = false; protected lastValue: number; lastHue: number; lastBrightness: number; waitingSendoff: boolean; resistOff: boolean; - brightnessTimeout: NodeJS.Timeout; + HSVTimeout: NodeJS.Timeout; powerTimeout: NodeJS.Timeout; + isCountingTime: boolean; + timeout: NodeJS.Timeout; + processAccessoryCommandTimeout: NodeJS.Timeout; + service2: any; //================================================= // Start Constructor // @@ -65,111 +68,232 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { ) { this.setupMisc(); - this.accessoryState = DEFAULT_ACCESSORY_STATE; + this.accessoryState = mergeDeep({}, DEFAULT_ACCESSORY_STATE); this.logs = logs; this.controller = controller; this.hap = api.hap; this.api = api; this.config = config; this.initializeCharacteristics(); - this.fetchAndUpdateState(2); + this.fetchDeviceState(2); + this.isCountingTime = false; + this.lastValue = this.accessoryState.HSV.value; + this.periodicScan(); } - //================================================= - // End Constructor // + async periodicScan() { + while (true) { + await new Promise(resolve => setTimeout(resolve, 5000, + )); + this.fetchDeviceState(2, true); + } + } + + // setOn(value: CharacteristicValue) { + // if (!this.isCountingTime) { + // this.isCountingTime = true; + // console.time('setters'); + // console.timeLog('setters'); + // console.log('setters: isOn: ', value); + // } else { + // console.timeLog('setters'); + // console.log('setters: isOn: ', value); + // } + // this.startResetTimeout(); + // } + + // setHue(value: CharacteristicValue) { + // if (!this.isCountingTime) { + // this.isCountingTime = true; + // console.time('setters'); + // console.timeLog('setters'); + // console.log('setters: setHue: ', value); + // } else { + // console.timeLog('setters'); + // console.log('setters: setHue: ', value); + // } + // this.startResetTimeout(); + // } + + // setSaturation(value: CharacteristicValue) { + // if (!this.isCountingTime) { + // this.isCountingTime = true; + // console.time('setters'); + // console.timeLog('setters'); + // console.log('setters: setSaturation: ', value); + // } else { + // console.timeLog('setters'); + // console.log('setters: setSaturation: ', value); + // } + // this.startResetTimeout(); + // } + + // setValue(value: CharacteristicValue) { + // if (!this.isCountingTime) { + // this.isCountingTime = true; + // console.time('setters'); + // console.timeLog('setters'); + // console.log('setters: setValue: ', value); + // } else { + // console.timeLog('setters'); + // console.log('setters: setValue: ', value); + // } + // this.startResetTimeout(); + // } + + // startResetTimeout() { + // clearTimeout(this.timeout); + // this.timeout = setTimeout(() => { + // console.timeEnd('setters'); + // console.log('reset setters boolean'); + // this.isCountingTime = false; + // }, 3000); + // } - //================================================= - // Start Setters // setOn(value: CharacteristicValue) { this.powerTimeout = setTimeout(() => { if (!this.resistOff) { const partialAccessoryCommand: IPartialAccessoryCommand = { isOn: value as boolean, isPowerCommand: true }; this.processAccessoryCommand(partialAccessoryCommand); } - }, 100); + }, 20); } setHue(value: CharacteristicValue) { + this.resistSetOnCommand() this.accessoryState.HSV.hue = value as number; const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { hue: value as number } }; - this.processAccessoryCommand(partialAccessoryCommand); } setSaturation(value: CharacteristicValue) { - + this.resistSetOnCommand() this.accessoryState.HSV.saturation = value as number; const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { saturation: value as number } }; this.processAccessoryCommand(partialAccessoryCommand); } - setBrightness(value: CharacteristicValue) { - clearTimeout(this.brightnessTimeout) - clearTimeout(this.powerTimeout) - this.resistOff = true; - this.brightnessTimeout = setTimeout(() => { - this.resistOff = false; - }, 100); - + setValue(value: CharacteristicValue) { + this.resistSetOnCommand() this.accessoryState.HSV.value = value as number; const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { value: value as number } }; this.processAccessoryCommand(partialAccessoryCommand); } - // setColorTemperature(value: CharacteristicValue) { - // this.ColorCommandMode = CCT; - // const accessoryCommand: IAccessoryCommand = { colorTemperature: value as number }; - // this.processAccessoryCommand(accessoryCommand); + // setBrightness2(value: CharacteristicValue) { + // this.resistSetOnCommand() + // this.accessoryState.TB.brightness = value as number; + // const partialAccessoryCommand: IPartialAccessoryCommand = { TB: { brightness: value as number } }; + // this.processAccessoryCommand(partialAccessoryCommand); // } + setColorTemperature(value: CharacteristicValue) { + this.resistSetOnCommand() + this.accessoryState.TB.temperature = value as number; + const partialAccessoryCommand: IPartialAccessoryCommand = { TB: { temperature: value as number } }; + console.log('set color temp', value) + this.processAccessoryCommand(partialAccessoryCommand); + } + setConfiguredName(value: CharacteristicValue) { const name: string = value.toString(); - this.logs.warn(`Renaming device to ${name}`,); + this.logs.warn(`Renaming device to ${name}`); this.accessory.context.displayName = name; this.api.updatePlatformAccessories([this.accessory]); } + resistSetOnCommand() { + this.resistOff = true; + clearTimeout(this.HSVTimeout); + clearTimeout(this.powerTimeout); + this.HSVTimeout = setTimeout(() => { + this.resistOff = false; + }, 50); + } + identifyLight() { this.flashEffect(); } - //================================================= - // End Setters // + getHue() { + return new Promise((resolve, reject) => { + setTimeout(async () => { + try { + const { HSV: { hue }, TB: { temperature } } = await this.fetchDeviceState(5, false); + this.logValue('getHue', hue); + resolve(hue); + } catch (error) { + console.log('getHue Error: ', error) + + } + }, 50) + }); + } - //================================================= - // Start Getters // + getSaturation() { + return new Promise((resolve, reject) => { + setTimeout(async () => { + try { + const { HSV: { saturation }, TB: { temperature } } = await this.fetchDeviceState(5, false); + this.logValue('getSaturation', saturation); + resolve(saturation); + } catch (error) { + console.log('getSaturation Error: ', error) + + } + }, 50) + }); + } - getHue() { - const { HSV: { hue }, TB: { temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - this.fetchAndUpdateState(2); - return hue; + getValue() { + return new Promise((resolve, reject) => { + setTimeout(async () => { + try { + const { HSV: { value }, TB: { temperature } } = await this.fetchDeviceState(5, false); + this.logValue('getValue', value); + resolve(value); + } catch (error) { + console.log('getValue Error: ', error) + + } + }, 50) + }); } - // getColorTemperature() { - // const { isOn, HSV: { hue, saturation }, brightness, colorTemperature } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState) + getOn() { + return new Promise((resolve, reject) => { + setTimeout(async () => { + try { + const { isOn } = await this.fetchDeviceState(5, false); + this.logValue('isOn', isOn); + resolve(isOn); + } catch (error) { + console.log('isOn Error: ', error) + } + }, 50) + }); + } - // this.fetchAndUpdateState(3); - // return colorTemperature; - // } + // getBrightness2() { - getBrightness() { - const { HSV: { value }, TB: { brightness } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + // const { HSV: { value }, TB: { brightness } } = this.deviceStateToAccessoryState(this.controller.getLastOutboundState()); + // console.log(this.controller.getLastOutboundState()) + // this.fetchAndUpdateState(5); + // return value; + // } - this.fetchAndUpdateState(2); - return value; + getColorTemperature() { + const { HSV: { hue }, TB: { temperature } } = this.deviceStateToAccessoryState(this.controller.getLastOutboundState()); + this.fetchDeviceState(5); + return temperature; } - /** - ** @getOn - * instantly retrieve the current on/off state stored in our object - * next call this.getState() which will update all values asynchronously as they are ready - */ - async getOn() { - const { isOn } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - this.fetchAndUpdateState(2); - return isOn; + + + logValue(valueType: string, value: any) { + console.log(`${valueType} value: ${value}`); } flashEffect() { @@ -181,20 +305,25 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //TODO, Severe! Bundle commands so that close consecutive changes in hue, sat, and brightness aren't sent as separate commands protected processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { + if (this.waitingSendoff) { + return; + } try { - - this.setRecentlyControlled(); - this.waitingSendoff = false; - const sanitizedAcessoryCommand = this.completeAccessoryCommand(partialAccessoryCommand); - if (partialAccessoryCommand.isPowerCommand) { - this.controller.setOn(sanitizedAcessoryCommand.isOn); - } else { - const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); - this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand); - } + this.waitingSendoff = true; + this.processAccessoryCommandTimeout = setTimeout(() => { + this.waitingSendoff = false; + const sanitizedAcessoryCommand = this.completeAccessoryCommand(partialAccessoryCommand); + if (partialAccessoryCommand.isPowerCommand) { + this.controller.setOn(sanitizedAcessoryCommand.isOn); + } else { + const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); + console.log(deviceCommand) + this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand); + } + }, 10); } catch (error) { - console.log('processAccessoryCommand: ', error) + console.log('processAccessoryCommand: ', error); } } @@ -210,31 +339,38 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): { deviceCommand: IDeviceCommand, commandOptions: ICommandOptions } { let { isOn, HSV: { hue, saturation, value }, TB } = accessoryCommand; const { temperature, brightness } = TB; - - - if (Math.max(brightness, value) > 0) isOn = true; - const commandOptions: ICommandOptions = { colorAssist: true, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; + if (Math.max(brightness, value) > 0) { + isOn = true; + } + const commandOptions: ICommandOptions = { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; let red, green, blue, warmWhite, coldWhite, colorMask = null; - colorMask = COLOR_MASKS.BOTH + colorMask = COLOR_MASKS.BOTH; + if (this.controller.getCachedDeviceInformation().deviceAPI.simultaneousCCT) { + ({ warmWhite, coldWhite } = TBtoCCT({ temperature, brightness })); + ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value })); + } else { + if (saturation < 95) { - if (saturation < 95) { - ({ warmWhite, coldWhite } = TBtoCCT({ temperature: hue, brightness: value })); + ({ warmWhite, coldWhite } = TBtoCCT({ temperature: hue + 140, brightness: value })); + ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value: this.lastValue })); + console.log(red, green, blue, warmWhite, coldWhite) + if (saturation < 5) { + this.lastValue = value; + red = 0, green = 0, blue = 0; + colorMask = COLOR_MASKS.WHITE; + } - ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value: this.lastValue })); - if (saturation < 5) { - red = 0, green = 0, blue = 0; - colorMask = COLOR_MASKS.WHITE + } else { + colorMask = COLOR_MASKS.COLOR; + this.lastValue = value; + ({ red, green, blue } = HSVtoRGB({ hue, saturation, value })); + warmWhite = 0; + coldWhite = 0; } - - } else { - colorMask = COLOR_MASKS.COLOR; - this.lastValue = value; - ({ red, green, blue } = HSVtoRGB({ hue, saturation, value })); - warmWhite = 0; - coldWhite = 0; } + const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, colorMask, CCT: { warmWhite, coldWhite } }; return { deviceCommand, commandOptions }; } @@ -242,47 +378,17 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected sendCommand(deviceCommand: IDeviceCommand, commandOptions: ICommandOptions, accessoryCommand) { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); try { - this.controller.setAllValues(deviceCommand, commandOptions).catch(e => {this.logs.warn(e)}) + this.controller.setAllValues(deviceCommand, commandOptions); } catch (error) { - console.log(error) + console.log("sendCommand ERROR: ", error); } this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`); } - - - protected async updateLocalState(requestLevel, deviceState) { - - if (!deviceState) deviceState = await this.controller.fetchState().then(res => res).catch(e => { this.logs.warn(e) }); - - this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); - // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; - const { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); - let accessoryState: IAccessoryState; - if (deviceState) { - switch (requestLevel) { - case 0: - // accessoryState = { HSV: { value }, isOn }; - break; - case 1: - // accessoryState = { HSV: { hue, value }, isOn }; - break; - case 2: - accessoryState = { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } }; - break; - case 3: - accessoryState = { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } }; - break; - } - this.accessoryState = accessoryState; - // console.log(accessoryState) - this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); - } - } - - updateHomekitState() { - let { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - + updateStateHomekitCharacteristic(deviceState: IDeviceState) { + console.log(deviceState) + const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); + console.log(isOn, hue, saturation, value, brightness, temperature) this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSV.saturation); this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); @@ -290,23 +396,38 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { - if (!deviceState) throw 'device state not provided'; - let { RGB, CCT, isOn } = deviceState; - const HSV: IColorHSV = RGBtoHSV(RGB); - const TB: IColorTB = CCTtoTB(CCT); + if (!deviceState) { + throw 'device state not provided'; + } + const { RGB, CCT, isOn } = deviceState; + const { red, green, blue } = RGB; + const { deviceAPI: { hasBrightness, hasCCT, hasColor, simultaneousCCT } } = this.controller.getCachedDeviceInformation(); + + let TB: IColorTB; + let HSV: IColorHSV; + + HSV = RGBtoHSV(RGB); + TB = CCTtoTB(CCT); + if (!simultaneousCCT) { + if (Math.max(red, green, blue) <= 0) { + HSV = { hue: 5, saturation: 4, value: TB.brightness } + } + } const accessoryState: IAccessoryState = { HSV, TB, isOn }; return accessoryState; } initializeCharacteristics() { - const cachedDeviceInformation = this.controller.getCachedDeviceInformation(); - const { deviceAPI: { hasBrightness, hasCCT, hasColor } } = cachedDeviceInformation; + const { deviceAPI: { hasBrightness, hasCCT, hasColor, simultaneousCCT } } = this.controller.getCachedDeviceInformation(); this.addAccessoryInformationCharacteristic(); this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); + // if (simultaneousCCT) { + // this.service2 = this.accessory.getService('Light Bulb 1') ?? this.accessory.addService(this.hap.Service.Lightbulb, 'Light Bulb 1', 'subtype1'); + // } if (hasColor) { this.addHueCharacteristic(); @@ -317,8 +438,8 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.addBrightnessCharacteristic(); } - if (hasCCT) { - // this.addColorTemperatureCharacteristic(); + if (simultaneousCCT) { + this.addColorTemperatureCharacteristic(); } if (!hasBrightness) { @@ -341,16 +462,33 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } - async fetchAndUpdateState(requestLevel) { + public async fetchDeviceState(attempts = 1, updateHomekit = false) { + let deviceState: IDeviceState; + let accessoryState: IAccessoryState; try { - this.readRequestLevel = requestLevel; - await this.updateLocalState(this.readRequestLevel, null).catch(e => { console.log('fetchAndUpdateState ERROR', e) }); - this.updateHomekitState(); + deviceState = await this.controller.fetchState(); + accessoryState = this.deviceStateToAccessoryState(deviceState); + this.accessoryState = accessoryState; + if (updateHomekit) { + this.updateStateHomekitCharacteristic(deviceState); + } } catch (error) { - this.hbLogger.error(error); + console.log("fetchDeviceState ERROR: ", error); + if (attempts > 0) { + setTimeout(() => { + this.fetchDeviceState(attempts - 1), updateHomekit; + }, 500); + } else { + this.hbLogger.error(`Failed to fetch and update state for ${this.accessory.displayName}: ${error}`); + } + } + if (!deviceState) { + return this.accessoryState; } + return accessoryState; } + getController() { return this.controller; } @@ -372,30 +510,36 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { addSaturationCharacteristic() { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Saturation characteristic to service.`); this.service.getCharacteristic(this.hap.Characteristic.Saturation) - .onSet(this.setSaturation.bind(this)); - // .onGet(this.CHANGE_ME.bind(this)); + .onSet(this.setSaturation.bind(this)) + .onGet(this.getSaturation.bind(this)); } addBrightnessCharacteristic() { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); this.service.getCharacteristic(this.hap.Characteristic.Brightness) - .onSet(this.setBrightness.bind(this)) - .onGet(this.getBrightness.bind(this)); + .onSet(this.setValue.bind(this)) + .onGet(this.getValue.bind(this)); + + if (this.controller.getCachedDeviceInformation().deviceAPI.simultaneousCCT) { + // this.service2.getCharacteristic(this.hap.Characteristic.Brightness) + // // .onSet(this.setBrightness2.bind(this)) + // .onGet(this.getBrightness2.bind(this)); + } } - // addColorTemperatureCharacteristic() { - // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); - // this.service.getCharacteristic(this.hap.Characteristic.ColorTemperature) - // .onSet(this.setColorTemperature.bind(this)) - // .onGet(this.getColorTemperature.bind(this)); + addColorTemperatureCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Color Temperature characteristic to service.`); + // this.service2.getCharacteristic(this.hap.Characteristic.ColorTemperature) + // // .onSet(this.setColorTemperature.bind(this)) + // .onGet(this.getColorTemperature.bind(this)); - // if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { - // this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); - // this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service); - // this.accessory.configureController(this.adaptiveLightingService); - // } - // } + if (this.api.versionGreaterOrEqual && this.api.versionGreaterOrEqual('1.3.0-beta.46')) { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Adaptive Lighting service to accessory.`); + // this.adaptiveLightingService = new this.api.hap.AdaptiveLightingController(this.service2); + // this.accessory.configureController(this.adaptiveLightingService); + } + } addAccessoryInformationCharacteristic() { @@ -430,6 +574,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); } + setRecentlyControlled() { this.recentlyControlled = true; setTimeout(() => { @@ -441,9 +586,5 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { return this.recentlyControlled; } - - - - } // ZackneticMagichomePlatformAccessory class diff --git a/src/settings.ts b/src/settings.ts index e4c42f2..1440fc0 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,10 +1,10 @@ - -/** - * This is the name of the platform that users will use to register the plugin in the Homebridge config.json - */ -export const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; - -/** - * This must match the name of your plugin as defined the package.json - */ + +/** + * This is the name of the platform that users will use to register the plugin in the Homebridge config.json + */ +export const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; + +/** + * This must match the name of your plugin as defined the package.json + */ export const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b6b18f1..8e68463 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,27 +1,27 @@ -{ - "compilerOptions": { - "target": "ES2018", // ~node10 - "module": "commonjs", - "lib": [ - "es2015", - "es2016", - "es2017", - "es2018" - ], - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "outDir": "./dist", - "rootDir": "./src", - "esModuleInterop": true, - "strictNullChecks": false, - "strict": false, - "downlevelIteration": true - }, - "include": [ - "src/" - ], - "exclude": [ - "**/*.spec.ts" - ] -} +{ + "compilerOptions": { + "target": "ES2018", // ~node10 + "module": "commonjs", + "lib": [ + "es2015", + "es2016", + "es2017", + "es2018" + ], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "esModuleInterop": true, + "strictNullChecks": false, + "strict": false, + "downlevelIteration": true + }, + "include": [ + "src/" + ], + "exclude": [ + "**/*.spec.ts" + ] +} From 7e84dfea9d7fb9019d6adcbfd43b45a3d1df2417 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Tue, 2 May 2023 16:59:59 -0400 Subject: [PATCH 39/42] animation updates --- src/AccessoryGenerator.ts | 22 +-- src/AnimationGenerator.ts | 18 +- src/CustomHomeKitTypes.ts | 79 ++++++++ src/animationAccessory.ts | 187 +++++++++--------- src/misc/types.ts | 13 +- src/misc/utils.ts | 2 +- src/platformAccessory.ts | 393 +++++++++++++++++++++----------------- 7 files changed, 421 insertions(+), 293 deletions(-) create mode 100644 src/CustomHomeKitTypes.ts diff --git a/src/AccessoryGenerator.ts b/src/AccessoryGenerator.ts index f13be24..36a00f2 100644 --- a/src/AccessoryGenerator.ts +++ b/src/AccessoryGenerator.ts @@ -1,6 +1,6 @@ import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep } from 'magichome-platform'; import { IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; -import { API, HAP, PlatformAccessory, PlatformConfig } from 'homebridge'; +import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; // import { homekitInterface } from './misc/types'; import { Logs } from './logs'; @@ -38,22 +38,22 @@ export class AccessoryGenerator { try { let completeDevices: ICompleteDevice[] = await this.controllerGenerator.discoverCompleteDevices(); - completeDevices = completeDevices.filter((device) => { - //if the device.completeDeviceInfo includes "ABCD" - if (device.completeDeviceInfo.protoDevice.uniqueId.includes('DC4F22CF7C31')) { - return true; - } else { - return false; - } + // completeDevices = completeDevices.filter((device) => { + // //if the device.completeDeviceInfo includes "ABCD" + // if (device.completeDeviceInfo.protoDevice.uniqueId.includes('DC4F22CF7C31')) { + // return true; + // } else { + // return false; + // } - }); + // }); const controllers: BaseController[] = await this.controllerGenerator.generateControllers(completeDevices); const activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] = await this.generateActiveAccessories(controllers); // this.registerOfflineAccessories(); return activeAccessories; } catch (error) { - this.logs.error(error); + // this.logs.error(error); } } @@ -151,7 +151,7 @@ export class AccessoryGenerator { // console.log(homebridgeUUID); const newAccessory: MagicHomeAccessory = new this.api.platformAccessory(description, homebridgeUUID) as MagicHomeAccessory; // console.log(newAccessory) - newAccessory.context = { displayName: description as string, deviceMetaData, protoDevice, latestUpdate: Date.now() }; + newAccessory.context = { displayName: description as string, deviceMetaData, protoDevice, latestUpdate: Date.now(), assignedAnimations: [] }; // new homekitInterface[description](this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); const hBAccessory = new HomebridgeMagichomeDynamicPlatformAccessory(this.api, newAccessory, this.config, controller, this.hbLogger, this.logs); this.activeAccessoriesList.push(hBAccessory); diff --git a/src/AnimationGenerator.ts b/src/AnimationGenerator.ts index fd29940..f2683d1 100644 --- a/src/AnimationGenerator.ts +++ b/src/AnimationGenerator.ts @@ -1,5 +1,5 @@ -import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave } from 'magichome-platform'; -import { thunderStruck, colorWave, AnimationController } from 'magichome-platform'; +import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave, IAnimationBlueprint } from 'magichome-platform'; +import { thunderStruck, rainbow, AnimationManager } from 'magichome-platform'; import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; @@ -10,7 +10,7 @@ import { HomebridgeAnimationAccessory } from './animationAccessory'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; -const animationLoops = [colorWave, thunderStruck] +const animationLoops = [rainbow, thunderStruck] export class AnimationGenerator { public readonly animationsFromDiskMap: Map = new Map(); @@ -28,7 +28,8 @@ export class AnimationGenerator { hbLogger, config, animationsFromDiskMap, - activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]) { + activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] + ) { this.api = api; this.hap = api.hap; this.hbLogger = hbLogger; @@ -48,7 +49,6 @@ export class AnimationGenerator { for (const animationLoop of animationLoops) { const homebridgeUUID = this.hap.uuid.generate(animationLoop.name); - console.log(animationLoop.name) try { if (this.animationsFromDiskMap.has(homebridgeUUID)) { const existingAnimationAccessory = this.animationsFromDiskMap.get(homebridgeUUID); @@ -77,16 +77,15 @@ export class AnimationGenerator { this.updateExistingAccessories(existingAccessoriesList); } - createNewAnimation(animationLoop: IAnimationLoop): AnimationAccessory { + createNewAnimation(animationLoop: IAnimationBlueprint): AnimationAccessory { let homebridgeUUID = this.hap.uuid.generate(animationLoop.name); - console.log(homebridgeUUID, animationLoop.name) const newAccessory: AnimationAccessory = new this.api.platformAccessory(animationLoop.name, homebridgeUUID) as AnimationAccessory; - newAccessory.context.animationLoop = animationLoop; + newAccessory.context.animationBlueprint = animationLoop; new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); return newAccessory; } - processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationLoop) { + processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationBlueprint) { // const { name, pattern, accessoryOffsetMS } = animationLoop; @@ -102,7 +101,6 @@ export class AnimationGenerator { } registerNewAccessories(newAccessories: AnimationAccessory[]) { - // link the accessory to your platform this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, newAccessories); diff --git a/src/CustomHomeKitTypes.ts b/src/CustomHomeKitTypes.ts new file mode 100644 index 0000000..5b0598c --- /dev/null +++ b/src/CustomHomeKitTypes.ts @@ -0,0 +1,79 @@ +import { Characteristic, Formats, Perms, Service } from "hap-nodejs"; + +/** + * Characteristic "ProgramService" + */ +export class Program extends Characteristic { + static readonly UUID = "00000102-0000-1000-8000-0026BB765296"; + +constructor() { + super("Program lights", Program.UUID, { + format: Formats.BOOL, + // unit: 'mired', + // minValue: 153, + // maxValue: 500, + perms: [ + Perms.PAIRED_WRITE, + Perms.PAIRED_READ, + Perms.NOTIFY, + ] + }); + this.value = this.getDefaultValue(); +} +} + +/** + * Service "ProgramService" + */ +export class ProgramService extends Service { + static readonly UUID = "00000101-0000-1000-8000-0026BB765296"; + + constructor(displayName: string, subtype?: string) { + super(displayName, ProgramService.UUID, subtype); + + // Required Characteristics + this.addCharacteristic(Program); + + // Optional Characteristics + this.addOptionalCharacteristic(Characteristic.Name); + } +} + +/** + * Characteristic "ProgramService" + */ +export class Clear extends Characteristic { + static readonly UUID = "00000102-0000-1000-8000-0026BB765297"; + +constructor() { + super("Clear Lights", Clear.UUID, { + format: Formats.BOOL, + // unit: 'mired', + // minValue: 153, + // maxValue: 500, + perms: [ + Perms.PAIRED_WRITE, + Perms.PAIRED_READ, + Perms.NOTIFY, + ] + }); + this.value = this.getDefaultValue(); +} +} + +/** + * Service "ProgramService" + */ +export class ClearService extends Service { + static readonly UUID = "00000101-0000-1000-8000-0026BB765297"; + + constructor(displayName: string, subtype?: string) { + super(displayName, ClearService.UUID, subtype); + + // Required Characteristics + this.addCharacteristic(Clear); + + // Optional Characteristics + this.addOptionalCharacteristic(Characteristic.Name); + } +} diff --git a/src/animationAccessory.ts b/src/animationAccessory.ts index 4ba15fc..5b28ef9 100644 --- a/src/animationAccessory.ts +++ b/src/animationAccessory.ts @@ -1,8 +1,8 @@ import type { Service, CharacteristicValue, HAP } from 'homebridge'; - -import { AnimationAccessory, DEFAULT_ACCESSORY_STATE, IAccessoryState } from './misc/types'; +import * as CustomHomeKitTypes from "./CustomHomeKitTypes"; +import { AnimationAccessory, DEFAULT_ACCESSORY_STATE, DEFAULT_ANIMATION_STATE, IAccessoryState, IAnimationState } from './misc/types'; // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, AnimationController } from 'magichome-platform'; +import { BaseController, AnimationManager, overwriteDeep } from 'magichome-platform'; import { Logs } from './logs'; import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; @@ -13,15 +13,14 @@ export class HomebridgeAnimationAccessory { protected service: Service; protected service2: Service; - protected accessoryState: IAccessoryState; - protected animationController: AnimationController; + protected accessoryState: IAnimationState = { isOn: false }; + protected animationManager: AnimationManager; protected isRecoding = false; protected numToggles = 0; listeningTimeout: NodeJS.Timeout; listenCount: number = 0; countTimeout: NodeJS.Timeout; isListening: boolean = false; - isTurnedOn: number = 0; //================================================= // Start Constructor // @@ -33,14 +32,14 @@ export class HomebridgeAnimationAccessory { protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], protected animationLoop ) { - this.accessoryState = DEFAULT_ACCESSORY_STATE; + overwriteDeep(this.accessoryState, DEFAULT_ANIMATION_STATE); // this.logs = logs; // this.controller = controller; this.hap = api.hap; this.api = api; // this.config = config; this.initializeCharacteristics(); - this.animationController = new AnimationController(); + this.animationManager = new AnimationController(); } //================================================= @@ -50,54 +49,59 @@ export class HomebridgeAnimationAccessory { // Start Setters // async setOn(value: CharacteristicValue) { this.accessoryState.isOn = value as boolean; - if (this.animationController.isActive || !value) this.animationController.clearAnimations(); - clearTimeout(this.listeningTimeout); - this.listenCount++; - if (this.listenCount == 2) { - this.logs.info("Listening for new devices.") - this.isListening = true; - // this.service2.updateCharacteristic(this.hap.Characteristic.StatusLowBattery, true); - } else if (this.listenCount == 3) { - this.listeningTimeout = setTimeout(async () => { - this.listenCount = 0; - this.isListening = false; - - this.logs.info("Assigning new devices.") - const filteredAccessories = this.accessoriesList.filter(accessory => { - return accessory.isReadyToAnimate(); + + if (this.animationManager.isActive || !value) { + this.animationManager.clearAnimations() + for (const accessory of this.accessoriesList) { + if (accessory.hasAssignedAnimation(this.animationLoop.name)) accessory.restoreBackupAccessoryState(); + } + } else if (value) { + + const controllers = this.accessoriesList + .filter(accessory => accessory.hasAssignedAnimation(this.animationLoop.name)) + .map(accessory => { + accessory.setBackupAccessoryState(); + return accessory.getController(); }); - for (const accessory of filteredAccessories) { - if(!this.accessory.context.activeControllerList)this.accessory.context.activeControllerList = []; - this.accessory.context.activeControllerList.push(accessory.getController()) - } - }, LISTENING_TIMEOUT_MS); - } else if (this.listenCount >= 5) { - this.isListening = false; - this.listenCount = 0; - this.accessory.context.activeControllerList = []; - } else { - this.listeningTimeout = setTimeout(async () => { - this.listenCount = 0; - if (value) { - - await this.animationController.animateAsynchronously(this.accessory.context.activeControllerList, this.animationLoop).catch(e => { }) - } - }, LISTENING_TIMEOUT_MS); + + await this.animationManager.animateAsynchronously(controllers, this.animationLoop).catch(e => { }) } - } - /** - * Handle requests to get the current value of the "Status Low Battery" characteristic - */ + } - setConfiguredName(value: CharacteristicValue) { + assignDevices(value: CharacteristicValue) { + if (!value) return; + this.logs.info("Assigning new devices.") + this.accessoriesList.filter(accessory => { + return accessory.isReadyToAnimate(); + }).forEach(accessory => { + accessory.addAssignedAnimation(this.animationLoop.name); + }); + } - const name: string = value.toString(); - this.logs.warn('Renaming device to %o', name); - this.accessory.context.displayName = name; - this.api.updatePlatformAccessories([this.accessory]); + clearDevices(value: CharacteristicValue) { + if (!value) return; + this.logs.info("Unassigning All Devices.") + this.accessoriesList.forEach( + accessory => { + accessory.removeAssignedAnimation(this.animationLoop.name); + }); } + + +/** + * Handle requests to get the current value of the "Status Low Battery" characteristic + */ + +setConfiguredName(value: CharacteristicValue) { + + const name: string = value.toString(); + this.logs.warn('Renaming device to %o', name); + this.accessory.context.displayName = name; + this.api.updatePlatformAccessories([this.accessory]); +} + //================================================= // End Setters // @@ -105,54 +109,61 @@ export class HomebridgeAnimationAccessory { // Start Getters // async getOn() { - const { isOn } = this.accessoryState; - return isOn; - } + const { isOn } = this.accessoryState; + return isOn; +} - //================================================= - // End LightEffects // +//================================================= +// End LightEffects // - initializeCharacteristics() { - this.addAccessoryInformationCharacteristic(); +initializeCharacteristics() { + this.addAccessoryInformationCharacteristic(); - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding "Switch" service to accessory.`); - this.service = this.accessory.getService(this.hap.Service.Outlet) ?? this.accessory.addService(this.hap.Service.Outlet); - this.addOnCharacteristic(); - this.addConfiguredNameCharacteristic(); - } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding "Switch" service to accessory.`); + this.service = this.accessory.getService(this.hap.Service.Outlet) ?? this.accessory.addService(this.hap.Service.Outlet); + this.addOnCharacteristic(); + this.addConfiguredNameCharacteristic(); + this.addOtherCharacteristics(); - addOnCharacteristic() { - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); - this.service.getCharacteristic(this.hap.Characteristic.On) - .onSet(this.setOn.bind(this)) - .onGet(this.getOn.bind(this)); - } +} - addAccessoryInformationCharacteristic() { +addOnCharacteristic() { + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); + this.service.getCharacteristic(this.hap.Characteristic.On) + .onSet(this.setOn.bind(this)) + .onGet(this.getOn.bind(this)); +} - this.accessory.getService(this.hap.Service.AccessoryInformation)! - .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') - // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) - // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) - // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') - // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') - .removeAllListeners(this.hap.CharacteristicEventTypes.SET) - .removeAllListeners(this.hap.CharacteristicEventTypes.GET); +addOtherCharacteristics() { + this.service.getCharacteristic(CustomHomeKitTypes.Program).onSet(this.assignDevices.bind(this)); + this.service.getCharacteristic(CustomHomeKitTypes.Clear).onSet(this.clearDevices.bind(this)); +} - this.accessory.getService(this.hap.Service.AccessoryInformation)! - .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); - } +addAccessoryInformationCharacteristic() { - addConfiguredNameCharacteristic() { - if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { - this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) - .onSet(this.setConfiguredName.bind(this)); - } else { - this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) - .onSet(this.setConfiguredName.bind(this)); - } - this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .setCharacteristic(this.hap.Characteristic.Manufacturer, 'Zacknetic') + // .setCharacteristic(this.hap.Characteristic.SerialNumber, uniqueId) + // .setCharacteristic(this.hap.Characteristic.Model, modelNumber) + // .setCharacteristic(this.hap.Characteristic.HardwareRevision, controllerHardwareVersion?.toString(16) ?? 'unknown') + // .setCharacteristic(this.hap.Characteristic.FirmwareRevision, controllerFirmwareVersion?.toString(16) ?? 'unknown ') + .removeAllListeners(this.hap.CharacteristicEventTypes.SET) + .removeAllListeners(this.hap.CharacteristicEventTypes.GET); + + this.accessory.getService(this.hap.Service.AccessoryInformation)! + .addOptionalCharacteristic(this.hap.Characteristic.ConfiguredName); +} +addConfiguredNameCharacteristic() { + if (!this.service.testCharacteristic(this.hap.Characteristic.ConfiguredName)) { + this.service.addCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); + } else { + this.service.getCharacteristic(this.hap.Characteristic.ConfiguredName) + .onSet(this.setConfiguredName.bind(this)); } + this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Configured Name characteristic to service.`); + +} } diff --git a/src/misc/types.ts b/src/misc/types.ts index a64e48c..a897e28 100644 --- a/src/misc/types.ts +++ b/src/misc/types.ts @@ -1,5 +1,6 @@ import type { PlatformAccessory } from 'homebridge'; -import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation, IDeviceMetaData, IProtoDevice, IAnimationLoop } from 'magichome-platform'; +import { BaseController, IDeviceState, IDeviceCommand, IColorCCT, IDeviceInformation, IDeviceMetaData, IProtoDevice, IAnimationBlueprint } from 'magichome-platform'; +import { HomebridgeMagichomeDynamicPlatformAccessory } from '../platformAccessory'; // import { Switch } from '../accessories/Switch'; // import { DimmerStrip } from '../accessories/DimmerStrip'; @@ -33,14 +34,15 @@ export interface AnimationAccessory extends PlatformAccessory { } export interface IAnimationContext { - animationLoop: IAnimationLoop; - activeControllerList: BaseController[]; + activeAccessoryList: any; + animationBlueprint: IAnimationBlueprint; displayName?: string; } export interface IAccessoryContext { displayName?: string; deviceMetaData: IDeviceMetaData; + assignedAnimations: string[] protoDevice: IProtoDevice; latestUpdate: number; } @@ -50,6 +52,11 @@ export interface IAccessoryState { HSV: IColorHSV, TB: IColorTB } + +export interface IAnimationState { + isOn: boolean, +} + export interface IPartialAccessoryCommand { isOn?: boolean, HSV?: IPartialColorHSV, diff --git a/src/misc/utils.ts b/src/misc/utils.ts index caff4b7..1a78b43 100644 --- a/src/misc/utils.ts +++ b/src/misc/utils.ts @@ -197,7 +197,7 @@ export function CCTtoTB(CCT: IColorCCT): IColorTB { } // Calculate the brightness based on the coldWhite value - brightness = Math.round((coldWhite / 255) * 100); + brightness = Math.round(Math.max((coldWhite / 255) * 100, (warmWhite / 255) * 100)); // Return the temperature and brightness as a TB value return { temperature, brightness }; diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index c1ea036..a1fd3ed 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -1,24 +1,22 @@ import type { - API, Service, PlatformConfig, CharacteristicValue, + API, Service, PlatformConfig, CharacteristicValue, Characteristic, CharacteristicSetCallback, CharacteristicGetCallback, HAP, Logger, Logging, } from 'homebridge'; import { clamp, TBtoCCT, HSVtoRGB, RGBtoHSV, CCTtoTB } from './misc/utils'; import { AnimationAccessory, DEFAULT_ACCESSORY_COMMAND, DEFAULT_ACCESSORY_STATE, IAccessoryCommand, IAccessoryState, IColorHSV, IColorTB, IConfigOptions, IPartialAccessoryCommand, MagicHomeAccessory } from './misc/types'; -// import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; import { BaseController, ICommandOptions, IDeviceCommand, IDeviceState, IProtoDevice, IAnimationLoop, ICompleteResponse, mergeDeep, overwriteDeep, COMMAND_TYPE, COLOR_MASKS } from 'magichome-platform'; import { Logs } from './logs'; -const WHITE_MODE = 'WHITE_MODE'; -const COLOR_MODE = 'COLOR_MODE'; const RECENT_CONTROLLED_TIMEOUT_MS = 30 * 1000; -/** - * 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 HomebridgeMagichomeDynamicPlatformAccessory { + + protected service: Service; protected readonly hap: HAP; @@ -28,19 +26,12 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { public accessoryState: IAccessoryState; - protected colorCommandMode: string = COLOR_MODE; - protected colorWhiteSimultaniousSaturationLevel; protected colorOffSaturationLevel; protected simultaniousDevicesColorWhite; - protected deviceWriteStatus = 'ready'; - protected deviceReadStatus = 'ready'; - protected readRequestLevel = 0; - protected recentlyControlled = false; protected currentlyAnimating = false; - protected currentAnimator: AnimationAccessory = null; protected queue; protected lastValue: number; @@ -54,7 +45,15 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { timeout: NodeJS.Timeout; processAccessoryCommandTimeout: NodeJS.Timeout; service2: any; - + useBackupHSV: boolean; + backupHSV: any; + backupAccessoryState: any; + protected skipNextAccessoryStatusUpdate: boolean = false; + periodicScanTimeout: NodeJS.Timeout; + CustomCharacteristics: any; + UUID_CCT: string; + testString: string; + testInt = 0; //================================================= // Start Constructor // @@ -66,7 +65,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected readonly hbLogger: Logging, protected readonly logs, ) { - + this.UUID_CCT = 'a9a59a9f-9b8f-45d7-84b6-eeb848a8d05a'; this.setupMisc(); this.accessoryState = mergeDeep({}, DEFAULT_ACCESSORY_STATE); this.logs = logs; @@ -81,11 +80,17 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.periodicScan(); } + protected second = true; + //updated state every 10 seconds but only the isOn state async periodicScan() { - while (true) { - await new Promise(resolve => setTimeout(resolve, 5000, - )); - this.fetchDeviceState(2, true); + // console.log('periodicScan: called', this.skipNextAccessoryStateUpdate) + let onlyIsOn = []; + while (!this.skipNextAccessoryStatusUpdate) { + if (!this.second) onlyIsOn = ["isOn"]; + this.second = false; + await this.fetchDeviceState(2, true, onlyIsOn); + // console.log("periodicScan outside await", this.periodicScanTimeout) + await new Promise((resolve) => setTimeout(resolve, 5000)); } } @@ -102,32 +107,32 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // this.startResetTimeout(); // } - // setHue(value: CharacteristicValue) { + // setHue2(value: CharacteristicValue) { + // this.testString = value as string; // if (!this.isCountingTime) { // this.isCountingTime = true; // console.time('setters'); // console.timeLog('setters'); - // console.log('setters: setHue: ', value); + // console.log('setters: setHue2: ', value); // } else { // console.timeLog('setters'); - // console.log('setters: setHue: ', value); + // console.log('setters: setHue2: ', value); // } // this.startResetTimeout(); // } - // setSaturation(value: CharacteristicValue) { + // setBrightness2(value: CharacteristicValue) { // if (!this.isCountingTime) { // this.isCountingTime = true; // console.time('setters'); // console.timeLog('setters'); - // console.log('setters: setSaturation: ', value); + // console.log('setters: setBrightness2: ', value); // } else { // console.timeLog('setters'); - // console.log('setters: setSaturation: ', value); + // console.log('setters: setBrightness2: ', value); // } // this.startResetTimeout(); // } - // setValue(value: CharacteristicValue) { // if (!this.isCountingTime) { // this.isCountingTime = true; @@ -142,17 +147,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // } // startResetTimeout() { + // this.testInt++; // clearTimeout(this.timeout); // this.timeout = setTimeout(() => { + // this.service.updateCharacteristic(CustomHomeKitTypes.CCT, false); // console.timeEnd('setters'); // console.log('reset setters boolean'); // this.isCountingTime = false; // }, 3000); // } - setOn(value: CharacteristicValue) { + async setOn(value: CharacteristicValue) { this.powerTimeout = setTimeout(() => { if (!this.resistOff) { + this.accessoryState.isOn = value as boolean; const partialAccessoryCommand: IPartialAccessoryCommand = { isOn: value as boolean, isPowerCommand: true }; this.processAccessoryCommand(partialAccessoryCommand); } @@ -166,32 +174,26 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.processAccessoryCommand(partialAccessoryCommand); } - setSaturation(value: CharacteristicValue) { + async setSaturation(value: CharacteristicValue) { this.resistSetOnCommand() this.accessoryState.HSV.saturation = value as number; - const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { saturation: value as number } }; - this.processAccessoryCommand(partialAccessoryCommand); + // const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { saturation: value as number } }; + // this.processAccessoryCommand(partialAccessoryCommand); } - setValue(value: CharacteristicValue) { + async setValue(value: CharacteristicValue) { this.resistSetOnCommand() this.accessoryState.HSV.value = value as number; const partialAccessoryCommand: IPartialAccessoryCommand = { HSV: { value: value as number } }; this.processAccessoryCommand(partialAccessoryCommand); - } - // setBrightness2(value: CharacteristicValue) { - // this.resistSetOnCommand() - // this.accessoryState.TB.brightness = value as number; - // const partialAccessoryCommand: IPartialAccessoryCommand = { TB: { brightness: value as number } }; - // this.processAccessoryCommand(partialAccessoryCommand); - // } + } setColorTemperature(value: CharacteristicValue) { this.resistSetOnCommand() this.accessoryState.TB.temperature = value as number; const partialAccessoryCommand: IPartialAccessoryCommand = { TB: { temperature: value as number } }; - console.log('set color temp', value) + // console.log('set color temp', value) this.processAccessoryCommand(partialAccessoryCommand); } @@ -203,6 +205,22 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.api.updatePlatformAccessories([this.accessory]); } + public addAssignedAnimation(animationName: string) { + if (this.accessory.context.assignedAnimations.includes(animationName)) return; + this.accessory.context.assignedAnimations.push(animationName); + this.api.updatePlatformAccessories([this.accessory]); + } + + public removeAssignedAnimation(_animationName: string) { + this.accessory.context.assignedAnimations = this.accessory.context.assignedAnimations.filter((animationName) => { + return animationName !== _animationName; + }); + } + + public hasAssignedAnimation(animationName: string): boolean { + return this.accessory.context.assignedAnimations.includes(animationName); + } + resistSetOnCommand() { this.resistOff = true; clearTimeout(this.HSVTimeout); @@ -217,74 +235,43 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } getHue() { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { setTimeout(async () => { - try { - const { HSV: { hue }, TB: { temperature } } = await this.fetchDeviceState(5, false); - this.logValue('getHue', hue); - resolve(hue); - } catch (error) { - console.log('getHue Error: ', error) - - } + const { HSV: { hue } } = this.accessoryState; + resolve(hue); }, 50) }); } getSaturation() { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { setTimeout(async () => { - try { - const { HSV: { saturation }, TB: { temperature } } = await this.fetchDeviceState(5, false); - this.logValue('getSaturation', saturation); - resolve(saturation); - } catch (error) { - console.log('getSaturation Error: ', error) - - } + const { HSV: { saturation } } = this.accessoryState; + resolve(saturation); }, 50) }); } getValue() { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { setTimeout(async () => { - try { - const { HSV: { value }, TB: { temperature } } = await this.fetchDeviceState(5, false); - this.logValue('getValue', value); - resolve(value); - } catch (error) { - console.log('getValue Error: ', error) - - } + const { HSV: { value } } = this.accessoryState; + resolve(value); }, 50) }); } getOn() { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { setTimeout(async () => { - try { - const { isOn } = await this.fetchDeviceState(5, false); - this.logValue('isOn', isOn); - resolve(isOn); - } catch (error) { - console.log('isOn Error: ', error) - } - }, 50) + const { isOn } = this.accessoryState; + resolve(isOn); + }, 100) }); } - // getBrightness2() { - - // const { HSV: { value }, TB: { brightness } } = this.deviceStateToAccessoryState(this.controller.getLastOutboundState()); - // console.log(this.controller.getLastOutboundState()) - // this.fetchAndUpdateState(5); - // return value; - // } - getColorTemperature() { - const { HSV: { hue }, TB: { temperature } } = this.deviceStateToAccessoryState(this.controller.getLastOutboundState()); + const { TB: { temperature } } = this.deviceStateToAccessoryState(this.controller.getLastOutboundState()); this.fetchDeviceState(5); return temperature; } @@ -292,9 +279,9 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { - logValue(valueType: string, value: any) { - console.log(`${valueType} value: ${value}`); - } + // logValue(valueType: string, value: any) { + // console.log(`${valueType} value: ${value}`); + // } flashEffect() { // @@ -303,7 +290,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // End LightEffects // - //TODO, Severe! Bundle commands so that close consecutive changes in hue, sat, and brightness aren't sent as separate commands protected processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { if (this.waitingSendoff) { return; @@ -311,24 +297,47 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { try { this.setRecentlyControlled(); this.waitingSendoff = true; - this.processAccessoryCommandTimeout = setTimeout(() => { + this.skipNextStatusUpdate(); + setTimeout(() => { this.waitingSendoff = false; const sanitizedAcessoryCommand = this.completeAccessoryCommand(partialAccessoryCommand); if (partialAccessoryCommand.isPowerCommand) { this.controller.setOn(sanitizedAcessoryCommand.isOn); } else { const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); - console.log(deviceCommand) this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand); } - }, 10); + }, 50); } catch (error) { - console.log('processAccessoryCommand: ', error); + // console.log('processAccessoryCommand: ', error); + } + } + + protected async skipNextStatusUpdate() { + if (this.skipNextAccessoryStatusUpdate) return; + this.skipNextAccessoryStatusUpdate = true; + clearTimeout(this.periodicScanTimeout); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + setTimeout(() => { + this.skipNextAccessoryStatusUpdate = false; + this.periodicScan() + }, 550); + } + + public setBackupAccessoryState() { + this.backupAccessoryState = mergeDeep({}, this.accessoryState); + } + + public restoreBackupAccessoryState() { + if (this.backupAccessoryState) { + this.processAccessoryCommand(this.backupAccessoryState); + this.updateStateHomekitCharacteristic(); } } protected completeAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand): IAccessoryCommand { - this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); + // this.logs.debug(this.accessory.context.displayName, '\n Current State:', this.accessoryState, '\n Received Command', this.newAccessoryCommand); const sanitizedAcessoryCommand: IAccessoryCommand = mergeDeep({}, partialAccessoryCommand, this.accessoryState); if (partialAccessoryCommand.hasOwnProperty('isOn') && !(partialAccessoryCommand.hasOwnProperty('HSV') || partialAccessoryCommand.hasOwnProperty('brightness'))) { sanitizedAcessoryCommand.isPowerCommand = true; @@ -337,86 +346,138 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } protected accessoryCommandToDeviceCommand(accessoryCommand: IAccessoryCommand): { deviceCommand: IDeviceCommand, commandOptions: ICommandOptions } { + let { isOn, HSV: { hue, saturation, value }, TB } = accessoryCommand; - const { temperature, brightness } = TB; - if (Math.max(brightness, value) > 0) { - isOn = true; - } - const commandOptions: ICommandOptions = { colorAssist: false, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; + const { brightness } = TB; + isOn = (Math.max(brightness, value) > 0); + + const commandOptions: ICommandOptions = { colorAssist: true, commandType: COMMAND_TYPE.COLOR_COMMAND, waitForResponse: true, maxRetries: 5, timeoutMS: 50 }; let red, green, blue, warmWhite, coldWhite, colorMask = null; colorMask = COLOR_MASKS.BOTH; - if (this.controller.getCachedDeviceInformation().deviceAPI.simultaneousCCT) { - ({ warmWhite, coldWhite } = TBtoCCT({ temperature, brightness })); - ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value })); - } else { - if (saturation < 95) { - - ({ warmWhite, coldWhite } = TBtoCCT({ temperature: hue + 140, brightness: value })); - ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value: this.lastValue })); - console.log(red, green, blue, warmWhite, coldWhite) - if (saturation < 5) { - this.lastValue = value; - red = 0, green = 0, blue = 0; - colorMask = COLOR_MASKS.WHITE; - } - } else { - colorMask = COLOR_MASKS.COLOR; + if (saturation < 95) { + + ({ warmWhite, coldWhite } = TBtoCCT({ temperature: hue + 140, brightness: value })); + ({ red, green, blue } = HSVtoRGB({ hue, saturation: 100, value: this.lastValue })); + + if (saturation < 5) { this.lastValue = value; - ({ red, green, blue } = HSVtoRGB({ hue, saturation, value })); - warmWhite = 0; - coldWhite = 0; + red = 0, green = 0, blue = 0; + colorMask = COLOR_MASKS.WHITE; } - } + } else { + colorMask = COLOR_MASKS.COLOR; + this.lastValue = value; + ({ red, green, blue } = HSVtoRGB({ hue, saturation, value })); + warmWhite = 0; + coldWhite = 0; + } const deviceCommand: IDeviceCommand = { isOn, RGB: { red, green, blue }, colorMask, CCT: { warmWhite, coldWhite } }; return { deviceCommand, commandOptions }; } + setBackupHSV(HSV) { + this.backupHSV = HSV; + this.useBackupHSV = true; + } + + getBackupHSV(reset = false) { + if (reset) + this.useBackupHSV = false; + return this.backupHSV; + } + + setRecentlyControlled() { + this.recentlyControlled = true; + setTimeout(() => { + this.recentlyControlled = false; + }, RECENT_CONTROLLED_TIMEOUT_MS); + } + + public isReadyToAnimate() { + return this.recentlyControlled; + } + protected sendCommand(deviceCommand: IDeviceCommand, commandOptions: ICommandOptions, accessoryCommand) { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); try { this.controller.setAllValues(deviceCommand, commandOptions); } catch (error) { - console.log("sendCommand ERROR: ", error); + // console.log("sendCommand ERROR: ", error); } this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`); } - updateStateHomekitCharacteristic(deviceState: IDeviceState) { - console.log(deviceState) - const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); - console.log(isOn, hue, saturation, value, brightness, temperature) + updateStateHomekitCharacteristic() { + if (this.waitingSendoff) return; + // console.log(deviceState) + // const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); + // console.log(isOn, hue, saturation, value, brightness, temperature) + const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.accessoryState; + this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); - this.service.updateCharacteristic(this.hap.Characteristic.Saturation, this.accessoryState.HSV.saturation); + this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); this.service.updateCharacteristic(this.hap.Characteristic.Hue, hue); this.service.updateCharacteristic(this.hap.Characteristic.Brightness, value); } - deviceStateToAccessoryState(deviceState: IDeviceState): IAccessoryState { + public async fetchDeviceState(attempts = 1, updateHomekit = false, restrictedToCharacteristics: string[] = []) { + let deviceState: IDeviceState; + let accessoryState: IAccessoryState; + try { + deviceState = await this.controller.fetchStateRGB(); + accessoryState = this.deviceStateToAccessoryState(deviceState, restrictedToCharacteristics); + overwriteDeep(this.accessoryState, accessoryState) + // if (updateHomekit) { + this.updateStateHomekitCharacteristic(); + // } + } catch (error) { + // console.log("fetchDeviceState ERROR: ", error); + if (attempts > 0) { + setTimeout(() => { + this.fetchDeviceState(attempts - 1, updateHomekit, restrictedToCharacteristics); + }, 500); + } else { + this.hbLogger.warn(`Failed to fetch and update state for ${this.accessory.context.displayName}: ${error}`); + } + } + if (!deviceState) { + this.hbLogger.warn(`Failed to fetch and update state for ${this.accessory.context.displayName}`); + } + } + + deviceStateToAccessoryState(deviceState: IDeviceState, restrictedToCharacteristics: string[] = []): IAccessoryState { if (!deviceState) { - throw 'device state not provided'; + // throw 'device state not provided'; } const { RGB, CCT, isOn } = deviceState; const { red, green, blue } = RGB; const { deviceAPI: { hasBrightness, hasCCT, hasColor, simultaneousCCT } } = this.controller.getCachedDeviceInformation(); - let TB: IColorTB; - let HSV: IColorHSV; - - HSV = RGBtoHSV(RGB); - TB = CCTtoTB(CCT); - if (!simultaneousCCT) { - if (Math.max(red, green, blue) <= 0) { - HSV = { hue: 5, saturation: 4, value: TB.brightness } - } + let HSV: IColorHSV = RGBtoHSV(RGB); + let TB: IColorTB = CCTtoTB(CCT); + // if (!simultaneousCCT) { + if (Math.max(red, green, blue) <= 0) { + HSV = { hue: 5, saturation: 4, value: TB.brightness } } - const accessoryState: IAccessoryState = { HSV, TB, isOn }; + // } + + let accessoryState = { isOn: null, HSV: { hue: null, saturation: null, value: null }, TB: { brightness: null, temperature: null } }; + + if (restrictedToCharacteristics.includes('isOn') || restrictedToCharacteristics.includes('Hue') || restrictedToCharacteristics.includes('Value')) { + if (restrictedToCharacteristics.includes('isOn')) accessoryState.isOn = isOn; + if (restrictedToCharacteristics.includes('Hue')) accessoryState.HSV.hue = HSV.hue; + if (restrictedToCharacteristics.includes('Value')) accessoryState.HSV.value = HSV.value; + mergeDeep(accessoryState, this.accessoryState) + } else accessoryState = { HSV, TB, isOn } + if (accessoryState.HSV.value < 1) { accessoryState.HSV.value = TB.brightness } return accessoryState; } + initializeCharacteristics() { const { deviceAPI: { hasBrightness, hasCCT, hasColor, simultaneousCCT } } = this.controller.getCachedDeviceInformation(); @@ -425,9 +486,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Lightbulb service to accessory.`); this.service = this.accessory.getService(this.hap.Service.Lightbulb) ?? this.accessory.addService(this.hap.Service.Lightbulb); - // if (simultaneousCCT) { - // this.service2 = this.accessory.getService('Light Bulb 1') ?? this.accessory.addService(this.hap.Service.Lightbulb, 'Light Bulb 1', 'subtype1'); - // } if (hasColor) { this.addHueCharacteristic(); @@ -462,31 +520,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } - public async fetchDeviceState(attempts = 1, updateHomekit = false) { - let deviceState: IDeviceState; - let accessoryState: IAccessoryState; - try { - deviceState = await this.controller.fetchState(); - accessoryState = this.deviceStateToAccessoryState(deviceState); - this.accessoryState = accessoryState; - if (updateHomekit) { - this.updateStateHomekitCharacteristic(deviceState); - } - } catch (error) { - console.log("fetchDeviceState ERROR: ", error); - if (attempts > 0) { - setTimeout(() => { - this.fetchDeviceState(attempts - 1), updateHomekit; - }, 500); - } else { - this.hbLogger.error(`Failed to fetch and update state for ${this.accessory.displayName}: ${error}`); - } - } - if (!deviceState) { - return this.accessoryState; - } - return accessoryState; - } getController() { @@ -522,9 +555,15 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { .onGet(this.getValue.bind(this)); if (this.controller.getCachedDeviceInformation().deviceAPI.simultaneousCCT) { - // this.service2.getCharacteristic(this.hap.Characteristic.Brightness) - // // .onSet(this.setBrightness2.bind(this)) - // .onGet(this.getBrightness2.bind(this)); + // console.log('adding CCT'); + // this.service.getCharacteristic(CustomHomeKitTypes.CCT) + // // this.service2.getCharacteristic(this.hap.Characteristic.Brightness) + // .onSet(this.setHue2.bind(this)); + // .onGet(this.getHue2.bind(this)); + // this.service.getCharacteristic(this.CustomCharacteristics.CCT) + // // this.service2.getCharacteristic(this.hap.Characteristic.Brightness) + // .onSet(this.setBrightness2.bind(this)) + // // .onGet(this.getBrightness2.bind(this)); } } @@ -575,16 +614,10 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } - setRecentlyControlled() { - this.recentlyControlled = true; - setTimeout(() => { - this.recentlyControlled = false; - }, RECENT_CONTROLLED_TIMEOUT_MS); - } - - public isReadyToAnimate() { - return this.recentlyControlled; - } + } // ZackneticMagichomePlatformAccessory class +const sleep = (ms) => new Promise((resolve) => { + setTimeout(resolve, ms); +}); From 8c3495dbd6a487268ad7272aa65b526f95e4f53c Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Tue, 9 May 2023 21:57:00 -0400 Subject: [PATCH 40/42] animation fixes --- src/AnimationGenerator.ts | 70 +++++++++++++++++---------------------- src/animationAccessory.ts | 40 +++++++++++----------- src/platform.ts | 8 +++-- src/platformAccessory.ts | 2 ++ 4 files changed, 59 insertions(+), 61 deletions(-) diff --git a/src/AnimationGenerator.ts b/src/AnimationGenerator.ts index f2683d1..68accde 100644 --- a/src/AnimationGenerator.ts +++ b/src/AnimationGenerator.ts @@ -1,6 +1,6 @@ -import { BaseController, ControllerGenerator, IDeviceAPI, ICompleteDevice, IProtoDevice, ICompleteDeviceInfo, mergeDeep, overwriteDeep, IAnimationLoop, cctWave, IAnimationBlueprint } from 'magichome-platform'; +import { IAnimationBlueprint } from 'magichome-platform'; import { thunderStruck, rainbow, AnimationManager } from 'magichome-platform'; -import { AnimationAccessory, IAccessoryContext, IAccessoryState, MagicHomeAccessory } from './misc/types'; +import { AnimationAccessory, MagicHomeAccessory } from './misc/types'; import { API, HAP, PlatformAccessory, PlatformConfig, uuid } from 'homebridge'; // import { homekitInterface } from './misc/types'; @@ -10,33 +10,23 @@ import { HomebridgeAnimationAccessory } from './animationAccessory'; const PLATFORM_NAME = 'homebridge-magichome-dynamic-platform'; const PLUGIN_NAME = 'homebridge-magichome-dynamic-platform'; -const animationLoops = [rainbow, thunderStruck] +const animationBlueprints = [rainbow, thunderStruck] export class AnimationGenerator { - public readonly animationsFromDiskMap: Map = new Map(); public readonly activeAnimationAcessoriesMap: Map = new Map(); public readonly cachedAccessoriesMap: Map = new Map(); - private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[]; private hap: HAP; - private api: API; - private hbLogger; - private config: PlatformConfig; - private logs: Logs; + private animationManager: AnimationManager; constructor( - api: API, - logs: Logs, - hbLogger, - config, - animationsFromDiskMap, - activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] - ) { - this.api = api; - this.hap = api.hap; - this.hbLogger = hbLogger; - this.logs = logs; - this.config = config; - this.animationsFromDiskMap = animationsFromDiskMap; - this.activeAccessories = activeAccessories; + private api: API, + private logs: Logs, + private hbLogger, + private config : PlatformConfig, + public readonly animationsFromDiskMap : Map = new Map(), + private activeAccessories: HomebridgeMagichomeDynamicPlatformAccessory[] + ) { + this.hap = this.api.hap; + this.animationManager = AnimationManager.getInstance([], [thunderStruck, rainbow]); } @@ -47,22 +37,22 @@ export class AnimationGenerator { const existingAccessoriesList: AnimationAccessory[] = []; - for (const animationLoop of animationLoops) { - const homebridgeUUID = this.hap.uuid.generate(animationLoop.name); + for (const animationBlueprint of animationBlueprints) { + const homebridgeUUID = this.hap.uuid.generate(animationBlueprint.name); try { if (this.animationsFromDiskMap.has(homebridgeUUID)) { const existingAnimationAccessory = this.animationsFromDiskMap.get(homebridgeUUID); this.animationsFromDiskMap.delete(homebridgeUUID); - this.logs.info(`[${animationLoop.name}] - Found existing accessory. Updating...`); - const existingAccessory = this.processOnlineAccessory(existingAnimationAccessory, animationLoop); + this.logs.info(`[${animationBlueprint.name}] - Found existing accessory. Updating...`); + const existingAccessory = this.processOnlineAccessory(existingAnimationAccessory, animationBlueprint); existingAccessoriesList.push(existingAccessory); - } else if (!this.activeAnimationAcessoriesMap.has(homebridgeUUID)) { //if the accessory is not a duplicate active device - const newAccessory: AnimationAccessory = this.createNewAnimation(animationLoop); - this.logs.info(`[${animationLoop.name}] - Found new accessory. Registering...`); + } + + else if (!this.activeAnimationAcessoriesMap.has(homebridgeUUID)) { //if the accessory is not a duplicate active device + const newAccessory: AnimationAccessory = this.createNewAnimation(animationBlueprint); + this.logs.info(`[${animationBlueprint.name}] - Found new accessory. Registering...`); newAccessoriesList.push(newAccessory); //add it to new accessory list - - this.activeAnimationAcessoriesMap.set(homebridgeUUID, newAccessory); } @@ -75,26 +65,28 @@ export class AnimationGenerator { this.registerNewAccessories(newAccessoriesList); //register new accessories from scan this.updateExistingAccessories(existingAccessoriesList); + // this.unregisterAccessory(existingAccessoriesList); } - createNewAnimation(animationLoop: IAnimationBlueprint): AnimationAccessory { - let homebridgeUUID = this.hap.uuid.generate(animationLoop.name); - const newAccessory: AnimationAccessory = new this.api.platformAccessory(animationLoop.name, homebridgeUUID) as AnimationAccessory; - newAccessory.context.animationBlueprint = animationLoop; - new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationLoop); + createNewAnimation(animationBlueprint: IAnimationBlueprint): AnimationAccessory { + let homebridgeUUID = this.hap.uuid.generate(animationBlueprint.name); + const newAccessory: AnimationAccessory = new this.api.platformAccessory(animationBlueprint.name, homebridgeUUID) as AnimationAccessory; + newAccessory.context.animationBlueprint = animationBlueprint; + new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, newAccessory, this.activeAccessories, animationBlueprint); return newAccessory; } - processOnlineAccessory(existingAccessory: AnimationAccessory, animationLoop: IAnimationBlueprint) { + processOnlineAccessory(existingAccessory: AnimationAccessory, animationBlueprint: IAnimationBlueprint) { // const { name, pattern, accessoryOffsetMS } = animationLoop; try { - new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationLoop); + new HomebridgeAnimationAccessory(this.hap, this.logs, this.api, existingAccessory, this.activeAccessories, animationBlueprint); // new homekitInterface[description](this.api, existingAccessory, this.config, controller, this.hbLogger, this.logs); } catch (error) { + console.log(error) // throw new Error(`[Error] [${existingAccessory.context.displayName}] [UID: ${cachedDeviceInformation.protoDevice.uniqueId}] [processExistingAccessory]: ${error}`); } return existingAccessory; diff --git a/src/animationAccessory.ts b/src/animationAccessory.ts index 5b28ef9..d1deb63 100644 --- a/src/animationAccessory.ts +++ b/src/animationAccessory.ts @@ -2,7 +2,7 @@ import type { Service, CharacteristicValue, HAP } from 'homebridge'; import * as CustomHomeKitTypes from "./CustomHomeKitTypes"; import { AnimationAccessory, DEFAULT_ACCESSORY_STATE, DEFAULT_ANIMATION_STATE, IAccessoryState, IAnimationState } from './misc/types'; // import { addAccessoryInformationCharacteristic, addBrightnessCharacteristic, addColorTemperatureCharacteristic, addConfiguredNameCharacteristic, addHueCharacteristic, addOnCharacteristic, addSaturationCharacteristic } from './misc/serviceCharacteristics'; -import { BaseController, AnimationManager, overwriteDeep } from 'magichome-platform'; +import { BaseController, AnimationManager, overwriteDeep, IAnimationBlueprint } from 'magichome-platform'; import { Logs } from './logs'; import { HomebridgeMagichomeDynamicPlatformAccessory } from './platformAccessory'; @@ -14,32 +14,31 @@ export class HomebridgeAnimationAccessory { protected service2: Service; protected accessoryState: IAnimationState = { isOn: false }; - protected animationManager: AnimationManager; protected isRecoding = false; protected numToggles = 0; listeningTimeout: NodeJS.Timeout; listenCount: number = 0; countTimeout: NodeJS.Timeout; isListening: boolean = false; + protected animationManager: AnimationManager; + //================================================= // Start Constructor // - constructor( protected hap: HAP, protected logs, protected api, protected accessory: AnimationAccessory, protected accessoriesList: HomebridgeMagichomeDynamicPlatformAccessory[], - protected animationLoop + protected animationBlueprint: IAnimationBlueprint, ) { overwriteDeep(this.accessoryState, DEFAULT_ANIMATION_STATE); - // this.logs = logs; - // this.controller = controller; - this.hap = api.hap; - this.api = api; - // this.config = config; this.initializeCharacteristics(); - this.animationManager = new AnimationController(); + this.animationManager = AnimationManager.getInstance(); + } + + private initialize() { + } //================================================= @@ -48,23 +47,24 @@ export class HomebridgeAnimationAccessory { //================================================= // Start Setters // async setOn(value: CharacteristicValue) { + console.log(value) this.accessoryState.isOn = value as boolean; - - if (this.animationManager.isActive || !value) { - this.animationManager.clearAnimations() + const isActive = this.animationManager.isAnimationLoopActiveByName(this.animationBlueprint.name); + if (isActive && !value) { + this.animationManager.deactivateAnimationLoopByName(this.animationBlueprint.name) for (const accessory of this.accessoriesList) { - if (accessory.hasAssignedAnimation(this.animationLoop.name)) accessory.restoreBackupAccessoryState(); + if (accessory.hasAssignedAnimation(this.animationBlueprint.name)) accessory.restoreBackupAccessoryState(); } - } else if (value) { + } else if (!isActive && value) { const controllers = this.accessoriesList - .filter(accessory => accessory.hasAssignedAnimation(this.animationLoop.name)) + .filter(accessory => accessory.hasAssignedAnimation(this.animationBlueprint.name)) .map(accessory => { accessory.setBackupAccessoryState(); return accessory.getController(); }); - await this.animationManager.animateAsynchronously(controllers, this.animationLoop).catch(e => { }) + this.animationManager.activateAnimationLoopByName(this.animationBlueprint.name); } } @@ -75,7 +75,8 @@ export class HomebridgeAnimationAccessory { this.accessoriesList.filter(accessory => { return accessory.isReadyToAnimate(); }).forEach(accessory => { - accessory.addAssignedAnimation(this.animationLoop.name); + accessory.addAssignedAnimation(this.animationBlueprint.name); + this.animationManager.addLightToAnimationLoop(accessory.getController(), this.animationBlueprint) }); } @@ -84,7 +85,8 @@ export class HomebridgeAnimationAccessory { this.logs.info("Unassigning All Devices.") this.accessoriesList.forEach( accessory => { - accessory.removeAssignedAnimation(this.animationLoop.name); + accessory.removeAssignedAnimation(this.animationBlueprint.name); + this.animationManager.removeLightFromAnimationLoop(accessory.getController(), this.animationBlueprint); }); } diff --git a/src/platform.ts b/src/platform.ts index e323b6c..a76e907 100644 --- a/src/platform.ts +++ b/src/platform.ts @@ -40,7 +40,7 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin public readonly accessoriesFromDiskMap: Map = new Map(); private readonly hbLogger: Logging; private readonly log: Logs; - animationsFromDiskMap:Map = new Map(); + animationsFromDiskMap: Map = new Map(); constructor( logging: Logging, config: PlatformConfig, @@ -83,11 +83,13 @@ export class HomebridgeMagichomeDynamicPlatform implements DynamicPlatformPlugin this.accessoriesFromDiskMap.set(homebridgeUUID, accessory); this.log.info(`${this.accessoriesFromDiskMap.size} - Loading accessory from cache: ${accessory.context.displayName}`); } else { - const homebridgeUUID = this.hap.uuid.generate(accessory.context.animationLoop.name); + + const homebridgeUUID = this.hap.uuid.generate(accessory.context.animationBlueprint.name); + + this.animationsFromDiskMap.set(homebridgeUUID, accessory); // const homebridgeUUID = accessory.context.animationLoop; - this.animationsFromDiskMap.set(homebridgeUUID, accessory); } diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index a1fd3ed..c914d5a 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -35,6 +35,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected queue; protected lastValue: number; + public uuid: string; lastHue: number; lastBrightness: number; waitingSendoff: boolean; @@ -77,6 +78,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.fetchDeviceState(2); this.isCountingTime = false; this.lastValue = this.accessoryState.HSV.value; + this.uuid = this.accessory.UUID; this.periodicScan(); } From 4a5b001be3cf5a7153fbe5a48055f0fdf86a9439 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Mon, 3 Jul 2023 18:12:12 -0400 Subject: [PATCH 41/42] Update platformAccessory.ts --- src/platformAccessory.ts | 88 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 2 deletions(-) diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index c914d5a..8db7017 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -285,6 +285,31 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // console.log(`${valueType} value: ${value}`); // } +<<<<<<< Updated upstream +======= + getBrightness() { + const { HSV: { value }, TB: { brightness } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); + + this.fetchAndUpdateState(2); + return value; + } + + /** + ** @getOn + * instantly retrieve the current on/off state stored in our object + * next call this.getState() which will update all values asynchronously as they are ready + */ + async getOn() { + await this.updateLocalState(this.readRequestLevel, null).catch(e => { console.log('fetchAndUpdateState ERROR', e) }); + + const { deviceState } = await this.controller.getCachedDeviceInformation(); + const { isOn } = this.deviceStateToAccessoryState(deviceState); + + this.fetchAndUpdateState(2); + return isOn; + } + +>>>>>>> Stashed changes flashEffect() { // } //flashEffect @@ -292,6 +317,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // End LightEffects // +<<<<<<< Updated upstream protected processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { if (this.waitingSendoff) { return; @@ -310,6 +336,20 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand); } }, 50); +======= + //TODO, Severe! Bundle commands so that close consecutive changes in hue, sat, and brightness aren't sent as separate commands + protected async processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { + try { + this.setRecentlyControlled(); + this.waitingSendoff = false; + const sanitizedAcessoryCommand = this.completeAccessoryCommand(partialAccessoryCommand); + if (partialAccessoryCommand.isPowerCommand) { + await this.controller.setOn(sanitizedAcessoryCommand.isOn); + } else { + const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); + await this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand); + } +>>>>>>> Stashed changes } catch (error) { // console.log('processAccessoryCommand: ', error); } @@ -406,19 +446,46 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected sendCommand(deviceCommand: IDeviceCommand, commandOptions: ICommandOptions, accessoryCommand) { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); try { +<<<<<<< Updated upstream this.controller.setAllValues(deviceCommand, commandOptions); +======= + this.controller.setAllValues(deviceCommand, commandOptions).catch(e => { this.logs.warn(e) }) +>>>>>>> Stashed changes } catch (error) { // console.log("sendCommand ERROR: ", error); } this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`); } +<<<<<<< Updated upstream updateStateHomekitCharacteristic() { if (this.waitingSendoff) return; // console.log(deviceState) // const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); // console.log(isOn, hue, saturation, value, brightness, temperature) const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.accessoryState; +======= + + + protected async updateLocalState(requestLevel, deviceState) { + + if (!deviceState) deviceState = await this.controller.fetchState().then(res => res).catch(e => { this.logs.warn(e) }); + + this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); + // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; + const { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); + let accessoryState: IAccessoryState; + if (deviceState) { + accessoryState = { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } }; + this.accessoryState = accessoryState; + // console.log(accessoryState) + this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); + } + } + + updateHomekitState() { + let { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); +>>>>>>> Stashed changes this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); @@ -522,7 +589,19 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } +<<<<<<< Updated upstream +======= + async fetchAndUpdateState(requestLevel) { + try { + this.readRequestLevel = requestLevel; + await this.updateLocalState(this.readRequestLevel, null).catch(e => { console.log('fetchAndUpdateState ERROR', e) }); + // this.updateHomekitState(); + } catch (error) { + this.hbLogger.error(error); + } + } +>>>>>>> Stashed changes getController() { return this.controller; @@ -532,14 +611,14 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding On characteristic to service.`); this.service.getCharacteristic(this.hap.Characteristic.On) .onSet(this.setOn.bind(this)) - .onGet(this.getOn.bind(this)); + // .onGet(this.getOn.bind(this)); } addHueCharacteristic() { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Hue characteristic to service.`); this.service.getCharacteristic(this.hap.Characteristic.Hue) .onSet(this.setHue.bind(this)) - .onGet(this.getHue.bind(this)); + // .onGet(this.getHue.bind(this)); } addSaturationCharacteristic() { @@ -553,6 +632,7 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { addBrightnessCharacteristic() { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); this.service.getCharacteristic(this.hap.Characteristic.Brightness) +<<<<<<< Updated upstream .onSet(this.setValue.bind(this)) .onGet(this.getValue.bind(this)); @@ -567,6 +647,10 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // .onSet(this.setBrightness2.bind(this)) // // .onGet(this.getBrightness2.bind(this)); } +======= + .onSet(this.setBrightness.bind(this)) + // .onGet(this.getBrightness.bind(this)); +>>>>>>> Stashed changes } addColorTemperatureCharacteristic() { From 90cd3dbbb1ab9af0252a96d2b7295639b97962f7 Mon Sep 17 00:00:00 2001 From: Zacknetic Date: Mon, 3 Jul 2023 18:16:22 -0400 Subject: [PATCH 42/42] Update platformAccessory.ts --- src/platformAccessory.ts | 85 ---------------------------------------- 1 file changed, 85 deletions(-) diff --git a/src/platformAccessory.ts b/src/platformAccessory.ts index 8db7017..5cc124e 100644 --- a/src/platformAccessory.ts +++ b/src/platformAccessory.ts @@ -285,31 +285,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // console.log(`${valueType} value: ${value}`); // } -<<<<<<< Updated upstream -======= - getBrightness() { - const { HSV: { value }, TB: { brightness } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); - - this.fetchAndUpdateState(2); - return value; - } - - /** - ** @getOn - * instantly retrieve the current on/off state stored in our object - * next call this.getState() which will update all values asynchronously as they are ready - */ - async getOn() { - await this.updateLocalState(this.readRequestLevel, null).catch(e => { console.log('fetchAndUpdateState ERROR', e) }); - - const { deviceState } = await this.controller.getCachedDeviceInformation(); - const { isOn } = this.deviceStateToAccessoryState(deviceState); - - this.fetchAndUpdateState(2); - return isOn; - } - ->>>>>>> Stashed changes flashEffect() { // } //flashEffect @@ -317,7 +292,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { //================================================= // End LightEffects // -<<<<<<< Updated upstream protected processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { if (this.waitingSendoff) { return; @@ -336,20 +310,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand); } }, 50); -======= - //TODO, Severe! Bundle commands so that close consecutive changes in hue, sat, and brightness aren't sent as separate commands - protected async processAccessoryCommand(partialAccessoryCommand: IPartialAccessoryCommand) { - try { - this.setRecentlyControlled(); - this.waitingSendoff = false; - const sanitizedAcessoryCommand = this.completeAccessoryCommand(partialAccessoryCommand); - if (partialAccessoryCommand.isPowerCommand) { - await this.controller.setOn(sanitizedAcessoryCommand.isOn); - } else { - const { deviceCommand, commandOptions } = this.accessoryCommandToDeviceCommand(sanitizedAcessoryCommand); - await this.sendCommand(deviceCommand, commandOptions, sanitizedAcessoryCommand); - } ->>>>>>> Stashed changes } catch (error) { // console.log('processAccessoryCommand: ', error); } @@ -446,46 +406,19 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { protected sendCommand(deviceCommand: IDeviceCommand, commandOptions: ICommandOptions, accessoryCommand) { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Outgoing Command:`, deviceCommand); try { -<<<<<<< Updated upstream this.controller.setAllValues(deviceCommand, commandOptions); -======= - this.controller.setAllValues(deviceCommand, commandOptions).catch(e => { this.logs.warn(e) }) ->>>>>>> Stashed changes } catch (error) { // console.log("sendCommand ERROR: ", error); } this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - After sending command, received response from device:`); } -<<<<<<< Updated upstream updateStateHomekitCharacteristic() { if (this.waitingSendoff) return; // console.log(deviceState) // const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); // console.log(isOn, hue, saturation, value, brightness, temperature) const { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.accessoryState; -======= - - - protected async updateLocalState(requestLevel, deviceState) { - - if (!deviceState) deviceState = await this.controller.fetchState().then(res => res).catch(e => { this.logs.warn(e) }); - - this.logs.debug(`[${this.accessory.context.displayName}] - Device State:\n`, deviceState); - // this.accessory.context.cachedDeviceInformation.deviceState = deviceState; - const { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(deviceState); - let accessoryState: IAccessoryState; - if (deviceState) { - accessoryState = { HSV: { hue, saturation, value }, isOn, TB: { brightness, temperature } }; - this.accessoryState = accessoryState; - // console.log(accessoryState) - this.logs.debug(`[${this.accessory.context.displayName}] - Homebridge State:\n`, accessoryState); - } - } - - updateHomekitState() { - let { isOn, HSV: { hue, saturation, value }, TB: { brightness, temperature } } = this.deviceStateToAccessoryState(this.controller.getCachedDeviceInformation().deviceState); ->>>>>>> Stashed changes this.service.updateCharacteristic(this.hap.Characteristic.On, isOn); this.service.updateCharacteristic(this.hap.Characteristic.Saturation, saturation); @@ -589,19 +522,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { } -<<<<<<< Updated upstream - -======= - async fetchAndUpdateState(requestLevel) { - try { - this.readRequestLevel = requestLevel; - await this.updateLocalState(this.readRequestLevel, null).catch(e => { console.log('fetchAndUpdateState ERROR', e) }); - // this.updateHomekitState(); - } catch (error) { - this.hbLogger.error(error); - } - } ->>>>>>> Stashed changes getController() { return this.controller; @@ -632,7 +552,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { addBrightnessCharacteristic() { this.logs.trace(`[Trace] [${this.accessory.context.displayName}] - Adding Brightness characteristic to service.`); this.service.getCharacteristic(this.hap.Characteristic.Brightness) -<<<<<<< Updated upstream .onSet(this.setValue.bind(this)) .onGet(this.getValue.bind(this)); @@ -647,10 +566,6 @@ export class HomebridgeMagichomeDynamicPlatformAccessory { // .onSet(this.setBrightness2.bind(this)) // // .onGet(this.getBrightness2.bind(this)); } -======= - .onSet(this.setBrightness.bind(this)) - // .onGet(this.getBrightness.bind(this)); ->>>>>>> Stashed changes } addColorTemperatureCharacteristic() {