diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..818e9dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**/node_modules +**/bin diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..76b1657 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "preLaunchTask": "build and install", + "program": "/Users/brandonwatson/.npm-global/bin/homebridge", + "sourceMaps": true, + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..ad92e87 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "build", + "problemMatcher": [] + }, + { + "type": "shell", + "label": "build and install", + "command": "npm run build&&sudo npm install -g --unsafe-perm ." + } + ] +} \ No newline at end of file diff --git a/homebridge-flux.code-workspace b/homebridge-flux.code-workspace new file mode 100644 index 0000000..362d7c2 --- /dev/null +++ b/homebridge-flux.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..69ae266 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,474 @@ +{ + "name": "homebridge-flux", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + } + }, + "bonjour-hap": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/bonjour-hap/-/bonjour-hap-3.5.4.tgz", + "integrity": "sha512-MgU27SEZYQ09Skm71Xa7SZoAg259V4IlAJNWaloFVMlYDn1OjJy3nkwSixRHnDzrcLWocVI84f9exI1ObZChBw==", + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^7.2.0", + "multicast-dns-service-types": "^1.1.0" + } + }, + "bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "decimal.js": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-7.5.1.tgz", + "integrity": "sha512-1K5Y6MykxQYfHBcFfAj2uBaLmwreq4MsjsvrlgcEOvg+X82IeeXlIVIVkBMiypksu+yo9vcYP6lfU3qTedofSQ==" + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "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==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + }, + "dns-packet": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-4.2.0.tgz", + "integrity": "sha512-bn1AKpfkFbm0MIioOMHZ5qJzl2uypdBwI4nYNsqvhjsegBhcKJUlCrMPWLx6JEezRjxZmxhtIz/FkBEur2l8Cw==", + "requires": { + "ip": "^1.1.5", + "safe-buffer": "^5.1.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "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" + } + }, + "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=" + }, + "fast-srp-hap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-srp-hap/-/fast-srp-hap-1.0.1.tgz", + "integrity": "sha1-N3Ek0Za8alFXquWze/X6NbtK0tk=" + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-ssl-certificate": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/get-ssl-certificate/-/get-ssl-certificate-2.3.3.tgz", + "integrity": "sha512-aKYXS1S5+2IYw4W5+lKC/M+lvaNYPe0PhnQ144NWARcBg35H3ZvyVZ6y0LNGtiAxggFBHeO7LaVGO4bgHK4g1Q==" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, + "hap-nodejs": { + "version": "0.4.51", + "resolved": "https://registry.npmjs.org/hap-nodejs/-/hap-nodejs-0.4.51.tgz", + "integrity": "sha512-d+b0KsakGRC5IgYBBCuqkAFzj8iKAHVw0bKreT8vmhK4b43FTVWiSwi5MWXApoYQUkbPux+xnVYqwMo+Zviieg==", + "requires": { + "bonjour-hap": "^3.5.1", + "buffer-shims": "^1.0.0", + "debug": "^2.2.0", + "decimal.js": "^7.2.3", + "fast-srp-hap": "^1.0.1", + "ip": "^1.1.3", + "node-persist": "^0.0.11", + "tweetnacl": "^1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "node-persist": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.11.tgz", + "integrity": "sha1-1m66Pr72IPB5Uw+nsTB2qQZmWHQ=", + "requires": { + "mkdirp": "~0.5.1", + "q": "~1.1.1" + } + } + } + }, + "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-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "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==" + }, + "homebridge": { + "version": "0.4.53", + "resolved": "https://registry.npmjs.org/homebridge/-/homebridge-0.4.53.tgz", + "integrity": "sha512-yi8GEKVEkQWeOE9CPmZiu+7dZzeiqzVX/P8suTd2h1hjXHiuots3UdZunEY4MOwNNPc8w62m47T9pbK6RZM4WA==", + "requires": { + "chalk": "^1.1.1", + "commander": "2.8.1", + "hap-nodejs": "0.4.51", + "node-persist": "^0.0.8", + "qrcode-terminal": "^0.11.0", + "semver": "5.0.3" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==" + }, + "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==" + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "requires": { + "has": "^1.0.3" + } + }, + "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==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "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==", + "requires": { + "dns-packet": "^4.0.0", + "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=" + }, + "node-hue-api": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/node-hue-api/-/node-hue-api-4.0.5.tgz", + "integrity": "sha512-g/6cEB6m9e20bf1T8wmHvK8r6dqtgn5xS0l2WRGYts7jxEk7amTn2HkDyvgmaS5QTvH8gkeFNrpjq2IxyrVBcw==", + "requires": { + "axios": "^0.19.0", + "bottleneck": "^2.19.5", + "get-ssl-certificate": "^2.3.3" + } + }, + "node-persist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/node-persist/-/node-persist-0.0.8.tgz", + "integrity": "sha1-pWxzm8b/2c7vGcDo2JWXkX8Ikkk=", + "requires": { + "mkdirp": "~0.3.5", + "q": "~1.1.1" + }, + "dependencies": { + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=" + } + } + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" + }, + "object-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", + "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==" + }, + "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.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "q": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/q/-/q-1.1.2.tgz", + "integrity": "sha1-Y1fikSBnAdmfGXq4TlforRlvKok=" + }, + "qrcode-terminal": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", + "integrity": "sha1-/8bCii/Av7RwUrR+I/T0RqX7254=" + }, + "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==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=" + }, + "string.prototype.trimend": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz", + "integrity": "sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz", + "integrity": "sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..7867a65 --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "homebridge-flux", + "version": "1.0.0", + "description": "", + "main": "bin/index.js", + "scripts": { + "build": "tsc", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "ssh://git@watsonb8.ddns.net:2122/home/homebridge-flux.git" + }, + "keywords": [ + "homebridge-plugin", + "Hue", + "f.lux", + "typescript" + ], + "engines": { + "homebridge": ">=0.4.21", + "node": ">=7.6.0" + }, + "author": "Brandon Watson", + "license": "ISC", + "dependencies": { + "homebridge": "^0.4.53", + "node-hue-api": "^4.0.5" + } +} \ No newline at end of file diff --git a/src/fluxAccessory.ts b/src/fluxAccessory.ts new file mode 100644 index 0000000..60c72fa --- /dev/null +++ b/src/fluxAccessory.ts @@ -0,0 +1,100 @@ +import { IAccessory } from "./models/iAccessory"; +import Api = require("node-hue-api/lib/api/Api"); +import Light = require("node-hue-api/lib/model/Light"); +import LightState = require("node-hue-api/lib/model/lightstate/LightState"); +import { Sleep } from "./sleep"; + +let Service: HAPNodeJS.Service; +let Characteristic: HAPNodeJS.Characteristic; + +export interface IFluxProps { + api: any; + log: any; + homebridge: any; + hue: Api +} + +export class FluxAccessory implements IAccessory { + private _api: any; + private _homebridge: any; + private _log: any = {}; + + //Service fields + private _switchService: HAPNodeJS.Service; + private _infoService: HAPNodeJS.Service; + + private _isActive: boolean; + private _hue: Api; + + private _lights: Array = []; + + private _brightness: number = 0; + + constructor(props: IFluxProps) { + //Assign class variables + this._log = props.log; + this._api = props.api; + Service = props.api.hap.Service; + Characteristic = props.api.hap.Characteristic; + this._homebridge = props.homebridge; + + this._isActive = false; + this._hue = props.hue; + + this.platformAccessory = new this._homebridge.platformAccessory(this.name, this.generateUUID(), this._homebridge.hap.Accessory.Categories.SWITCH); + + //@ts-ignore + this._infoService = new Service.AccessoryInformation(); + this._infoService.setCharacteristic(Characteristic.Manufacturer, "Brandon Watson") + this._infoService.setCharacteristic(Characteristic.Model, "F.lux") + this._infoService.setCharacteristic(Characteristic.SerialNumber, "123-456-789"); + + this._switchService = new Service.Switch( + this.name, + 'fluxService' + ) + + this._switchService.getCharacteristic(Characteristic.On) + //@ts-ignore + // .on("set", this.onPowerSet) + // .on("get", this.onPowerGet); + } + + public name: string = "Flux"; + + public platformAccessory: any; + + + public getServices(): HAPNodeJS.Service[] { + throw new Error("Method not implemented."); + } + + /** + * Helper function to convert a hex string to rgb + * @param hex hex string starting with "#" + */ + private hexToRgb = (hex: string): { red: number, green: number, blue: number } | null => { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + red: parseInt(result[1], 16), + green: parseInt(result[2], 16), + blue: parseInt(result[3], 16) + } : null; + } + + /** + * Helper function to generate a UUID + */ + private generateUUID(): string { // Public Domain/MIT + var d = new Date().getTime(); + if (typeof performance !== 'undefined' && typeof performance.now === 'function') { + d += performance.now(); //use high-precision timer if available + } + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); + }); + } + +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..ac0f963 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,104 @@ +import { IConfig, ISequence } from "./models/iConfig"; +import { v3 } from 'node-hue-api'; +import LocalBootstrap = require("node-hue-api/lib/api/http/LocalBootstrap"); +import Api = require("node-hue-api/lib/api/Api"); +import { Sleep } from "./sleep"; +import { IAccessory } from "./models/iAccessory"; +import { FluxAccessory } from "./fluxAccessory"; + +let Accessory: any; +let Homebridge: any; + +/** + * Main entry. + * @param homebridge + */ +export default function (homebridge: any) { + Homebridge = homebridge; + Accessory = homebridge.platformAccessory; + homebridge.registerPlatform( + 'homebridge-flux', + 'Flux', + FluxPlatform, + true + ); +}; + +class FluxPlatform { + log: any = {}; + api: any; + accessoryList: Array = []; + config: IConfig; + hue: Api | undefined; + + + constructor(log: any, config: any, api: any) { + this.log = log; + this.api = api; + this.config = config; + this.log('INFO - Registering Hue Chase platform'); + this.api.on('didFinishLaunching', this.didFinishLaunching.bind(this)); + } + + private connectHue = async () => { + if (!this.config) { + return; + } + + if (this.config.userName && this.config.clientKey) { + this.hue = await v3.api.createLocal(this.config.ipAddress).connect(this.config.userName, this.config.clientKey, undefined); + this.log("Using existing connection info"); + } else { + const unauthenticatedApi = await v3.api.createLocal(this.config.ipAddress).connect(undefined, undefined, undefined); + let createdUser; + let connected = false + while (!connected) { + try { + this.log("Creating hue user. Push link button") + createdUser = await unauthenticatedApi.users.createUser("homebridge", "HueChase"); + + this.hue = await v3.api.createLocal(this.config.ipAddress).connect(createdUser.username, createdUser.clientKey, undefined); + this.log("Connected to Hue Bridge"); + this.log(`UserName: ${createdUser.username}, ClientKey: ${createdUser.clientkey}`) + connected = true; + + } catch (err) { + if (err.getHueErrorType() === 101) { + this.log('The Link button on the bridge was not pressed. Please press the Link button and try again.'); + Sleep(5000); + } else { + this.log(`Unexpected Error: ${err.message}`); + break; + } + + } + } + } + } + + /** + * Handler for didFinishLaunching + * Happens after constructor + */ + private didFinishLaunching() { + this.log(`INFO - Done registering Hue Chase platform`); + } + + /** + * Called by homebridge to gather accessories. + * @param callback + */ + public accessories = async (callback: (accessories: Array) => void) => { + //Connect to hue bridge + await this.connectHue(); + + this.accessoryList.push(new FluxAccessory({ + api: this.api, + log: this.log, + homebridge: Homebridge, + hue: this.hue!, + })); + + callback(this.accessoryList); + } +} \ No newline at end of file diff --git a/src/models/hapNodeJS.d.ts b/src/models/hapNodeJS.d.ts new file mode 100644 index 0000000..ac9620e --- /dev/null +++ b/src/models/hapNodeJS.d.ts @@ -0,0 +1,456 @@ +declare namespace HAPNodeJS { + + export interface uuid { + generate(data: string): string; + isValid(UUID: string): boolean; + unparse(bug: string, offset: number): string; + } + + type EventService = "characteristic-change" | "service-configurationChange" + + export interface IEventEmitterAccessory { + addListener(event: EventService, listener: Function): this; + on(event: EventService, listener: Function): this; + once(event: EventService, listener: Function): this; + removeListener(event: EventService, listener: Function): this; + removeAllListeners(event?: EventService): this; + setMaxListeners(n: number): this; + getMaxListeners(): number; + listeners(event: EventService): Function[]; + emit(event: EventService, ...args: any[]): boolean; + listenerCount(type: string): number; + } + + export interface Service extends IEventEmitterAccessory { + new(displayName: string, UUID: string, subtype: string): Service; + + displayName: string; + UUID: string; + subtype: string; + iid: string; + characteristics: Characteristic[]; + optionalCharacteristics: Characteristic[]; + + addCharacteristic(characteristic: Characteristic | Function): Characteristic; + removeCharacteristic(characteristic: Characteristic): void; + getCharacteristic(name: string | Function): Characteristic; + testCharacteristic(name: string | Function): boolean; + setCharacteristic(name: string | Function, value: CharacteristicValue): Service; + updateCharacteristic(name: string | Function, value: CharacteristicValue): Service; + addOptionalCharacteristic(characteristic: Characteristic | Function): void; + getCharacteristicByIID(iid: string): Characteristic; + + toHAP(opt: any): JSON; + + AccessoryInformation: PredefinedService; + AirPurifier: PredefinedService; + AirQualitySensor: PredefinedService; + BatteryService: PredefinedService; + BridgeConfiguration: PredefinedService; + BridgingState: PredefinedService; + CameraControl: PredefinedService; + CameraRTPStreamManagement: PredefinedService; + CarbonDioxideSensor: PredefinedService; + CarbonMonoxideSensor: PredefinedService; + ContactSensor: PredefinedService; + Door: PredefinedService; + Doorbell: PredefinedService; + Fan: PredefinedService; + Fanv2: PredefinedService; + Faucet: PredefinedService; + FilterMaintenance: PredefinedService; + GarageDoorOpener: PredefinedService; + HeaterCooler: PredefinedService; + HumidifierDehumidifier: PredefinedService; + HumiditySensor: PredefinedService; + InputSource: PredefinedService; + IrrigationSystem: PredefinedService; + LeakSensor: PredefinedService; + LightSensor: PredefinedService; + Lightbulb: PredefinedService; + LockManagement: PredefinedService; + LockMechanism: PredefinedService; + Microphone: PredefinedService; + MotionSensor: PredefinedService; + OccupancySensor: PredefinedService; + Outlet: PredefinedService; + Pairing: PredefinedService; + ProtocolInformation: PredefinedService; + Relay: PredefinedService; + SecuritySystem: PredefinedService; + ServiceLabel: PredefinedService; + Slat: PredefinedService; + SmokeSensor: PredefinedService; + Speaker: PredefinedService; + StatefulProgrammableSwitch: PredefinedService; + StatelessProgrammableSwitch: PredefinedService; + Switch: PredefinedService; + Television: PredefinedService; + TelevisionSpeaker: PredefinedService; + TemperatureSensor: PredefinedService; + Thermostat: PredefinedService; + TimeInformation: PredefinedService; + TunneledBTLEAccessoryService: PredefinedService; + Valve: PredefinedService; + Window: PredefinedService; + WindowCovering: PredefinedService; + } + + export interface PredefinedService { + new(displayName: string, subtype: string): Service; + } + + export interface CameraSource { + + } + + type EventAccessory = "service-configurationChange" | "service-characteristic-change" | "identify" + + export interface IEventEmitterAccessory { + addListener(event: EventAccessory, listener: Function): this; + on(event: EventAccessory, listener: Function): this; + once(event: EventAccessory, listener: Function): this; + removeListener(event: EventAccessory, listener: Function): this; + removeAllListeners(event?: EventAccessory): this; + setMaxListeners(n: number): this; + getMaxListeners(): number; + listeners(event: EventAccessory): Function[]; + emit(event: EventAccessory, ...args: any[]): boolean; + listenerCount(type: string): number; + } + + export interface CharacteristicProps { + format: Characteristic.Formats; + unit: Characteristic.Units, + minValue: number, + maxValue: number, + minStep: number, + perms: Characteristic.Perms[] + } + + type EventCharacteristic = "get" | "set" + type CharacteristicValue = boolean | string | number + + export type CharacteristicGetCallback = (error: Error | null, value: T) => void + export type CharacteristicSetCallback = (error?: Error | null) => void + export type CharacteristicCallback = CharacteristicGetCallback | CharacteristicSetCallback + + export interface IEventEmitterCharacteristic { + addListener(event: EventCharacteristic, listener: CharacteristicCallback): this; + on(event: EventCharacteristic, listener: CharacteristicCallback): this; + once(event: EventCharacteristic, listener: CharacteristicCallback): this; + removeListener(event: EventCharacteristic, listener: CharacteristicCallback): this; + removeAllListeners(event?: EventCharacteristic): this; + setMaxListeners(n: number): this; + getMaxListeners(): number; + listeners(event: EventCharacteristic): CharacteristicCallback[]; + emit(event: EventCharacteristic, ...args: any[]): boolean; + listenerCount(type: string): number; + } + + export interface Characteristic extends IEventEmitterCharacteristic { + new(displayName: string, UUID: string, props?: CharacteristicProps): Characteristic; + + Formats: typeof Characteristic.Formats; + Units: typeof Characteristic.Units; + Perms: typeof Characteristic.Perms; + + setProps(props: CharacteristicProps): Characteristic + getValue(callback?: CharacteristicGetCallback, context?: any, connectionID?: string): void; + setValue(newValue: CharacteristicValue, callback?: CharacteristicSetCallback, context?: any, connectionID?: string): Characteristic; + updateValue(newValue: CharacteristicValue, callback?: () => void, context?: any): Characteristic; + getDefaultValue(): CharacteristicValue; + toHAP(opt: any): JSON; + + AccessoryFlags: Characteristic; + AccessoryIdentifier: Characteristic; + Active: Characteristic; + ActiveIdentifier: Characteristic; + AdministratorOnlyAccess: Characteristic; + AirParticulateDensity: Characteristic; + AirParticulateSize: Characteristic; + AirQuality: Characteristic; + AppMatchingIdentifier: Characteristic; + AudioFeedback: Characteristic; + BatteryLevel: Characteristic; + Brightness: Characteristic; + CarbonDioxideDetected: Characteristic; + CarbonDioxideLevel: Characteristic; + CarbonDioxidePeakLevel: Characteristic; + CarbonMonoxideDetected: Characteristic; + CarbonMonoxideLevel: Characteristic; + CarbonMonoxidePeakLevel: Characteristic; + Category: Characteristic; + ChargingState: Characteristic; + ClosedCaptions: Characteristic; + ColorTemperature: Characteristic; + ConfigureBridgedAccessory: Characteristic; + ConfigureBridgedAccessoryStatus: Characteristic; + ConfiguredName: Characteristic; + ContactSensorState: Characteristic; + CoolingThresholdTemperature: Characteristic; + CurrentAirPurifierState: Characteristic; + CurrentAmbientLightLevel: Characteristic; + CurrentDoorState: Characteristic; + CurrentFanState: Characteristic; + CurrentHeaterCoolerState: Characteristic; + CurrentHeatingCoolingState: Characteristic; + CurrentHorizontalTiltAngle: Characteristic; + CurrentHumidifierDehumidifierState: Characteristic; + CurrentMediaState: Characteristic; + CurrentPosition: Characteristic; + CurrentRelativeHumidity: Characteristic; + CurrentSlatState: Characteristic; + CurrentTemperature: Characteristic; + CurrentTiltAngle: Characteristic; + CurrentTime: Characteristic; + CurrentVerticalTiltAngle: Characteristic; + CurrentVisibilityState: Characteristic; + DayoftheWeek: Characteristic; + DigitalZoom: Characteristic; + DiscoverBridgedAccessories: Characteristic; + DiscoveredBridgedAccessories: Characteristic; + DisplayOrder: Characteristic; + FilterChangeIndication: Characteristic; + FilterLifeLevel: Characteristic; + FirmwareRevision: Characteristic; + HardwareRevision: Characteristic; + HeatingThresholdTemperature: Characteristic; + HoldPosition: Characteristic; + Hue: Characteristic; + Identifier: Characteristic; + Identify: Characteristic; + ImageMirroring: Characteristic; + ImageRotation: Characteristic; + InUse: Characteristic; + InputDeviceType: Characteristic; + InputSourceType: Characteristic; + IsConfigured: Characteristic; + LeakDetected: Characteristic; + LinkQuality: Characteristic; + LockControlPoint: Characteristic; + LockCurrentState: Characteristic; + LockLastKnownAction: Characteristic; + LockManagementAutoSecurityTimeout: Characteristic; + LockPhysicalControls: Characteristic; + LockTargetState: Characteristic; + Logs: Characteristic; + Manufacturer: Characteristic; + Model: Characteristic; + MotionDetected: Characteristic; + Mute: Characteristic; + Name: Characteristic; + NightVision: Characteristic; + NitrogenDioxideDensity: Characteristic; + ObstructionDetected: Characteristic; + OccupancyDetected: Characteristic; + On: Characteristic; + OpticalZoom: Characteristic; + OutletInUse: Characteristic; + OzoneDensity: Characteristic; + PM10Density: Characteristic; + PM2_5Density: Characteristic; + PairSetup: Characteristic; + PairVerify: Characteristic; + PairingFeatures: Characteristic; + PairingPairings: Characteristic; + PictureMode: Characteristic; + PositionState: Characteristic; + PowerModeSelection: Characteristic; + ProgramMode: Characteristic; + ProgrammableSwitchEvent: Characteristic; + ProgrammableSwitchOutputState: Characteristic; + Reachable: Characteristic; + RelativeHumidityDehumidifierThreshold: Characteristic; + RelativeHumidityHumidifierThreshold: Characteristic; + RelayControlPoint: Characteristic; + RelayEnabled: Characteristic; + RelayState: Characteristic; + RemainingDuration: Characteristic; + RemoteKey: Characteristic; + ResetFilterIndication: Characteristic; + RotationDirection: Characteristic; + RotationSpeed: Characteristic; + Saturation: Characteristic; + SecuritySystemAlarmType: Characteristic; + SecuritySystemCurrentState: Characteristic; + SecuritySystemTargetState: Characteristic; + SelectedRTPStreamConfiguration: Characteristic; + SerialNumber: Characteristic; + ServiceLabelIndex: Characteristic; + ServiceLabelNamespace: Characteristic; + SetDuration: Characteristic; + SetupEndpoints: Characteristic; + SlatType: Characteristic; + SleepDiscoveryMode: Characteristic; + SmokeDetected: Characteristic; + SoftwareRevision: Characteristic; + StatusActive: Characteristic; + StatusFault: Characteristic; + StatusJammed: Characteristic; + StatusLowBattery: Characteristic; + StatusTampered: Characteristic; + StreamingStatus: Characteristic; + SulphurDioxideDensity: Characteristic; + SupportedAudioStreamConfiguration: Characteristic; + SupportedRTPConfiguration: Characteristic; + SupportedVideoStreamConfiguration: Characteristic; + SwingMode: Characteristic; + TargetAirPurifierState: Characteristic; + TargetAirQuality: Characteristic; + TargetDoorState: Characteristic; + TargetFanState: Characteristic; + TargetHeaterCoolerState: Characteristic; + TargetHeatingCoolingState: Characteristic; + TargetHorizontalTiltAngle: Characteristic; + TargetHumidifierDehumidifierState: Characteristic; + TargetMediaState: Characteristic; + TargetPosition: Characteristic; + TargetRelativeHumidity: Characteristic; + TargetSlatState: Characteristic; + TargetTemperature: Characteristic; + TargetTiltAngle: Characteristic; + TargetVerticalTiltAngle: Characteristic; + TargetVisibilityState: Characteristic; + TemperatureDisplayUnits: Characteristic; + TimeUpdate: Characteristic; + TunnelConnectionTimeout: Characteristic; + TunneledAccessoryAdvertising: Characteristic; + TunneledAccessoryConnected: Characteristic; + TunneledAccessoryStateNumber: Characteristic; + VOCDensity: Characteristic; + ValveType: Characteristic; + Version: Characteristic; + Volume: Characteristic; + VolumeControlType: Characteristic; + VolumeSelector: Characteristic; + WaterLevel: Characteristic; + } + + + module Characteristic { + export enum Formats { + BOOL, + INT, + FLOAT, + STRING, + ARRAY, // unconfirmed + DICTIONARY, // unconfirmed + UINT8, + UINT16, + UINT32, + UINT64, + DATA, // unconfirmed + TLV8 + } + + export enum Units { + // HomeKit only defines Celsius, for Fahrenheit, it requires iOS app to do the conversion. + CELSIUS, + PERCENTAGE, + ARC_DEGREE, + LUX, + SECONDS + } + + export enum Perms { + READ, + WRITE, + NOTIFY, + HIDDEN + } + } + + export interface PublishInfo { + port: number; + username: string; + pincode: string; + category: number; + } + + export interface Accessory extends IEventEmitterAccessory { + new(displayName: string, UUID: string): Accessory; + displayName: string; + username: string; + pincode: string; + UUID: string; + aid: string; + bridged: boolean; + bridgedAccessories: Accessory[]; + reachable: boolean; + category: Accessory.Categories; + services: Service[]; + cameraSource: CameraSource; + Categories: typeof Accessory.Categories + addService(service: Service | Function): Service; + removeService(service: Service): void; + getService(name: string | Function): Service; + updateReachability(reachable: boolean): void; + addBridgedAccessory(accessory: Accessory, deferUpdate: boolean): Accessory; + addBridgedAccessories(accessories: Accessory[]): void + removeBridgedAccessory(accessory: Accessory, deferUpdate: boolean): void; + removeBridgedAccessories(accessories: Accessory[]): void; + getCharacteristicByIID(iid: string): Characteristic; + getBridgedAccessoryByAID(aid: string): Accessory; + findCharacteristic(aid: string, iid: string): Accessory; + configureCameraSource(cameraSource: CameraSource): void; + toHAP(opt: any): JSON; + publish(info: PublishInfo, allowInsecureRequest: boolean): void; + destroy(): void; + setupURI(): string; + } + + module Accessory { + export enum Categories { + OTHER = 1, + BRIDGE = 2, + FAN = 3, + GARAGE_DOOR_OPENER = 4, + LIGHTBULB = 5, + DOOR_LOCK = 6, + OUTLET = 7, + SWITCH = 8, + THERMOSTAT = 9, + SENSOR = 10, + ALARM_SYSTEM = 11, + SECURITY_SYSTEM = 11, + DOOR = 12, + WINDOW = 13, + WINDOW_COVERING = 14, + PROGRAMMABLE_SWITCH = 15, + RANGE_EXTENDER = 16, + CAMERA = 17, + IP_CAMERA = 17, + VIDEO_DOORBELL = 18, + AIR_PURIFIER = 19, + AIR_HEATER = 20, + AIR_CONDITIONER = 21, + AIR_HUMIDIFIER = 22, + AIR_DEHUMIDIFIER = 23, + APPLE_TV = 24, + SPEAKER = 26, + AIRPORT = 27, + SPRINKLER = 28, + FAUCET = 29, + SHOWER_HEAD = 30, + TELEVISION = 31, + TARGET_CONTROLLER = 32 + } + } + + export interface HAPNodeJS { + init(storagePath?: string): void, + uuid: uuid, + Accessory: Accessory, + Service: Service, + Characteristic: Characteristic + } + + +} + +declare var hapNodeJS: HAPNodeJS.HAPNodeJS; + +declare module "hap-nodejs" { + export = hapNodeJS; +} \ No newline at end of file diff --git a/src/models/iAccessory.ts b/src/models/iAccessory.ts new file mode 100644 index 0000000..681a8b9 --- /dev/null +++ b/src/models/iAccessory.ts @@ -0,0 +1,14 @@ + +/** + * Interface to describe homebridge required elements. + */ +export interface IAccessory { + /** + * Required by homebridge. + */ + name: string, + /** + * Called by homebridge to gather services. + */ + getServices(): Array, +} \ No newline at end of file diff --git a/src/models/iConfig.ts b/src/models/iConfig.ts new file mode 100644 index 0000000..db14cdb --- /dev/null +++ b/src/models/iConfig.ts @@ -0,0 +1,16 @@ +export interface ISequence { + name: string; + transitionTime: number; + matchAllLights?: boolean; + colors: Array; + lights: Array; +} + +export interface IConfig { + platform: string; + ipAddress: string; + userName?: string; + clientKey?: string; + configLocation: string; + sequences: Array +} \ No newline at end of file diff --git a/src/sleep.ts b/src/sleep.ts new file mode 100644 index 0000000..9e2e118 --- /dev/null +++ b/src/sleep.ts @@ -0,0 +1,3 @@ +export const Sleep = (ms: number) => { + return new Promise(resolve => setTimeout(resolve, ms)); +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7c8c5ee --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,60 @@ +{ + "compilerOptions": { + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "ESNext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./bin", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + /* Advanced Options */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} \ No newline at end of file