diff --git a/README.md b/README.md index c0118688..1baee443 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,12 @@ Please use GitHub issues for this. ## Changelog +### 2.8.1 (2023-08-31) + +* (bropat) Automatic detection of supported P2P encryption (none, type1, type2) +* (bropat) Fixed regression introduced with activating p2p encryption for all devices (some older devices do not support it!) +* (bropat) Updated versions of the package dependencies + ### 2.8.0 (2023-08-20) * (bropat) Implemented p2p data encryption for all supported commands diff --git a/docs/_coverpage.md b/docs/_coverpage.md index 99bee90f..18401f02 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,6 +1,6 @@ ![logo](_media/eufy-security-client.png) -# eufy-security-client 2.8.0 +# eufy-security-client 2.8.1 > This shared library allows to control [Eufy security devices](https://us.eufylife.com/collections/security) by connecting to the Eufy cloud servers and local/remote stations over p2p diff --git a/docs/supported_devices.md b/docs/supported_devices.md index b200076c..add30f56 100644 --- a/docs/supported_devices.md +++ b/docs/supported_devices.md @@ -24,7 +24,7 @@ | ![T8420X image](_media/floodlight_small.jpg) | Floodlight Camera (T8420X) | :heavy_check_mark: | Firmware: 2.0.6.1 (20220824) | | ![T8422 image](_media/floodlight_small.jpg) | Floodlight Cam (T8422) | :heavy_check_mark: | | | ![T8423 image](_media/floodlight2pro_small.jpg) | Floodlight Cam 2 Pro (T8423) | :heavy_check_mark: | Firmware: 1.0.7.4 (20211219) | -| ![T8424 image](_media/floodlight2_small.jpg) | Floodlight Cam 2 (T8424) | :heavy_check_mark: | | +| ![T8424 image](_media/floodlight2_small.jpg) | Floodlight Cam 2 (T8424) | :heavy_check_mark: | Firmware: 2.0.8.8 (20230807) | | ![T84A1 image](_media/walllight_s100_small.jpg) | Wired Wall Light Cam S100 (T84A1) | :heavy_check_mark: | Firmware: 1.0.8.2 (20230521) | | ![T8200 image](_media/wireddoorbell2k_small.jpg) | Wired Doorbell 2k (T8200) | :heavy_check_mark: | | | ![T8200X image](_media/wireddoorbell2k_small.jpg) | Wired Doorbell 2k (T8200X) | :heavy_check_mark: | Firmware: 2.0.6.0 (20220826) | diff --git a/package-lock.json b/package-lock.json index 412e473a..134a38b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "eufy-security-client", - "version": "2.8.0", + "version": "2.8.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "eufy-security-client", - "version": "2.8.0", + "version": "2.8.1", "license": "MIT", "dependencies": { "@cospired/i18n-iso-languages": "^4.1.0", @@ -17,11 +17,11 @@ "i18n-iso-countries": "^7.6.0", "image-type": "^4.1.0", "long": "^5.2.3", - "mqtt": "^5.0.3", + "mqtt": "^5.0.4", "node-rsa": "^1.1.1", "node-schedule": "^2.1.1", "p-throttle": "^4.1.1", - "protobufjs": "^7.2.4", + "protobufjs": "^7.2.5", "qs": "^6.11.2", "sweet-collections": "^1.1.0", "tiny-typed-emitter": "^2.1.0", @@ -30,14 +30,14 @@ "devDependencies": { "@types/crypto-js": "^4.1.1", "@types/fs-extra": "^11.0.1", - "@types/node": "^16.18.41", + "@types/node": "^16.18.46", "@types/node-rsa": "^1.1.1", "@types/node-schedule": "^2.1.0", "@types/qs": "^6.9.7", - "@typescript-eslint/eslint-plugin": "^6.4.0", - "@typescript-eslint/parser": "^6.4.0", - "eslint": "^8.47.0", - "typescript": "^5.1.6" + "@typescript-eslint/eslint-plugin": "^6.5.0", + "@typescript-eslint/parser": "^6.5.0", + "eslint": "^8.48.0", + "typescript": "^5.2.2" }, "engines": { "node": ">=16.9.0" @@ -108,9 +108,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", - "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", + "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -321,9 +321,9 @@ } }, "node_modules/@types/node": { - "version": "16.18.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.41.tgz", - "integrity": "sha512-YZJjn+Aaw0xihnpdImxI22jqGbp0DCgTFKRycygjGx/Y27NnWFJa5FJ7P+MRT3u07dogEeMVh70pWpbIQollTA==" + "version": "16.18.46", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.46.tgz", + "integrity": "sha512-Mnq3O9Xz52exs3mlxMcQuA7/9VFe/dXcrgAyfjLkABIqxXKOgBRjyazTxUbjsxDa4BP7hhPliyjVTP9RDP14xg==" }, "node_modules/@types/node-rsa": { "version": "1.1.1", @@ -349,6 +349,20 @@ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, + "node_modules/@types/readable-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.2.tgz", + "integrity": "sha512-hhzOsMEISZ+mX1l+01F0duYt9wHEbCGmjARed0PcQoVS5zAdu7u5YbWYuNGhw09M1MgGr3kfsto+ut/MnAdKqA==", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, + "node_modules/@types/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -358,22 +372,30 @@ } }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", "dev": true }, + "node_modules/@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.0.tgz", - "integrity": "sha512-62o2Hmc7Gs3p8SLfbXcipjWAa6qk2wZGChXG2JbBtYpwSRmti/9KHLqfbLs9uDigOexG+3PaQ9G2g3201FWLKg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz", + "integrity": "sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/type-utils": "6.4.0", - "@typescript-eslint/utils": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/type-utils": "6.5.0", + "@typescript-eslint/utils": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -399,15 +421,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.0.tgz", - "integrity": "sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.5.0.tgz", + "integrity": "sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/typescript-estree": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4" }, "engines": { @@ -427,13 +449,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.4.0.tgz", - "integrity": "sha512-TUS7vaKkPWDVvl7GDNHFQMsMruD+zhkd3SdVW0d7b+7Zo+bd/hXJQ8nsiUZMi1jloWo6c9qt3B7Sqo+flC1nig==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz", + "integrity": "sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0" + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -444,13 +466,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.4.0.tgz", - "integrity": "sha512-TvqrUFFyGY0cX3WgDHcdl2/mMCWCDv/0thTtx/ODMY1QhEiyFtv/OlLaNIiYLwRpAxAtOLOY9SUf1H3Q3dlwAg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz", + "integrity": "sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.4.0", - "@typescript-eslint/utils": "6.4.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/utils": "6.5.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -471,9 +493,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", - "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -484,13 +506,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.0.tgz", - "integrity": "sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", + "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -511,17 +533,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.4.0.tgz", - "integrity": "sha512-BvvwryBQpECPGo8PwF/y/q+yacg8Hn/2XS+DqL/oRsOPK+RPt29h5Ui5dqOKHDlbXrAeHUTnyG3wZA0KTDxRZw==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.5.0.tgz", + "integrity": "sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/typescript-estree": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", "semver": "^7.5.4" }, "engines": { @@ -536,12 +558,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", - "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/types": "6.5.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1021,15 +1043,15 @@ } }, "node_modules/eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", - "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", + "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "^8.47.0", + "@eslint/js": "8.48.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1857,10 +1879,12 @@ } }, "node_modules/mqtt": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.0.3.tgz", - "integrity": "sha512-XyCzdCNFm4XXBUV7HQPd1qXYdu7GC/H+wXr+RfaztwZ72/c3sD8yRivOBdh8iKWHc+EGawSeDIvXCnvEykcJVA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.0.4.tgz", + "integrity": "sha512-Ao+DA4QYzIFXTQPIF0WKJfeHM2BV0kbP1xt/POPyJY2dQ02dscUJonh94NG9/aw0Fbk2L8Ex0YxobDSKUyQvcQ==", "dependencies": { + "@types/readable-stream": "^4.0.1", + "@types/ws": "^8.5.5", "commist": "^3.2.0", "concat-stream": "^2.0.0", "debug": "^4.3.4", @@ -2135,9 +2159,9 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/protobufjs": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", - "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", "hasInstallScript": true, "dependencies": { "@protobufjs/aspromise": "^1.1.2", @@ -2521,9 +2545,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -2659,9 +2683,9 @@ } }, "@eslint/js": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", - "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", + "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", "dev": true }, "@humanwhocodes/config-array": { @@ -2841,9 +2865,9 @@ } }, "@types/node": { - "version": "16.18.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.41.tgz", - "integrity": "sha512-YZJjn+Aaw0xihnpdImxI22jqGbp0DCgTFKRycygjGx/Y27NnWFJa5FJ7P+MRT3u07dogEeMVh70pWpbIQollTA==" + "version": "16.18.46", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.46.tgz", + "integrity": "sha512-Mnq3O9Xz52exs3mlxMcQuA7/9VFe/dXcrgAyfjLkABIqxXKOgBRjyazTxUbjsxDa4BP7hhPliyjVTP9RDP14xg==" }, "@types/node-rsa": { "version": "1.1.1", @@ -2869,6 +2893,22 @@ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, + "@types/readable-stream": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.2.tgz", + "integrity": "sha512-hhzOsMEISZ+mX1l+01F0duYt9wHEbCGmjARed0PcQoVS5zAdu7u5YbWYuNGhw09M1MgGr3kfsto+ut/MnAdKqA==", + "requires": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "@types/responselike": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", @@ -2878,22 +2918,30 @@ } }, "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", "dev": true }, + "@types/ws": { + "version": "8.5.5", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz", + "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==", + "requires": { + "@types/node": "*" + } + }, "@typescript-eslint/eslint-plugin": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.4.0.tgz", - "integrity": "sha512-62o2Hmc7Gs3p8SLfbXcipjWAa6qk2wZGChXG2JbBtYpwSRmti/9KHLqfbLs9uDigOexG+3PaQ9G2g3201FWLKg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.5.0.tgz", + "integrity": "sha512-2pktILyjvMaScU6iK3925uvGU87E+N9rh372uGZgiMYwafaw9SXq86U04XPq3UH6tzRvNgBsub6x2DacHc33lw==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/type-utils": "6.4.0", - "@typescript-eslint/utils": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/type-utils": "6.5.0", + "@typescript-eslint/utils": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2903,54 +2951,54 @@ } }, "@typescript-eslint/parser": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.4.0.tgz", - "integrity": "sha512-I1Ah1irl033uxjxO9Xql7+biL3YD7w9IU8zF+xlzD/YxY6a4b7DYA08PXUUCbm2sEljwJF6ERFy2kTGAGcNilg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.5.0.tgz", + "integrity": "sha512-LMAVtR5GN8nY0G0BadkG0XIe4AcNMeyEy3DyhKGAh9k4pLSMBO7rF29JvDBpZGCmp5Pgz5RLHP6eCpSYZJQDuQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/typescript-estree": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.4.0.tgz", - "integrity": "sha512-TUS7vaKkPWDVvl7GDNHFQMsMruD+zhkd3SdVW0d7b+7Zo+bd/hXJQ8nsiUZMi1jloWo6c9qt3B7Sqo+flC1nig==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.5.0.tgz", + "integrity": "sha512-A8hZ7OlxURricpycp5kdPTH3XnjG85UpJS6Fn4VzeoH4T388gQJ/PGP4ole5NfKt4WDVhmLaQ/dBLNDC4Xl/Kw==", "dev": true, "requires": { - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0" + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0" } }, "@typescript-eslint/type-utils": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.4.0.tgz", - "integrity": "sha512-TvqrUFFyGY0cX3WgDHcdl2/mMCWCDv/0thTtx/ODMY1QhEiyFtv/OlLaNIiYLwRpAxAtOLOY9SUf1H3Q3dlwAg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.5.0.tgz", + "integrity": "sha512-f7OcZOkRivtujIBQ4yrJNIuwyCQO1OjocVqntl9dgSIZAdKqicj3xFDqDOzHDlGCZX990LqhLQXWRnQvsapq8A==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "6.4.0", - "@typescript-eslint/utils": "6.4.0", + "@typescript-eslint/typescript-estree": "6.5.0", + "@typescript-eslint/utils": "6.5.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.4.0.tgz", - "integrity": "sha512-+FV9kVFrS7w78YtzkIsNSoYsnOtrYVnKWSTVXoL1761CsCRv5wpDOINgsXpxD67YCLZtVQekDDyaxfjVWUJmmg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.5.0.tgz", + "integrity": "sha512-eqLLOEF5/lU8jW3Bw+8auf4lZSbbljHR2saKnYqON12G/WsJrGeeDHWuQePoEf9ro22+JkbPfWQwKEC5WwLQ3w==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.4.0.tgz", - "integrity": "sha512-iDPJArf/K2sxvjOR6skeUCNgHR/tCQXBsa+ee1/clRKr3olZjZ/dSkXPZjG6YkPtnW6p5D1egeEPMCW6Gn4yLA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.5.0.tgz", + "integrity": "sha512-q0rGwSe9e5Kk/XzliB9h2LBc9tmXX25G0833r7kffbl5437FPWb2tbpIV9wAATebC/018pGa9fwPDuvGN+LxWQ==", "dev": true, "requires": { - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/visitor-keys": "6.4.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/visitor-keys": "6.5.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2959,27 +3007,27 @@ } }, "@typescript-eslint/utils": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.4.0.tgz", - "integrity": "sha512-BvvwryBQpECPGo8PwF/y/q+yacg8Hn/2XS+DqL/oRsOPK+RPt29h5Ui5dqOKHDlbXrAeHUTnyG3wZA0KTDxRZw==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.5.0.tgz", + "integrity": "sha512-9nqtjkNykFzeVtt9Pj6lyR9WEdd8npPhhIPM992FWVkZuS6tmxHfGVnlUcjpUP2hv8r4w35nT33mlxd+Be1ACQ==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.4.0", - "@typescript-eslint/types": "6.4.0", - "@typescript-eslint/typescript-estree": "6.4.0", + "@typescript-eslint/scope-manager": "6.5.0", + "@typescript-eslint/types": "6.5.0", + "@typescript-eslint/typescript-estree": "6.5.0", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.4.0.tgz", - "integrity": "sha512-yJSfyT+uJm+JRDWYRYdCm2i+pmvXJSMtPR9Cq5/XQs4QIgNoLcoRtDdzsLbLsFM/c6um6ohQkg/MLxWvoIndJA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.5.0.tgz", + "integrity": "sha512-yCB/2wkbv3hPsh02ZS8dFQnij9VVQXJMN/gbQsaaY+zxALkZnxa/wagvLEFsAWMPv7d7lxQmNsIzGU1w/T/WyA==", "dev": true, "requires": { - "@typescript-eslint/types": "6.4.0", + "@typescript-eslint/types": "6.5.0", "eslint-visitor-keys": "^3.4.1" } }, @@ -3324,15 +3372,15 @@ "dev": true }, "eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", - "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", + "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "^8.47.0", + "@eslint/js": "8.48.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3948,10 +3996,12 @@ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, "mqtt": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.0.3.tgz", - "integrity": "sha512-XyCzdCNFm4XXBUV7HQPd1qXYdu7GC/H+wXr+RfaztwZ72/c3sD8yRivOBdh8iKWHc+EGawSeDIvXCnvEykcJVA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.0.4.tgz", + "integrity": "sha512-Ao+DA4QYzIFXTQPIF0WKJfeHM2BV0kbP1xt/POPyJY2dQ02dscUJonh94NG9/aw0Fbk2L8Ex0YxobDSKUyQvcQ==", "requires": { + "@types/readable-stream": "^4.0.1", + "@types/ws": "^8.5.5", "commist": "^3.2.0", "concat-stream": "^2.0.0", "debug": "^4.3.4", @@ -4151,9 +4201,9 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "protobufjs": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", - "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -4416,9 +4466,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true }, "universalify": { diff --git a/package.json b/package.json index 0fdc65b4..ecca83b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eufy-security-client", - "version": "2.8.0", + "version": "2.8.1", "description": "Client to comunicate with Eufy-Security devices", "author": { "name": "bropat", @@ -42,7 +42,7 @@ "dependencies": { "got": "^11.8.6", "long": "^5.2.3", - "protobufjs": "^7.2.4", + "protobufjs": "^7.2.5", "qs": "^6.11.2", "node-rsa": "^1.1.1", "crypto-js": "^4.1.1", @@ -52,23 +52,23 @@ "@cospired/i18n-iso-languages": "^4.1.0", "fs-extra": "^11.1.1", "sweet-collections": "^1.1.0", - "mqtt": "^5.0.3", + "mqtt": "^5.0.4", "node-schedule": "^2.1.1", "p-throttle": "^4.1.1", "image-type": "^4.1.0", "date-and-time": "^3.0.2" }, "devDependencies": { - "@types/node": "^16.18.41", + "@types/node": "^16.18.46", "@types/qs": "^6.9.7", "@types/node-rsa": "^1.1.1", "@types/crypto-js": "^4.1.1", "@types/fs-extra": "^11.0.1", "@types/node-schedule": "^2.1.0", - "@typescript-eslint/eslint-plugin": "^6.4.0", - "@typescript-eslint/parser": "^6.4.0", - "eslint": "^8.47.0", - "typescript": "^5.1.6" + "@typescript-eslint/eslint-plugin": "^6.5.0", + "@typescript-eslint/parser": "^6.5.0", + "eslint": "^8.48.0", + "typescript": "^5.2.2" }, "bugs": { "url": "https://github.com/bropat/eufy-security-client/issues" diff --git a/src/eufysecurity.ts b/src/eufysecurity.ts index d3131fd0..6f385a6c 100644 --- a/src/eufysecurity.ts +++ b/src/eufysecurity.ts @@ -18,7 +18,7 @@ import { BatteryDoorbellCamera, Camera, Device, EntrySensor, FloodlightCamera, G import { AlarmEvent, ChargingType, CommandType, DatabaseReturnCode, P2PConnectionType, SmartSafeAlarm911Event, SmartSafeShakeAlarmEvent, TFCardStatus } from "./p2p/types"; import { DatabaseCountByDate, DatabaseQueryLatestInfo, DatabaseQueryLocal, StreamMetadata, DatabaseQueryLatestInfoLocal, DatabaseQueryLatestInfoCloud, RGBColor, DynamicLighting } from "./p2p/interfaces"; import { CommandResult } from "./p2p/models"; -import { generateSerialnumber, generateUDID, handleUpdate, md5, parseValue, removeLastChar, waitForEvent } from "./utils"; +import { generateSerialnumber, generateUDID, getError, handleUpdate, md5, parseValue, removeLastChar, waitForEvent } from "./utils"; import { DeviceNotFoundError, StationNotFoundError, ReadOnlyPropertyError, NotSupportedError, AddUserError, DeleteUserError, UpdateUserUsernameError, UpdateUserPasscodeError, UpdateUserScheduleError, ensureError } from "./error"; import { libVersion } from "."; import { InvalidPropertyError } from "./http/error"; @@ -126,7 +126,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.debug("No stored data from last exit found", error); + this.log.debug("No stored data from last exit found", { error: getError(error) }); } try { @@ -143,7 +143,7 @@ export class EufySecurity extends TypedEmitter { } } catch(err) { const error = ensureError(err); - this.log.error("Handling update - Error", error); + this.log.error("Handling update - Error", { error: getError(error) }); } if (this.config.trustedDeviceName === undefined || this.config.trustedDeviceName === "") { @@ -171,7 +171,7 @@ export class EufySecurity extends TypedEmitter { this.api.on("connection error", (error: Error) => this.onAPIConnectionError(error)); if (this.persistentData.login_hash && this.persistentData.login_hash != "") { - this.log.debug("Load previous login_hash:", this.persistentData.login_hash); + this.log.debug("Load previous login_hash", { login_hash: this.persistentData.login_hash }); if (md5(`${this.config.username}:${this.config.password}`) != this.persistentData.login_hash) { this.log.info("Authentication properties changed, invalidate saved cloud token."); this.persistentData.cloud_token = ""; @@ -189,7 +189,7 @@ export class EufySecurity extends TypedEmitter { this.persistentData.httpApi = undefined; } if (this.persistentData.cloud_token && this.persistentData.cloud_token != "" && this.persistentData.cloud_token_expiration) { - this.log.debug("Load previous token:", { token: this.persistentData.cloud_token, tokenExpiration: this.persistentData.cloud_token_expiration }); + this.log.debug("Load previous token", { token: this.persistentData.cloud_token, tokenExpiration: this.persistentData.cloud_token_expiration }); this.api.setToken(this.persistentData.cloud_token); this.api.setTokenExpiration(new Date(this.persistentData.cloud_token_expiration)); } @@ -201,12 +201,12 @@ export class EufySecurity extends TypedEmitter { } if (!this.persistentData.openudid || this.persistentData.openudid == "") { this.persistentData.openudid = generateUDID(); - this.log.debug("Generated new openudid:", this.persistentData.openudid); + this.log.debug("Generated new openudid", { openudid: this.persistentData.openudid }); } this.api.setOpenUDID(this.persistentData.openudid); if (!this.persistentData.serial_number || this.persistentData.serial_number == "") { this.persistentData.serial_number = generateSerialnumber(12); - this.log.debug("Generated new serial_number:", this.persistentData.serial_number); + this.log.debug("Generated new serial_number", { serialnumber: this.persistentData.serial_number }); } this.api.setSerialNumber(this.persistentData.serial_number); @@ -253,7 +253,7 @@ export class EufySecurity extends TypedEmitter { const error = ensureError(err); if (error instanceof DeviceNotFoundError) { } else { - this.log.error("Lock MQTT Message Error", error); + this.log.error("Lock MQTT Message Error", { error: getError(error) }); } }).finally(() => { this.emit("mqtt lock message", message); @@ -312,7 +312,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error("getStorageInfo Error", error); + this.log.error("getStorageInfo Error", { error: getError(error), stationSN: stationSerial }); } } @@ -430,13 +430,13 @@ export class EufySecurity extends TypedEmitter { } private handleHouses(houses: Houses): void { - this.log.debug("Got houses:", houses); + this.log.debug("Got houses", { houses: houses }); //TODO: Finish implementation this.houses = houses; } private handleHubs(hubs: Hubs): void { - this.log.debug("Got hubs:", hubs); + this.log.debug("Got hubs", { hubs: hubs }); const stationsSNs: string[] = Object.keys(this.stations); const newStationsSNs = Object.keys(hubs); const promises: Array> = []; @@ -500,7 +500,7 @@ export class EufySecurity extends TypedEmitter { station.initialize(); } catch (err) { const error = ensureError(err); - this.log.error("HandleHubs Error", error); + this.log.error("HandleHubs Error", { error: getError(error), stationSN: station.getSerial() }); } return station; })); @@ -520,7 +520,7 @@ export class EufySecurity extends TypedEmitter { this.removeStation(station); }).catch((err) => { const error = ensureError(err); - this.log.error("Error removing station", error); + this.log.error("Error removing station", { error: getError(error), stationSN: stationSN }); }); } } @@ -531,7 +531,7 @@ export class EufySecurity extends TypedEmitter { if (Station.isStation(station.getDeviceType()) || (Device.isCamera(station.getDeviceType()) && !Device.isWiredDoorbell(station.getDeviceType()) || Device.isSmartSafe(station.getDeviceType()))) { station.getCameraInfo().catch(err => { const error = ensureError(err); - this.log.error(`Error during station ${station.getSerial()} p2p data refreshing`, error); + this.log.error(`Error during station p2p data refreshing`, { error: getError(error), stationSN: station.getSerial() }); }); if (this.refreshEufySecurityP2PTimeout[station.getSerial()] !== undefined) { clearTimeout(this.refreshEufySecurityP2PTimeout[station.getSerial()]); @@ -541,7 +541,7 @@ export class EufySecurity extends TypedEmitter { this.refreshEufySecurityP2PTimeout[station.getSerial()] = setTimeout(() => { station.getCameraInfo().catch(err => { const error = ensureError(err); - this.log.error(`Error during station ${station.getSerial()} p2p data refreshing`, error); + this.log.error(`Error during scheduled station p2p data refreshing`, { error: getError(error), stationSN: station.getSerial() }); }); }, this.P2P_REFRESH_INTERVAL_MIN * 60 * 1000); //} @@ -562,13 +562,13 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error(`Station ${station.getSerial()} - Error`, error); + this.log.error(`Station close Error`, { error: getError(error), stationSN: station.getSerial() }); }); } } private handleDevices(devices: FullDevices): void { - this.log.debug("Got devices:", devices); + this.log.debug("Got devices", { devices: devices }); const deviceSNs: string[] = Object.keys(this.devices); const newDeviceSNs = Object.keys(devices); const promises: Array> = []; @@ -644,7 +644,7 @@ export class EufySecurity extends TypedEmitter { device.initialize(); } catch (err) { const error = ensureError(err); - this.log.error("HandleDevices Error", error); + this.log.error("HandleDevices Error", { error: getError(error), deviceSN: device.getSerial() }); } return device; })); @@ -659,7 +659,7 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error("Error trying to connect to station afte device loaded", error); + this.log.error("Error trying to connect to station afte device loaded", { error: getError(error), deviceSN: device.getSerial() }); }); }); this.loadingEmitter.emit("devices loaded"); @@ -675,7 +675,7 @@ export class EufySecurity extends TypedEmitter { this.removeDevice(device); }).catch((err) => { const error = ensureError(err); - this.log.error("Error removing device", error); + this.log.error("Error removing device", { error: getError(error), deviceSN: deviceSN }); }); } } @@ -685,12 +685,12 @@ export class EufySecurity extends TypedEmitter { if (this.config.acceptInvitations) { await this.processInvitations().catch(err => { const error = ensureError(err); - this.log.error("Error in processing invitations", error); + this.log.error("Error in processing invitations", { error: getError(error) }); }); } await this.api.refreshAllData().catch(err => { const error = ensureError(err); - this.log.error("Error during API data refreshing", error); + this.log.error("Error during API data refreshing", { error: getError(error) }); }); if (this.refreshEufySecurityCloudTimeout !== undefined) clearTimeout(this.refreshEufySecurityCloudTimeout); @@ -771,7 +771,7 @@ export class EufySecurity extends TypedEmitter { }) .catch((err) => { const error = ensureError(err); - this.log.error("Connect Error", error); + this.log.error("Connect Error", { error: getError(error), options: options }); }); } @@ -784,7 +784,7 @@ export class EufySecurity extends TypedEmitter { device.updateRawProperties(values); }).catch((err) => { const error = ensureError(err); - this.log.error(`Update device ${deviceSN} properties error`, error); + this.log.error("Update device properties error", { error: getError(error), deviceSN: deviceSN, values: values }); }); } @@ -924,7 +924,7 @@ export class EufySecurity extends TypedEmitter { fse.writeFileSync(this.persistentFile, JSON.stringify(this.persistentData)); } catch (err) { const error = ensureError(err); - this.log.error("WritePersistentData Error", error); + this.log.error("WritePersistentData Error", { error: getError(error) }); } } @@ -971,7 +971,7 @@ export class EufySecurity extends TypedEmitter { const invites = await this.api.getInvites().catch(err => { const error = ensureError(err); - this.log.error("processInvitations - getInvites - Error", error); + this.log.error("Error getting invites from cloud", { error: getError(error) }); return error; }); if (Object.keys(invites).length > 0) { @@ -992,7 +992,7 @@ export class EufySecurity extends TypedEmitter { if (confirmInvites.length > 0) { const result = await this.api.confirmInvites(confirmInvites).catch(err => { const error = ensureError(err); - this.log.error("processInvitations - confirmInvites - Error", error); + this.log.error("Error in confirmation of invitations", { error: getError(error), confirmInvites: confirmInvites }); return error; }); if (result) { @@ -1004,18 +1004,18 @@ export class EufySecurity extends TypedEmitter { const houseInvites = await this.api.getHouseInviteList().catch(err => { const error = ensureError(err); - this.log.error("processInvitations - getHouseInviteList - Error", error); + this.log.error("Error getting house invites from cloud", { error: getError(error) }); return error; }); if (Object.keys(houseInvites).length > 0) { for(const invite of Object.values(houseInvites) as HouseInviteListResponse[]) { const result = await this.api.confirmHouseInvite(invite.house_id, invite.id).catch(err => { const error = ensureError(err); - this.log.error("processInvitations - confirmHouseInvite - Error", error); + this.log.error("Error in confirmation of house invitations", { error: getError(error) }); return error; }); if (result) { - this.log.info(`Accepted received house invitation from ${invite.action_user_email}`, invite); + this.log.info(`Accepted received house invitation from ${invite.action_user_email}`, { invite: invite }); refreshCloud = true; } } @@ -1028,7 +1028,7 @@ export class EufySecurity extends TypedEmitter { this.emit("push message", message); try { - this.log.debug("Received push message", message); + this.log.debug("Received push message", { message: message }); try { if ((message.type === ServerPushEvent.INVITE_DEVICE || message.type === ServerPushEvent.HOUSE_INVITE) && this.config.acceptInvitations) { if (this.isConnected()) @@ -1036,7 +1036,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`Error processing server push notification for device invitation`, error); + this.log.error(`Error processing server push notification for device invitation`, { error: getError(error), message: message }); } try { if (message.type === ServerPushEvent.REMOVE_DEVICE || message.type === ServerPushEvent.REMOVE_HOMEBASE || message.type === ServerPushEvent.HOUSE_REMOVE) { @@ -1045,7 +1045,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`Error processing server push notification for device/station/house removal`, error); + this.log.error(`Error processing server push notification for device/station/house removal`, { error: getError(error), message: message }); } this.getStations().then((stations: Station[]) => { stations.forEach(station => { @@ -1053,12 +1053,12 @@ export class EufySecurity extends TypedEmitter { station.processPushNotification(message); } catch (err) { const error = ensureError(err); - this.log.error(`Error processing push notification for station ${station.getSerial()}`, error); + this.log.error(`Error processing push notification for station`, { error: getError(error), stationSN: station.getSerial(), message: message }); } }); }).catch((err) => { const error = ensureError(err); - this.log.error("Process push notification for stations", error); + this.log.error("Process push notification for stations", { error: getError(error), message: message }); }); this.getDevices().then((devices: Device[]) => { devices.forEach(device => { @@ -1066,16 +1066,16 @@ export class EufySecurity extends TypedEmitter { device.processPushNotification(message, this.config.eventDurationSeconds); } catch (err) { const error = ensureError(err); - this.log.error(`Error processing push notification for device ${device.getSerial()}`, error); + this.log.error(`Error processing push notification for device`, { error: getError(error), deviceSN: device.getSerial(), message: message }); } }); }).catch((err) => { const error = ensureError(err); - this.log.error("Process push notification for devices", error); + this.log.error("Process push notification for devices", { error: getError(error), message: message }); }); } catch (err) { const error = ensureError(err); - this.log.error("OnPushMessage Generic Error", error); + this.log.error("OnPushMessage Generic Error", { error: getError(error), message: message }); } } @@ -1656,7 +1656,7 @@ export class EufySecurity extends TypedEmitter { this.emit("station livestream start", station, device, metadata, videostream, audiostream); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station start livestream error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station start livestream error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, metadata: metadata }); }); } @@ -1665,19 +1665,19 @@ export class EufySecurity extends TypedEmitter { this.emit("station livestream stop", station, device); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station stop livestream error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station stop livestream error`, { error: getError(error), stationSN: station.getSerial(), channel: channel }); }); } - private onErrorStationLivestream(station: Station, channel:number, _error: Error): void { + private onErrorStationLivestream(station: Station, channel:number, origError: Error): void { this.getStationDevice(station.getSerial(), channel).then((device: Device) => { station.stopLivestream(device).catch((err) => { const error = ensureError(err); - this.log.error(`Station livestream error (station: ${station.getSerial()} channel: ${channel} error: ${_error}})`, error); + this.log.error(`Station stop livestream error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, origError: getError(origError) }); }); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station livestream error (station: ${station.getSerial()} channel: ${channel} error: ${_error}})`, error); + this.log.error(`Station livestream error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, origError: getError(origError) }); }); } @@ -1686,7 +1686,7 @@ export class EufySecurity extends TypedEmitter { this.emit("station rtsp livestream start", station, device); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station start rtsp livestream error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station start rtsp livestream error`, { error: getError(error), stationSN: station.getSerial(), channel: channel }); }); } @@ -1695,7 +1695,7 @@ export class EufySecurity extends TypedEmitter { this.emit("station rtsp livestream stop", station, device); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station stop rtsp livestream error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station stop rtsp livestream error`, { error: getError(error), stationSN: station.getSerial(), channel: channel }); }); } @@ -1704,7 +1704,7 @@ export class EufySecurity extends TypedEmitter { this.emit("station download start", station, device, metadata, videoStream, audioStream); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station start download error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station start download error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, metadata: metadata }); }); } @@ -1713,7 +1713,7 @@ export class EufySecurity extends TypedEmitter { this.emit("station download finish", station, device); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station finish download error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station finish download error`, { error: getError(error), stationSN: station.getSerial(), channel: channel }); }); } @@ -1725,7 +1725,7 @@ export class EufySecurity extends TypedEmitter { result.customData.onSuccess(); } catch (err) { const error = ensureError(err); - this.log.error(`Station command result (station: ${station.getSerial()}) - onSuccess callback error`, error); + this.log.error(`Station command result - onSuccess callback error`, { error: getError(error), stationSN: station.getSerial(), result: result }); } } this.getStationDevice(station.getSerial(), result.channel).then((device: Device) => { @@ -1774,7 +1774,7 @@ export class EufySecurity extends TypedEmitter { }, timeoutMS); }).catch(err => { const error = ensureError(err); - this.log.error("Error during API data refreshing", error); + this.log.error("Error during API data refreshing", { error: getError(error) }); }); } }).catch((err) => { @@ -1784,7 +1784,7 @@ export class EufySecurity extends TypedEmitter { station.updateProperty(result.customData.property.name, result.customData.property.value); } } else { - this.log.error(`Station command result error (station: ${station.getSerial()})`, error); + this.log.error(`Station command result error`, { error: getError(error), stationSN: station.getSerial(), result: result }); } }); if (station.isIntegratedDevice() && result.command_type === CommandType.CMD_SET_ARMING && station.isConnected() && station.getDeviceType() !== DeviceType.DOORBELL) { @@ -1796,7 +1796,7 @@ export class EufySecurity extends TypedEmitter { result.customData.onFailure(); } catch (err) { const error = ensureError(err); - this.log.error(`Station command result (station: ${station.getSerial()}) - onFailure callback error`, error); + this.log.error(`Station command result - onFailure callback error`, { error: getError(error), stationSN: station.getSerial(), result: result }); } } } @@ -1882,7 +1882,7 @@ export class EufySecurity extends TypedEmitter { station.updateProperty(result.customData.property.name, result.customData.property.value); } } else { - this.log.error(`Station secondary command result error (station: ${station.getSerial()})`, error); + this.log.error(`Station secondary command result error`, { error: getError(error), stationSN: station.getSerial(), result: result }); } }); } @@ -1894,7 +1894,7 @@ export class EufySecurity extends TypedEmitter { device.setCustomPropertyValue(PropertyName.DeviceRTSPStreamUrl, value); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station rtsp url error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station rtsp url error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, url: value }); }); } @@ -1942,7 +1942,7 @@ export class EufySecurity extends TypedEmitter { station.setRTSPStream(device, true); }).catch((err) => { const error = ensureError(err); - this.log.error(`Device property changed error (device: ${device.getSerial()} name: ${name}) - station enable rtsp (station: ${device.getStationSerial()})`, error); + this.log.error(`Device property changed error - station enable rtsp`, { error: getError(error), deviceSN: device.getSerial(), stationSN: device.getStationSerial(), propertyName: name, propertyValue: value, ready: ready }); }); } else if (name === PropertyName.DeviceRTSPStream && (value as boolean) === false) { device.setCustomPropertyValue(PropertyName.DeviceRTSPStreamUrl, ""); @@ -1953,12 +1953,12 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error(`Device property changed error (device: ${device.getSerial()} name: ${name}) - station download image (station: ${device.getStationSerial()} image_path: ${value})`, error); + this.log.error(`Device property changed error - station download image`, { error: getError(error), deviceSN: device.getSerial(), stationSN: device.getStationSerial(), propertyName: name, propertyValue: value, ready: ready }); }); } } catch (err) { const error = ensureError(err); - this.log.error(`Device property changed error (device: ${device.getSerial()} name: ${name})`, error); + this.log.error(`Device property changed error`, { error: getError(error), deviceSN: device.getSerial(), stationSN: device.getStationSerial(), propertyName: name, propertyValue: value, ready: ready }); } } @@ -2069,12 +2069,12 @@ export class EufySecurity extends TypedEmitter { station.setRTSPStream(device, true); }).catch((err) => { const error = ensureError(err); - this.log.error(`Device ready error (device: ${device.getSerial()}) - station enable rtsp (station: ${device.getStationSerial()})`, error); + this.log.error(`Device ready error - station enable rtsp`, { error: getError(error), deviceSN: device.getSerial(), stationSN: device.getStationSerial() }); }); } } catch (err) { const error = ensureError(err); - this.log.error(`Device ready error (device: ${device.getSerial()})`, error); + this.log.error(`Device ready error`, { error: getError(error), deviceSN: device.getSerial(), stationSN: device.getStationSerial() }); } } @@ -2090,7 +2090,7 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error(`Station runtime state error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station runtime state error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, batteryLevel: batteryLevel, temperature: temperature }); }); } @@ -2107,7 +2107,7 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error(`Station charging state error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station charging state error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, chargeType: ChargingType[chargeType], batteryLevel: batteryLevel }); }); } @@ -2119,7 +2119,7 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error(`Station wifi rssi error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station wifi rssi error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, rssi: rssi }); }); } @@ -2135,7 +2135,7 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error(`Station floodlight manual switch error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station floodlight manual switch error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, enabled: enabled }); }); } @@ -2154,7 +2154,7 @@ export class EufySecurity extends TypedEmitter { this.emit("station talkback start", station, device, talkbackStream); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station talkback start error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station talkback start error`, { error: getError(error), stationSN: station.getSerial(), channel: channel }); }); } @@ -2163,16 +2163,16 @@ export class EufySecurity extends TypedEmitter { this.emit("station talkback stop", station, device); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station talkback stop error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station talkback stop error`, { error: getError(error), stationSN: station.getSerial(), channel: channel }); }); } - private onStationTalkbackError(station: Station, channel:number, _error: Error): void { + private onStationTalkbackError(station: Station, channel:number, origError: Error): void { this.getStationDevice(station.getSerial(), channel).then((device: Device) => { station.stopTalkback(device); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station talkback error (station: ${station.getSerial()} channel: ${channel} error: ${_error}})`, error); + this.log.error(`Station talkback error`, { error: getError(error), stationSN: station.getSerial(), channel: channel, origError: getError(origError) }); }); } @@ -2218,7 +2218,7 @@ export class EufySecurity extends TypedEmitter { (device as SmartSafe).shakeEvent(event, this.config.eventDurationSeconds); }).catch((err) => { const error = ensureError(err); - this.log.error(`onStationShakeAlarm device ${deviceSN} error`, error); + this.log.error(`onStationDeviceShakeAlarm error`, { error: getError(error), deviceSN: deviceSN, event: SmartSafeShakeAlarmEvent[event] }); }); } @@ -2228,7 +2228,7 @@ export class EufySecurity extends TypedEmitter { (device as SmartSafe).alarm911Event(event, this.config.eventDurationSeconds); }).catch((err) => { const error = ensureError(err); - this.log.error(`onStation911Alarm device ${deviceSN} error`, error); + this.log.error(`onStationDevice911Alarm error`, { error: getError(error), deviceSN: deviceSN, event: SmartSafeAlarm911Event[event] }); }); } @@ -2238,7 +2238,7 @@ export class EufySecurity extends TypedEmitter { (device as SmartSafe).jammedEvent(this.config.eventDurationSeconds); }).catch((err) => { const error = ensureError(err); - this.log.error(`onStationDeviceJammed device ${deviceSN} error`, error); + this.log.error(`onStationDeviceJammed error`, { error: getError(error), deviceSN: deviceSN }); }); } @@ -2248,7 +2248,7 @@ export class EufySecurity extends TypedEmitter { (device as SmartSafe).lowBatteryEvent(this.config.eventDurationSeconds); }).catch((err) => { const error = ensureError(err); - this.log.error(`onStationDeviceLowBattery device ${deviceSN} error`, error); + this.log.error(`onStationDeviceLowBattery error`, { error: getError(error), deviceSN: deviceSN }); }); } @@ -2258,7 +2258,7 @@ export class EufySecurity extends TypedEmitter { (device as SmartSafe).wrongTryProtectAlarmEvent(this.config.eventDurationSeconds); }).catch((err) => { const error = ensureError(err); - this.log.error(`onStationDeviceWrongTryProtectAlarm device ${deviceSN} error`, error); + this.log.error(`onStationDeviceWrongTryProtectAlarm error`, { error: getError(error), deviceSN: deviceSN }); }); } @@ -2278,7 +2278,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`addUser device ${deviceSN} error`, error); + this.log.error(`addUser error`, { error: getError(error), deviceSN: deviceSN, username: username, schedule: schedule }); this.emit("user error", device, username, new AddUserError("Generic error", { cause: error, context: { device: deviceSN, username: username, passcode: "[redacted]", schedule: schedule } })); } } @@ -2309,7 +2309,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`deleteUser device ${deviceSN} error`, error); + this.log.error(`deleteUser error`, { error: getError(error), deviceSN: deviceSN, username: username }); this.emit("user error", device, username, new DeleteUserError("Generic error", { cause: error, context: { device: deviceSN, username: username } })); } } @@ -2344,7 +2344,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`updateUser device ${deviceSN} error`, error); + this.log.error(`updateUser error`, { error: getError(error), deviceSN: deviceSN, username: username, newUsername: newUsername }); this.emit("user error", device, username, new UpdateUserUsernameError("Generic error", { cause: error, context: { device: deviceSN, username: username, newUsername: newUsername } })); } } @@ -2374,7 +2374,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`updateUserPasscode device ${deviceSN} error`, error); + this.log.error(`updateUserPasscode error`, { error: getError(error), deviceSN: deviceSN, username: username }); this.emit("user error", device, username, new UpdateUserPasscodeError("Generic error", { cause: error, context: { device: deviceSN, username: username, passcode: "[redacted]" } })); } } @@ -2404,7 +2404,7 @@ export class EufySecurity extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`updateUserSchedule device ${deviceSN} error`, error); + this.log.error(`updateUserSchedule error`, { error: getError(error), deviceSN: deviceSN, username: username, schedule: schedule }); this.emit("user error", device, username, new UpdateUserScheduleError("Generic error", { cause: error, context: { device: deviceSN, username: username, schedule: schedule } })); } } @@ -2414,7 +2414,7 @@ export class EufySecurity extends TypedEmitter { this.emit("device pin verified", device, successfull); }).catch((err) => { const error = ensureError(err); - this.log.error(`onStationDevicePinVerified device ${deviceSN} error`, error); + this.log.error(`onStationDevicePinVerified error`, { error: getError(error), deviceSN: deviceSN, successfull: successfull }); }); } @@ -2448,7 +2448,7 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error(`onStationImageDownload - Set first picture error`, error); + this.log.error(`onStationImageDownload - Set first picture error`, { error: getError(error), stationSN: station.getSerial(), file: file }); }); } @@ -2466,7 +2466,7 @@ export class EufySecurity extends TypedEmitter { device.update(raw); }).catch((err) => { const error = ensureError(err); - this.log.error("onStationDatabaseQueryLatest Error", error); + this.log.error("onStationDatabaseQueryLatest Error", { error: getError(error), stationSN: station.getSerial(), returnCode: returnCode }); }); } } @@ -2494,7 +2494,7 @@ export class EufySecurity extends TypedEmitter { } }).catch((err) => { const error = ensureError(err); - this.log.error(`Station sensor status error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station sensor status error`, { error: getError(error), stationSN: station.getSerial(), channel: channel }); }); } @@ -2503,7 +2503,7 @@ export class EufySecurity extends TypedEmitter { device.updateRawProperty(CommandType.CMD_CAMERA_GARAGE_DOOR_STATUS, status.toString(), "p2p"); }).catch((err) => { const error = ensureError(err); - this.log.error(`Station garage door status error (station: ${station.getSerial()} channel: ${channel})`, error); + this.log.error(`Station garage door status error`, { error: getError(error), stationSN: station.getSerial(), channel: channel }); }); } diff --git a/src/http/api.ts b/src/http/api.ts index ae768a48..807bd021 100644 --- a/src/http/api.ts +++ b/src/http/api.ts @@ -13,8 +13,9 @@ import { EventFilterType, PublicKeyType, ResponseErrorCode, StorageType, VerfyCo import { ParameterHelper } from "./parameter"; import { encryptAPIData, decryptAPIData, getTimezoneGMTString, decodeImage } from "./utils"; import { InvalidCountryCodeError, InvalidLanguageCodeError, ensureError } from "./../error"; -import { getShortUrl, md5, mergeDeep, parseJSON } from "./../utils"; +import { getError, getShortUrl, md5, mergeDeep, parseJSON } from "./../utils"; import { ApiBaseLoadError, ApiGenericError, ApiHTTPResponseCodeError, ApiInvalidResponseError, ApiRequestError, ApiResponseCodeError } from "./error"; +import { getNullTerminatedString } from "../p2p/utils"; export class HTTPApi extends TypedEmitter { @@ -79,7 +80,7 @@ export class HTTPApi extends TypedEmitter { this.log = log; this.apiBase = apiBase; - this.log.debug(`Loaded API_BASE: ${apiBase}`); + this.log.debug(`Loaded API`, { apieBase: apiBase, country: country, username: username, persistentData: persistentData }); this.headers.timezone = getTimezoneGMTString(); this.headers.country = country.toUpperCase(); @@ -95,7 +96,7 @@ export class HTTPApi extends TypedEmitter { this.ecdh.setPrivateKey(Buffer.from(this.persistentData.clientPrivateKey, "hex")); } catch (err) { const error = ensureError(err); - this.log.debug(`Invalid client private key, generate new client private key...`, error); + this.log.debug(`Invalid client private key, generate new client private key...`, { error: getError(error) }); this.ecdh.generateKeys(); this.persistentData.clientPrivateKey = this.ecdh.getPrivateKey().toString("hex"); } @@ -107,7 +108,7 @@ export class HTTPApi extends TypedEmitter { this.ecdh.computeSecret(Buffer.from(this.persistentData.serverPublicKey, "hex")) } catch (err) { const error = ensureError(err); - this.log.debug(`Invalid server public key, fallback to default server public key...`, error); + this.log.debug(`Invalid server public key, fallback to default server public key...`, { error: getError(error) }); this.persistentData.serverPublicKey = this.SERVER_PUBLIC_KEY; } } @@ -195,19 +196,6 @@ export class HTTPApi extends TypedEmitter { return error; } ], - /*beforeError: [ - error => { - const { response } = error; - if (response && response.body) { - const result = (response.body as ResultResponse); - error.name = "EufyError"; - error.message = `Code: ${result.code} Message: ${result.msg} (HTTP Code: ${response.statusCode})`; - this.log.error(`${error.name} - ${error.message} - requestUrl: ${error.request?.requestUrl}`); - } - - return error; - } - ],*/ beforeRequest: [ async _options => { await this.throttle(async () => { return; })(); @@ -302,7 +290,7 @@ export class HTTPApi extends TypedEmitter { options = mergeDeep(options, { force: false } as LoginOptions) as LoginOptions; - this.log.debug("Login and get an access token", { token: this.token, tokenExpiration: this.tokenExpiration }); + this.log.debug("Login and get an access token", { token: this.token, tokenExpiration: this.tokenExpiration, options: options }); if (!this.token || (this.tokenExpiration && (new Date()).getTime() >= this.tokenExpiration.getTime()) || options.verifyCode || options.captcha || options.force) { try { const data: LoginRequest = { @@ -346,14 +334,14 @@ export class HTTPApi extends TypedEmitter { ...this.headers, gtoken: md5(dataresult.user_id) }; - this.log.debug("Token data", { token: this.token, tokenExpiration: this.tokenExpiration, serverPublicKey: this.persistentData.serverPublicKey }); + this.log.debug("Login - Token data", { token: this.token, tokenExpiration: this.tokenExpiration, serverPublicKey: this.persistentData.serverPublicKey }); if (!this.connected) { this.connected = true; this.emit("connect"); } this.scheduleRenewAuthToken(); } else if (result.code == ResponseErrorCode.CODE_NEED_VERIFY_CODE) { - this.log.debug(`Send verification code...`); + this.log.debug(`Login - Send verification code...`); const dataresult: LoginResultResponse = result.data; this.setToken(dataresult.auth_token); @@ -364,23 +352,23 @@ export class HTTPApi extends TypedEmitter { this.emit("tfa request"); } else if (result.code == ResponseErrorCode.LOGIN_NEED_CAPTCHA || result.code == ResponseErrorCode.LOGIN_CAPTCHA_ERROR) { const dataresult: CaptchaResponse = result.data; - this.log.debug("Captcha verification received", { captchaId: dataresult.captcha_id, item: dataresult.item }); + this.log.debug("Login - Captcha verification received", { captchaId: dataresult.captcha_id, item: dataresult.item }); this.emit("captcha request", dataresult.captcha_id, dataresult.item); } else { - this.log.error("Response code not ok", {code: result.code, msg: result.msg }); + this.log.error("Login - Response code not ok", {code: result.code, msg: result.msg, data: response.data }); this.emit("connection error", new ApiResponseCodeError("API response code not ok", { context: { code: result.code, message: result.msg } })); } } else { - this.log.error("Response data is missing", {code: result.code, msg: result.msg, data: result.data }); + this.log.error("Login - Response data is missing", {code: result.code, msg: result.msg, data: result.data }); this.emit("connection error", new ApiInvalidResponseError("API response data is missing", { context: { code: result.code, message: result.msg, data: result.data } })); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Login - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); this.emit("connection error", new ApiHTTPResponseCodeError("API HTTP response code not ok", { context: { status: response.status, statusText: response.statusText } })); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error:", error); + this.log.error("Login - Generic Error:", { error: getError(error) }); this.emit("connection error", new ApiGenericError("Generic API error", { cause: error })); } } else if (!this.connected) { @@ -395,7 +383,7 @@ export class HTTPApi extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error("getPassportProfile Error", error); + this.log.error("Login - getPassportProfile Error", { error: getError(error) }); this.emit("connection error", new ApiGenericError("API get passport profile error", { cause: error })); } } @@ -420,14 +408,14 @@ export class HTTPApi extends TypedEmitter { this.log.info(`Requested verification code for 2FA`); return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Send verify code - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Send verify code - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Send verify code - Generic Error", { error: getError(error) }); } return false; } @@ -446,14 +434,14 @@ export class HTTPApi extends TypedEmitter { return result.data.list; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("List trust device - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("List trust device - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("List trust device - Generic Error", { error: getError(error) }); } } return []; @@ -470,7 +458,7 @@ export class HTTPApi extends TypedEmitter { transaction: `${new Date().getTime()}` } }); - this.log.debug("Response trust device:", response.data); + this.log.debug("Add trust device - Response trust device", { verifyCode: verifyCode, data: response.data }); if (response.status == 200) { const result: ResultResponse = response.data; @@ -479,19 +467,19 @@ export class HTTPApi extends TypedEmitter { const trusted_devices = await this.listTrustDevice(); trusted_devices.forEach((trusted_device: TrustDevice) => { if (trusted_device.is_current_device === 1) { - this.log.debug("This device is trusted. Token expiration extended:", { tokenExpiration: this.tokenExpiration}); + this.log.debug("Add trust device - This device is trusted. Token expiration extended:", { trustDevice: { phoneModel: trusted_device.phone_model, openUdid: trusted_device.open_udid }, tokenExpiration: this.tokenExpiration}); } }); return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Add trust device - Response code not ok", { code: result.code, msg: result.msg, verifyCode: verifyCode, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Add trust device - Status return code not 200", { status: response.status, statusText: response.statusText, verifyCode: verifyCode, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Add trust device - Generic Error", { error: getError(error) }); } } return false; @@ -522,14 +510,14 @@ export class HTTPApi extends TypedEmitter { return stationList; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Station list - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Station list - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Stations - Generic Error", error); + this.log.error("Station list - Generic Error", { error: getError(error) }); } } return []; @@ -560,14 +548,14 @@ export class HTTPApi extends TypedEmitter { return deviceList; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Device list - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Device list - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Devices - Generic Error", error); + this.log.error("Device list - Generic Error", { error: getError(error) }); } } return []; @@ -627,7 +615,7 @@ export class HTTPApi extends TypedEmitter { // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types public async request(request: HTTPApiRequest): Promise { - this.log.debug("Request:", { method: request.method, endpoint: request.endpoint, responseType: request.responseType, token: this.token, data: request.data }); + this.log.debug("Api request", { method: request.method, endpoint: request.endpoint, responseType: request.responseType, token: this.token, data: request.data }); try { const internalResponse = await this.requestEufyCloud(request.endpoint, { method: request.method, @@ -640,7 +628,7 @@ export class HTTPApi extends TypedEmitter { headers: internalResponse.headers, data: internalResponse.body, }; - this.log.debug("Response:", { token: this.token, request: request, response: response.data }); + this.log.debug("Api request - Response", { token: this.token, request: request, response: response.data }); return response; } catch (err) { @@ -672,17 +660,17 @@ export class HTTPApi extends TypedEmitter { if (response.status == 200) { const result: ResultResponse = response.data; if (result.code == 0) { - this.log.debug(`Push token OK`); + this.log.debug(`Check push token - Push token OK`); return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Check push token - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Check push token - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Check push token - Generic Error", { error: getError(error) }); } } return false; @@ -704,17 +692,17 @@ export class HTTPApi extends TypedEmitter { if (response.status == 200) { const result: ResultResponse = response.data; if (result.code == 0) { - this.log.debug(`Push token registered successfully`); + this.log.debug(`Register push token - Push token registered successfully`); return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Register push token - Response code not ok", { code: result.code, msg: result.msg, data: response.data, token: token }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Register push token - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, token: token }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Register push token - Generic Error", { error: getError(error), token: token }); } } return false; @@ -737,23 +725,23 @@ export class HTTPApi extends TypedEmitter { params: tmp_params } }); - this.log.debug("Response:", { stationSN: stationSN, deviceSN: deviceSN, params: tmp_params, response: response.data }); + this.log.debug("Set paramter - Response:", { stationSN: stationSN, deviceSN: deviceSN, params: tmp_params, response: response.data }); if (response.status == 200) { const result: ResultResponse = response.data; if (result.code == 0) { const dataresult = result.data; - this.log.debug("New parameters set", { params: tmp_params, response: dataresult }); + this.log.debug("Set paramter - New parameters set", { params: tmp_params, response: dataresult }); return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Set paramter - Response code not ok", { code: result.code, msg: result.msg, data: response.data, stationSN: stationSN, deviceSN: deviceSN, params: params }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Set paramter - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, stationSN: stationSN, deviceSN: deviceSN, params: params }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Set paramter - Generic Error", { error: getError(error), stationSN: stationSN, deviceSN: deviceSN, params: params }); } } return false; @@ -782,14 +770,14 @@ export class HTTPApi extends TypedEmitter { return ciphers; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get ciphers - Response code not ok", { code: result.code, msg: result.msg, data: response.data, cipherIDs: cipherIDs, userID: userID }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get ciphers - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, cipherIDs: cipherIDs, userID: userID }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get ciphers - Generic Error", { error: getError(error), cipherIDs: cipherIDs, userID: userID }); } } return {}; @@ -813,14 +801,14 @@ export class HTTPApi extends TypedEmitter { return voices; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get Voices - Response code not ok", { code: result.code, msg: result.msg, data: response.data, deviceSN: deviceSN }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get Voices - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, deviceSN: deviceSN }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get Voices - Generic Error", { error: getError(error), deviceSN: deviceSN }); } } return {}; @@ -917,17 +905,17 @@ export class HTTPApi extends TypedEmitter { }); } } else { - this.log.error("Response data is missing", { code: result.code, msg: result.msg, data: result.data }); + this.log.error(`${functionName} - Response data is missing`, { code: result.code, msg: result.msg, data: response.data, endpoint: endpoint, startTime: startTime, endTime: endTime, filter: filter, maxResults: maxResults }); } } else { - this.log.error(`${functionName} - Response code not ok`, {code: result.code, msg: result.msg }); + this.log.error(`${functionName} - Response code not ok`, {code: result.code, msg: result.msg, data: response.data, endpoint: endpoint, startTime: startTime, endTime: endTime, filter: filter, maxResults: maxResults }); } } else { - this.log.error(`${functionName} - Status return code not 200`, { status: response.status, statusText: response.statusText }); + this.log.error(`${functionName} - Status return code not 200`, { status: response.status, statusText: response.statusText, data: response.data, endpoint: endpoint, startTime: startTime, endTime: endTime, filter: filter, maxResults: maxResults }); } } catch (err) { const error = ensureError(err); - this.log.error(`${functionName} - Generic Error`, error); + this.log.error(`${functionName} - Generic Error`, { error: getError(error), endpoint: endpoint, startTime: startTime, endTime: endTime, filter: filter, maxResults: maxResults }); } } return records; @@ -993,14 +981,14 @@ export class HTTPApi extends TypedEmitter { return invites; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get invites - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get invites - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get invites - Generic Error", { error: getError(error) }); } } return {}; @@ -1022,14 +1010,14 @@ export class HTTPApi extends TypedEmitter { if (result.code == ResponseErrorCode.CODE_WHATEVER_ERROR) { return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Confirm invites - Response code not ok", { code: result.code, msg: result.msg, data: response.data, confirmInvites: confirmInvites }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Confirm invites - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, confirmInvites: confirmInvites }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Confirm invites - Generic Error", { error: getError(error), confirmInvites: confirmInvites }); } } return false; @@ -1055,15 +1043,15 @@ export class HTTPApi extends TypedEmitter { return result.data.public_key; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get public key - Response code not ok", { code: result.code, msg: result.msg, data: response.data, deviceSN: deviceSN, type: type }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get public key - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, deviceSN: deviceSN, type: type }); } } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get public key - Generic Error", { error: getError(error), deviceSN: deviceSN, type: type }); } } return ""; @@ -1076,15 +1064,16 @@ export class HTTPApi extends TypedEmitter { decryptedData = decryptAPIData(data, this.ecdh.computeSecret(Buffer.from(this.persistentData.serverPublicKey, "hex"))); } catch (err) { const error = ensureError(err); - this.log.error("Data decryption error, invalidating session data and reconnecting...", error); + this.log.error("Data decryption error, invalidating session data and reconnecting...", { error: getError(error) }); this.persistentData.serverPublicKey = this.SERVER_PUBLIC_KEY; this.invalidateToken(); this.emit("close"); } if (decryptedData) { + const str = getNullTerminatedString(decryptedData, "utf-8"); if (json) - return parseJSON(decryptedData.toString("utf-8"), this.log); - return decryptedData.toString(); + return parseJSON(str, this.log); + return str; } if (json) return {}; @@ -1115,14 +1104,14 @@ export class HTTPApi extends TypedEmitter { return entries; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get sensor history - Response code not ok", { code: result.code, msg: result.msg, data: response.data, stationSN: stationSN, deviceSN: deviceSN }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get sensor history - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, stationSN: stationSN, deviceSN: deviceSN }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get sensor history - Generic Error", { error: getError(error), stationSN: stationSN, deviceSN: deviceSN }); } } return []; @@ -1144,18 +1133,18 @@ export class HTTPApi extends TypedEmitter { if (result.code == ResponseErrorCode.CODE_WHATEVER_ERROR) { if (result.data) { const houseDetail = this.decryptAPIData(result.data) as HouseDetail; - this.log.debug("Decrypted house detail data", houseDetail); + this.log.debug("Get house detail - Decrypted house detail data", { details: houseDetail }); return houseDetail; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get house detail - Response code not ok", { code: result.code, msg: result.msg, data: response.data, houseID: houseID }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get house detail - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, houseID: houseID }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get house detail - Generic Error", { error: getError(error), houseID: houseID }); } } return null; @@ -1175,17 +1164,18 @@ export class HTTPApi extends TypedEmitter { const result: ResultResponse = response.data; if (result.code == ResponseErrorCode.CODE_WHATEVER_ERROR) { if (result.data) { + this.log.debug("Get house list - houses", { houses: result.data }); return result.data as Array; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get house list - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get house list - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get house list - Generic Error", { error: getError(error) }); } } return []; @@ -1208,18 +1198,18 @@ export class HTTPApi extends TypedEmitter { if (result.code == ResponseErrorCode.CODE_WHATEVER_ERROR) { if (result.data) { const houseInviteList = this.decryptAPIData(result.data) as Array; - this.log.debug("Decrypted house invite list data", houseInviteList); + this.log.debug("Get house invite list - Decrypted house invite list data", houseInviteList); return houseInviteList; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get house invite list - Response code not ok", { code: result.code, msg: result.msg, data: response.data, isInviter: isInviter }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get house invite list - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, isInviter: isInviter }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get house invite list - Generic Error", { error: getError(error), isInviter: isInviter }); } } return []; @@ -1244,14 +1234,14 @@ export class HTTPApi extends TypedEmitter { if (result.code == ResponseErrorCode.CODE_WHATEVER_ERROR) { return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Confirm house invite - Response code not ok", { code: result.code, msg: result.msg, data: response.data, houseID: houseID, inviteID: inviteID }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Confirm house invite - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, houseID: houseID, inviteID: inviteID }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Confirm house invite - Generic Error", { error: getError(error), houseID: houseID, inviteID: inviteID }); } } return false; @@ -1272,21 +1262,21 @@ export class HTTPApi extends TypedEmitter { if (result.code == ResponseErrorCode.CODE_WHATEVER_ERROR) { if (result.data) { const profile = this.decryptAPIData(result.data) as PassportProfileResponse; - this.log.debug("Decrypted passport profile data", profile); + this.log.debug("Get passport profile - Decrypted passport profile data", { profile: profile }); this.persistentData.user_id = profile.user_id; this.persistentData.nick_name = profile.nick_name; this.persistentData.email = profile.email; return profile; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get passport profile - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get passport profile - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get passport profile - Generic Error", { error: getError(error) }); } return null; } @@ -1310,14 +1300,14 @@ export class HTTPApi extends TypedEmitter { if (result.data) return result.data as AddUserResponse; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Add user - Response code not ok", { code: result.code, msg: result.msg, data: response.data, deviceSN: deviceSN, nickname: nickname, stationSN: stationSN }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Add user - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, deviceSN: deviceSN, nickname: nickname, stationSN: stationSN }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Add user - Generic Error", { error: getError(error), deviceSN: deviceSN, nickname: nickname, stationSN: stationSN }); } } return null; @@ -1341,14 +1331,14 @@ export class HTTPApi extends TypedEmitter { if (result.code == ResponseErrorCode.CODE_WHATEVER_ERROR) { return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Delete user - Response code not ok", { code: result.code, msg: result.msg, data: response.data, deviceSN: deviceSN, shortUserId: shortUserId, stationSN: stationSN }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Delete user - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, deviceSN: deviceSN, shortUserId: shortUserId, stationSN: stationSN }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Delete user - Generic Error", { error: getError(error), deviceSN: deviceSN, shortUserId: shortUserId, stationSN: stationSN }); } } return false; @@ -1368,14 +1358,14 @@ export class HTTPApi extends TypedEmitter { return usersResponse.user_list; } } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Get users - Response code not ok", { code: result.code, msg: result.msg, data: response.data, deviceSN: deviceSN, stationSN: stationSN }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get users - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, deviceSN: deviceSN, stationSN: stationSN }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get users - Generic Error", { error: getError(error), deviceSN: deviceSN, stationSN: stationSN }); } return null; } @@ -1392,7 +1382,7 @@ export class HTTPApi extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get user - Generic Error", { error: getError(error), deviceSN: deviceSN, stationSN: stationSN, shortUserId: shortUserId }); } return null; } @@ -1420,15 +1410,15 @@ export class HTTPApi extends TypedEmitter { if (result.code == ResponseErrorCode.CODE_WHATEVER_ERROR) { return true; } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Update user - Response code not ok", { code: result.code, msg: result.msg, data: response.data, deviceSN: deviceSN, stationSN: stationSN, shortUserId: shortUserId, nickname: nickname }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Update user - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, deviceSN: deviceSN, stationSN: stationSN, shortUserId: shortUserId, nickname: nickname }); } } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Update user - Generic Error", { error: getError(error), deviceSN: deviceSN, stationSN: stationSN, shortUserId: shortUserId, nickname: nickname }); } } return false; @@ -1449,13 +1439,13 @@ export class HTTPApi extends TypedEmitter { if (response.status == 200) { return decodeImage(station.p2p_did, response.data as Buffer); } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Get Image - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data, deviceSN: deviceSN, url: url }); } } } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Get Image - Generic Error", { error: getError(error), deviceSN: deviceSN, url: url }); } } return Buffer.alloc(0); diff --git a/src/http/device.ts b/src/http/device.ts index 6a9b5867..9df38cb1 100644 --- a/src/http/device.ts +++ b/src/http/device.ts @@ -11,7 +11,7 @@ import { calculateCellularSignalLevel, calculateWifiSignalLevel, getAbsoluteFile import { DecimalToRGBColor, eslTimestamp, getCurrentTimeInSeconds } from "../p2p/utils"; import { CusPushEvent, DoorbellPushEvent, LockPushEvent, IndoorPushEvent, SmartSafeEvent, HB3PairedDevicePushEvent, GarageDoorPushEvent } from "../push/types"; import { PushMessage, SmartSafeEventValueDetail } from "../push/models"; -import { isEmpty } from "../utils"; +import { getError, isEmpty } from "../utils"; import { InvalidPropertyError, PropertyNotSupportedError } from "./error"; import { DeviceSmartLockNotifyData } from "../mqtt/model"; import { DynamicLighting, InternalColoredLighting, InternalDynamicLighting, RGBColor } from "../p2p"; @@ -66,7 +66,7 @@ export class Device extends TypedEmitter { this.updateRawProperty(param.param_type, param.param_value, "http"); }); } - this.log.debug("Normalized Properties", { deviceSN: this.getSerial(), properties: this.properties }); + this.log.debug("Update device cloud properties", { deviceSN: this.getSerial(), properties: this.properties }); } public updateProperty(name: string, value: PropertyValue, force = false): boolean { @@ -80,9 +80,9 @@ export class Device extends TypedEmitter { } catch (err) { const error = ensureError(err); if (error instanceof InvalidPropertyError) { - this.log.error(`Invalid Property ${name} error`, error); + this.log.error(`Device update property - Invalid Property error`, { error: getError(error), deviceSN: this.getSerial(), propertyName: name, propertyValue: value, force: force }); } else { - this.log.error(`Property ${name} error`, error); + this.log.error(`Device update property - Property error`, { error: getError(error), deviceSN: this.getSerial(), propertyName: name, propertyValue: value, force: force }); } } return true; @@ -128,7 +128,7 @@ export class Device extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`Device handlePropertyChange error`, error, { metadata: metadata, oldValue: oldValue, newValue: newValue }); + this.log.error(`Device handle property change - error`, { error: getError(error), deviceSN: this.getSerial(), metadata: metadata, oldValue: oldValue, newValue: newValue }); } } @@ -153,9 +153,9 @@ export class Device extends TypedEmitter { } catch (err) { const error = ensureError(err); if (error instanceof PropertyNotSupportedError) { - this.log.debug("Property not supported error", error); + this.log.debug("Device update raw property - Property not supported error", { error: getError(error), deviceSN: this.getSerial(), type: type, value: value, source: source }); } else { - this.log.error("Property error", error); + this.log.error("Device update raw property - Property error", { error: getError(error), deviceSN: this.getSerial(), type: type, value: value, source: source }); } } } @@ -180,7 +180,7 @@ export class Device extends TypedEmitter { return value !== undefined ? (Number.parseInt((value as any).notification_ring_onoff) === 1 ? true : false) : booleanProperty.default !== undefined ? booleanProperty.default : false; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_BAT_DOORBELL_SET_NOTIFICATION_MODE DeviceNotificationRing Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_BAT_DOORBELL_SET_NOTIFICATION_MODE DeviceNotificationRing Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -190,7 +190,7 @@ export class Device extends TypedEmitter { return value !== undefined ? (Number.parseInt((value as any).notification_motion_onoff) === 1 ? true : false) : booleanProperty.default !== undefined ? booleanProperty.default : false; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_BAT_DOORBELL_SET_NOTIFICATION_MODE DeviceNotificationMotion Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_BAT_DOORBELL_SET_NOTIFICATION_MODE DeviceNotificationMotion Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -200,7 +200,7 @@ export class Device extends TypedEmitter { return value !== undefined ? Number.parseInt((value as any).notification_style) : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_BAT_DOORBELL_SET_NOTIFICATION_MODE DeviceNotificationType Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_BAT_DOORBELL_SET_NOTIFICATION_MODE DeviceNotificationType Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } @@ -215,7 +215,7 @@ export class Device extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error("Convert DOORBELL_NOTIFICATION_OPEN Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - DOORBELL_NOTIFICATION_OPEN Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return false; } } else if (property.key === CommandType.CMD_SET_PIRSENSITIVITY) { @@ -258,7 +258,7 @@ export class Device extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_PIRSENSITIVITY Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_SET_PIRSENSITIVITY Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } else if (property.key === CommandType.CMD_SMARTLOCK_AUTO_LOCK_SCHEDULE_STARTTIME || property.key === CommandType.CMD_SMARTLOCK_AUTO_LOCK_SCHEDULE_ENDTIME) { @@ -291,7 +291,7 @@ export class Device extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`Convert CMD_DOORBELL_DUAL_RADAR_WD_DETECTION_SENSITIVITY ${property.name} Error`, { property: property, value: value, error: error }); + this.log.error(`Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_DETECTION_SENSITIVITY ${property.name} Error`, { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } else if (property.key === CommandType.CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE) { @@ -302,7 +302,7 @@ export class Device extends TypedEmitter { return ((value as any).setting !== undefined && (value as any).setting.length > 0 !== undefined && (value as any).setting[0].start_hour !== undefined && (value as any).setting[0].start_min !== undefined) ? `${(value as any).setting[0].start_hour.padStart(2, "0")}:${(value as any).setting[0].start_min.padStart(2, "0")}` : stringProperty.default !== undefined ? stringProperty.default : ""; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseTimeFrom Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseTimeFrom Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return stringProperty.default !== undefined ? stringProperty.default : ""; } } @@ -312,7 +312,7 @@ export class Device extends TypedEmitter { return ((value as any).setting !== undefined && (value as any).setting.length > 0 !== undefined && (value as any).setting[0].end_hour !== undefined && (value as any).setting[0].end_min !== undefined) ? `${(value as any).setting[0].end_hour.padStart(2, "0")}:${(value as any).setting[0].end_min.padStart(2, "0")}` : stringProperty.default !== undefined ? stringProperty.default : ""; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseTimeTo Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseTimeTo Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return stringProperty.default !== undefined ? stringProperty.default : ""; } } @@ -322,7 +322,7 @@ export class Device extends TypedEmitter { return (value as any).setting[0].push_notify === 1 ? true : booleanProperty.default !== undefined ? booleanProperty.default : false; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponsePhoneNotification Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponsePhoneNotification Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -332,7 +332,7 @@ export class Device extends TypedEmitter { return (value as any).setting[0].homebase_alert === 1 ? true : booleanProperty.default !== undefined ? booleanProperty.default : false; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseHomeBaseNotification Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseHomeBaseNotification Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -342,7 +342,7 @@ export class Device extends TypedEmitter { return (value as any).setting[0].auto_voice_resp === 1 ? true : booleanProperty.default !== undefined ? booleanProperty.default : false; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseAutoVoiceResponse Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseAutoVoiceResponse Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -352,7 +352,7 @@ export class Device extends TypedEmitter { return ((value as any).setting !== undefined && (value as any).setting.length > 0 !== undefined && (value as any).setting[0].auto_voice_id !== undefined) ? (value as any).setting[0].auto_voice_id : numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseAutoVoiceResponseVoice Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_AUTO_RESPONSE DeviceLoiteringCustomResponseAutoVoiceResponseVoice Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } @@ -363,7 +363,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).ai_bottom_switch !== undefined ? (value as any).ai_bottom_switch === 1024 : (booleanProperty.default !== undefined ? booleanProperty.default : false); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_DELIVERY_GUARD_SWITCH Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_DELIVERY_GUARD_SWITCH Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } else if (property.key === CommandType.CMD_DOORBELL_DUAL_PACKAGE_STRAND_TIME) { @@ -372,7 +372,7 @@ export class Device extends TypedEmitter { return ((value as any).start_h !== undefined && (value as any).start_m !== undefined) ? `${(value as any).start_h.toString().padStart(2, "0")}:${(value as any).start_m.toString().padStart(2, "0")}` : stringProperty.default !== undefined ? stringProperty.default : ""; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_PACKAGE_STRAND_TIME Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_PACKAGE_STRAND_TIME Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return stringProperty.default !== undefined ? stringProperty.default : ""; } } else if (property.key === CommandType.CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE) { @@ -383,7 +383,7 @@ export class Device extends TypedEmitter { return (value as any).setting[0].active === 1 ? true : booleanProperty.default !== undefined ? booleanProperty.default : false; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponse Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponse Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -393,7 +393,7 @@ export class Device extends TypedEmitter { return (value as any).setting[0].active === 1 ? true : booleanProperty.default !== undefined ? booleanProperty.default : false; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponseVoiceResponse Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponseVoiceResponse Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -403,7 +403,7 @@ export class Device extends TypedEmitter { return ((value as any).setting !== undefined && (value as any).setting.length > 0 !== undefined && (value as any).setting[0].start_hour !== undefined && (value as any).setting[0].start_min !== undefined) ? `${(value as any).setting[0].start_hour.padStart(2, "0")}:${(value as any).setting[0].start_min.padStart(2, "0")}` : stringProperty.default !== undefined ? stringProperty.default : ""; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponseTimeFrom Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponseTimeFrom Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return stringProperty.default !== undefined ? stringProperty.default : ""; } } @@ -413,7 +413,7 @@ export class Device extends TypedEmitter { return ((value as any).setting !== undefined && (value as any).setting.length > 0 !== undefined && (value as any).setting[0].end_hour !== undefined && (value as any).setting[0].end_min !== undefined) ? `${(value as any).setting[0].end_hour.padStart(2, "0")}:${(value as any).setting[0].end_min.padStart(2, "0")}` : stringProperty.default !== undefined ? stringProperty.default : ""; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponseTimeTo Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponseTimeTo Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return stringProperty.default !== undefined ? stringProperty.default : ""; } } @@ -423,7 +423,7 @@ export class Device extends TypedEmitter { return ((value as any).setting !== undefined && (value as any).setting.length > 0 !== undefined && (value as any).setting[0].auto_voice_id !== undefined) ? (value as any).setting[0].auto_voice_id : numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponseVoiceResponseVoice Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RING_AUTO_RESPONSE DeviceRingAutoResponseVoiceResponseVoice Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } @@ -436,7 +436,7 @@ export class Device extends TypedEmitter { return ((value as any).start_h !== undefined && (value as any).start_m !== undefined) ? `${(value as any).start_h.toString().padStart(2, "0")}:${(value as any).start_m.toString().padStart(2, "0")}` : stringProperty.default !== undefined ? stringProperty.default : ""; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_PACKAGE_GUARD_TIME DeviceDeliveryGuardPackageGuardingActivatedTimeFrom Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_PACKAGE_GUARD_TIME DeviceDeliveryGuardPackageGuardingActivatedTimeFrom Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return stringProperty.default !== undefined ? stringProperty.default : ""; } } @@ -446,7 +446,7 @@ export class Device extends TypedEmitter { return ((value as any).end_h !== undefined && (value as any).end_m !== undefined) ? `${(value as any).end_h.toString().padStart(2, "0")}:${(value as any).end_m.toString().padStart(2, "0")}` : stringProperty.default !== undefined ? stringProperty.default : ""; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_PACKAGE_GUARD_TIME DeviceDeliveryGuardPackageGuardingActivatedTimeTo Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_PACKAGE_GUARD_TIME DeviceDeliveryGuardPackageGuardingActivatedTimeTo Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return stringProperty.default !== undefined ? stringProperty.default : ""; } } @@ -457,7 +457,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).radar_wd_distance !== undefined ? (value as any).radar_wd_distance as number : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RADAR_WD_DISTANCE Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_DISTANCE Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } else if (property.key === CommandType.CMD_DOORBELL_DUAL_RADAR_WD_TIME) { @@ -466,7 +466,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).radar_wd_time !== undefined ? (value as any).radar_wd_time as number : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_RADAR_WD_TIME Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_RADAR_WD_TIME Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } else if (property.key === CommandType.CMD_DOORBELL_DUAL_PACKAGE_GUARD_VOICE) { @@ -475,7 +475,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).auto_voice_id !== undefined ? (value as any).auto_voice_id as number : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_DOORBELL_DUAL_PACKAGE_GUARD_VOICE Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_DOORBELL_DUAL_PACKAGE_GUARD_VOICE Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } else if (property.key === CommandType.CMD_SET_SNOOZE_MODE) { @@ -486,7 +486,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).snooze_time !== undefined && (value as any).snooze_time !== "" && Number.parseInt((value as any).snooze_time) !== 0 ? true : booleanProperty.default !== undefined ? booleanProperty.default : false; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_SNOOZE_MODE DeviceSnooze Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_SET_SNOOZE_MODE DeviceSnooze Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -496,7 +496,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).snooze_time !== undefined && (value as any).snooze_time !== "" ? Number.parseInt((value as any).snooze_time) : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_SNOOZE_MODE DeviceSnoozeTime Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_SET_SNOOZE_MODE DeviceSnoozeTime Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } @@ -506,7 +506,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).startTime !== undefined ? Number.parseInt((value as any).startTime) : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_SNOOZE_MODE DeviceSnoozeTime Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_SET_SNOOZE_MODE DeviceSnoozeTime Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } @@ -516,7 +516,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).homebase_onoff !== undefined ? ((value as any).homebase_onoff === 1 ? true : false) : (booleanProperty.default !== undefined ? booleanProperty.default : false); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_SNOOZE_MODE DeviceSnoozeHomebase Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_SET_SNOOZE_MODE DeviceSnoozeHomebase Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -526,7 +526,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).motion_notify_onoff !== undefined ? ((value as any).motion_notify_onoff === 1 ? true : false) : (booleanProperty.default !== undefined ? booleanProperty.default : false); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_SNOOZE_MODE DeviceSnoozeMotion Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_SET_SNOOZE_MODE DeviceSnoozeMotion Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -536,7 +536,7 @@ export class Device extends TypedEmitter { return value !== undefined && (value as any).chime_onoff !== undefined ? ((value as any).chime_onoff === 1 ? true : false) : (booleanProperty.default !== undefined ? booleanProperty.default : false); } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_SNOOZE_MODE DeviceSnoozeChime Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - CMD_SET_SNOOZE_MODE DeviceSnoozeChime Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } @@ -553,7 +553,7 @@ export class Device extends TypedEmitter { return isHB3DetectionModeEnabled(Number.parseInt(value), property.name === PropertyName.DeviceMotionDetectionTypeHuman ? HB3DetectionTypes.HUMAN_DETECTION : property.name === PropertyName.DeviceMotionDetectionTypeHumanRecognition ? HB3DetectionTypes.HUMAN_RECOGNITION : property.name === PropertyName.DeviceMotionDetectionTypePet ? HB3DetectionTypes.PET_DETECTION : property.name === PropertyName.DeviceMotionDetectionTypeVehicle ? HB3DetectionTypes.VEHICLE_DETECTION : HB3DetectionTypes.ALL_OTHER_MOTION); } catch (err) { const error = ensureError(err); - this.log.error("Convert HB3 motion detection type Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - HB3 motion detection type Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } else if (property.key === CommandType.CELLULAR_INFO) { @@ -581,7 +581,7 @@ export class Device extends TypedEmitter { return value !== undefined ? Number.parseInt(value) : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = ensureError(err); - this.log.warn("PropertyMetadataNumeric Convert Error", { property: property, value: value, error: error }); + this.log.warn("Device convert raw property - PropertyMetadataNumeric Convert Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } else if (property.type === "boolean") { @@ -590,7 +590,7 @@ export class Device extends TypedEmitter { return value !== undefined ? (value === "1" || value.toLowerCase() === "true" ? true : false) : (booleanProperty.default !== undefined ? booleanProperty.default : false); } catch (err) { const error = ensureError(err); - this.log.warn("PropertyMetadataBoolean Convert Error", { property: property, value: value, error: error }); + this.log.warn("Device convert raw property - PropertyMetadataBoolean Convert Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } else if (property.type === "string") { @@ -602,7 +602,7 @@ export class Device extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error("Convert Error", { property: property, value: value, error: error }); + this.log.error("Device convert raw property - Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); } return value; } @@ -1457,7 +1457,7 @@ export class Camera extends Device { } } catch (err) { const error = ensureError(err); - this.log.error("Convert Error", { property: property, value: value, error: error }); + this.log.error("Camera convert raw property - Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); } return super.convertRawPropertyValue(property, value); } @@ -1475,7 +1475,7 @@ export class Camera extends Device { //TODO: Deprecated. Will be removed! await this.setParameters([{ paramType: ParamType.DETECT_SWITCH, paramValue: 1 }]).catch(err => { const error = ensureError(err); - this.log.error("Start detection Error", error); + this.log.error("Camera start detection - Error", { error: getError(error), deviceSN: this.getSerial() }); }); } @@ -1492,7 +1492,7 @@ export class Camera extends Device { proto: 2 } }); - this.log.debug("Response:", response.data); + this.log.debug("Camera start stream - Response", { data: response.data }); if (response.status == 200) { const result: ResultResponse = response.data; @@ -1505,14 +1505,14 @@ export class Camera extends Device { return `rtmp://${dataresult.domain}/hls/${dataresult.stream_name}==?time=${dataresult.time}&token=${dataresult.token}` } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Camera start stream - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Camera start stream - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Camera start stream - Generic Error", { error: getError(error), deviceSN: this.getSerial() }); } return ""; } @@ -1535,7 +1535,7 @@ export class Camera extends Device { proto: 2 } }); - this.log.debug("Response:", response.data); + this.log.debug("Camera stop stream - Response", { data: response.data }); if (response.status == 200) { const result: ResultResponse = response.data; @@ -1543,14 +1543,14 @@ export class Camera extends Device { this._isStreaming = false; this.log.info(`Livestream of camera ${this.rawDevice.device_sn} stopped`); } else { - this.log.error("Response code not ok", { code: result.code, msg: result.msg }); + this.log.error("Camera stop stream - Response code not ok", { code: result.code, msg: result.msg, data: response.data }); } } else { - this.log.error("Status return code not 200", { status: response.status, statusText: response.statusText }); + this.log.error("Camera stop stream - Status return code not 200", { status: response.status, statusText: response.statusText, data: response.data }); } } catch (err) { const error = ensureError(err); - this.log.error("Generic Error", error); + this.log.error("Camera stop stream - Generic Error", { error: getError(error), deviceSN: this.getSerial() }); } } @@ -1667,7 +1667,7 @@ export class Camera extends Device { } }).catch((err) => { const error = ensureError(err); - this.log.debug(`CusPushEvent.SECURITY - Device: ${message.device_sn} - Get picture - Error`, error); + this.log.debug(`Camera process push notification - CusPushEvent.SECURITY - Device Get picture - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); }); } if (message.fetch_id !== undefined) { @@ -1691,7 +1691,7 @@ export class Camera extends Device { } } catch (err) { const error = ensureError(err); - this.log.debug(`CusPushEvent.SECURITY - Device: ${message.device_sn} Error`, error); + this.log.debug(`Camera process push notification - CusPushEvent.SECURITY - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } else if (message.msg_type === DeviceType.HB3) { if (message.device_sn === this.getSerial()) { @@ -1703,7 +1703,7 @@ export class Camera extends Device { } }).catch((err) => { const error = ensureError(err); - this.log.debug(`HB3PairedDevicePushEvent - Device: ${message.device_sn} - Get picture - Error`, error); + this.log.debug(`Camera process push notification - HB3PairedDevicePushEvent - Device Get picture - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); }); } switch (message.event_type) { @@ -1802,12 +1802,12 @@ export class Camera extends Device { }, eventDurationSeconds * 1000)); break; default: - this.log.debug("Unhandled homebase3 camera push event", message); + this.log.debug("Camera process push notification - Unhandled homebase3 camera push event", message); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`HB3PairedDevicePushEvent - Device: ${message.device_sn} Error`, error); + this.log.debug(`Camera process push notification - HB3PairedDevicePushEvent - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -1843,7 +1843,7 @@ export class SoloCamera extends Camera { } }).catch((err) => { const error = ensureError(err); - this.log.debug(`SoloPushEvent - Device: ${message.device_sn} - Get picture - Error`, error); + this.log.debug(`SoloCamera process push notification - Device Get picture - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); }); } switch (message.event_type) { @@ -1866,12 +1866,12 @@ export class SoloCamera extends Camera { }, eventDurationSeconds * 1000)); break; default: - this.log.debug("Unhandled solo camera push event", message); + this.log.debug("SoloCamera process push notification - Unhandled solo camera push event", message); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`SoloPushEvent - Device: ${message.device_sn} Error`, error); + this.log.debug(`SoloCamera process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -1933,7 +1933,7 @@ export class IndoorCamera extends Camera { } }).catch((err) => { const error = ensureError(err); - this.log.debug(`IndoorPushEvent - Device: ${message.device_sn} - Get picture - Error`, error); + this.log.debug(`IndoorCamera process push notification - Device Get picture - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); }); } switch (message.event_type) { @@ -1980,12 +1980,12 @@ export class IndoorCamera extends Camera { }, eventDurationSeconds * 1000)); break; default: - this.log.debug("Unhandled indoor camera push event", message); + this.log.debug("IndoorCamera process push notification - Unhandled indoor camera push event", message); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`IndoorPushEvent - Device: ${message.device_sn} Error`, error); + this.log.debug(`IndoorCamera process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -2075,7 +2075,7 @@ export class DoorbellCamera extends Camera { } }).catch((err) => { const error = ensureError(err); - this.log.debug(`DoorbellPushEvent - Device: ${message.device_sn} - Get picture - Error`, error); + this.log.debug(`DoorbellCamera process push notification - Device Get picture - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); }); } switch (message.event_type) { @@ -2147,12 +2147,12 @@ export class DoorbellCamera extends Camera { }, eventDurationSeconds * 1000)); break; default: - this.log.debug("Unhandled doorbell push event", message); + this.log.debug("DoorbellCamera process push notification - Unhandled doorbell push event", message); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`DoorbellPushEvent - Device: ${message.device_sn} Error`, error); + this.log.debug(`DoorbellCamera process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -2212,7 +2212,7 @@ export class FloodlightCamera extends Camera { try { switch (property.key) { case CommandType.CMD_DEV_RECORD_AUTOSTOP: - if (this.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423 || this.getDeviceType() === DeviceType.FLOODLIGHT) + if (this.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423 || this.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8424 || this.getDeviceType() === DeviceType.FLOODLIGHT) return value !== undefined ? (value === "0" ? true : false) : false; break; case CommandType.CMD_FLOODLIGHT_SET_AUTO_CALIBRATION: @@ -2243,7 +2243,7 @@ export class FloodlightCamera extends Camera { } } catch (err) { const error = ensureError(err); - this.log.error("Convert Error", { property: property, value: value, error: error }); + this.log.error("FloodlightCamera convert raw property - Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); } return super.convertRawPropertyValue(property, value); } @@ -2260,7 +2260,7 @@ export class FloodlightCamera extends Camera { } }).catch((err) => { const error = ensureError(err); - this.log.debug(`FloodlightPushEvent - Device: ${message.device_sn} - Get picture - Error`, error); + this.log.debug(`FloodlightCamera process push notification - Device Get picture - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); }); } switch (message.event_type) { @@ -2283,12 +2283,12 @@ export class FloodlightCamera extends Camera { }, eventDurationSeconds * 1000)); break; default: - this.log.debug("Unhandled floodlight push event", message); + this.log.debug("FloodlightCamera process push notification - Unhandled floodlight push event", message); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`FloodlightPushEvent - Device: ${message.device_sn} Error`, error); + this.log.debug(`FloodlightCamera process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -2351,7 +2351,7 @@ export class WallLightCam extends Camera { } } catch (err) { const error = ensureError(err); - this.log.error("Convert Error", { property: property, value: value, error: error }); + this.log.error("WallLightCam convert raw property - Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); } return super.convertRawPropertyValue(property, value); } @@ -2383,7 +2383,7 @@ export class WallLightCam extends Camera { } }).catch((err) => { const error = ensureError(err); - this.log.debug(`WallLightCamPushEvent - Device: ${message.device_sn} - Get picture - Error`, error); + this.log.debug(`WallLightCam process push notification - Device Get picture - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); }); } switch (message.event_type) { @@ -2406,12 +2406,12 @@ export class WallLightCam extends Camera { }, eventDurationSeconds * 1000)); break; default: - this.log.debug("Unhandled WallLightCam push event", message); + this.log.debug("WallLightCam process push notification - Unhandled WallLightCam push event", message); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`WallLightCamPushEvent - Device: ${message.device_sn} Error`, error); + this.log.debug(`WallLightCam process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -2490,7 +2490,7 @@ export class GarageCamera extends Camera { } } catch (err) { const error = ensureError(err); - this.log.error("Convert Error", { property: property, value: value, error: error }); + this.log.error("GarageCamera convert raw property - Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); } return super.convertRawPropertyValue(property, value); } @@ -2507,7 +2507,7 @@ export class GarageCamera extends Camera { } }).catch((err) => { const error = ensureError(err); - this.log.debug(`GarageDoorPushEvent - Device: ${message.device_sn} - Get picture - Error`, error); + this.log.debug(`GarageCamera process push notification - Device Get picture - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); }); } switch (message.event_type) { @@ -2539,12 +2539,12 @@ export class GarageCamera extends Camera { } break; default: - this.log.debug("Unhandled GarageDoor push event", message); + this.log.debug("GarageCamera process push notification - Unhandled GarageDoor push event", message); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`GarageDoorPushEvent - Device: ${message.device_sn} Error`, error); + this.log.debug(`GarageCamera process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -2595,7 +2595,7 @@ export class EntrySensor extends Sensor { } } catch (err) { const error = ensureError(err); - this.log.debug(`CusPushEvent.DOOR_SENSOR - Device: ${message.device_sn} Error`, error); + this.log.debug(`EntrySensor process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -2677,7 +2677,7 @@ export class MotionSensor extends Sensor { }, eventDurationSeconds * 1000)); } catch (err) { const error = ensureError(err); - this.log.debug(`CusPushEvent.MOTION_SENSOR_PIR - Device: ${message.device_sn} Error`, error); + this.log.debug(`MotionSensor process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } @@ -2823,12 +2823,12 @@ export class Lock extends Device { // this.updateRawProperty(CommandType.CMD_SMARTLOCK_QUERY_BATTERY_LEVEL, "5"); // break; default: - this.log.debug("Unhandled lock notification event", eventType, eventTime, deviceSN); + this.log.debug("Lock process push notification - Unhandled lock notification event", eventType, eventTime, deviceSN); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`LockEvent - Device: ${deviceSN} Error`, error); + this.log.debug(`Lock process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), eventType: eventType, eventTime: eventTime, eventDurationSeconds: eventDurationSeconds, source: source }); } } } @@ -3087,7 +3087,7 @@ export class Keypad extends Device { } } catch (err) { const error = ensureError(err); - this.log.error("Convert Error", { property: property, value: value, error: error }); + this.log.error("Keypad convert raw property - Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); } return super.convertRawPropertyValue(property, value); } @@ -3260,7 +3260,7 @@ export class SmartSafe extends Device { } } catch (err) { const error = ensureError(err); - this.log.error("Convert Error", { property: property, value: value, error: error }); + this.log.error("SmartSafe convert raw property - Error", { error: getError(error), deviceSN: this.getSerial(), property: property, value: value }); } return super.convertRawPropertyValue(property, value); } @@ -3378,12 +3378,12 @@ export class SmartSafe extends Device { break; } default: - this.log.debug("Unhandled smart safe notification event", message.event_type, message.event_time, message.device_sn); + this.log.debug("SmartSafe process push notification - Unhandled smart safe notification event", message.event_type, message.event_time, message.device_sn); break; } } catch (err) { const error = ensureError(err); - this.log.debug(`LockEvent - Device: ${message.device_sn} Error`, error); + this.log.debug(`SmartSafe process push notification - Error`, { error: getError(error), deviceSN: this.getSerial(), message: JSON.stringify(message), eventDurationSeconds: eventDurationSeconds }); } } } diff --git a/src/http/parameter.ts b/src/http/parameter.ts index 553a53b1..62737f72 100644 --- a/src/http/parameter.ts +++ b/src/http/parameter.ts @@ -1,7 +1,7 @@ import { Logger } from "ts-log"; import { CommandType } from "../p2p/types"; -import { decodeBase64 } from "../p2p/utils"; +import { decodeBase64, getNullTerminatedString } from "../p2p/utils"; import { parseJSON } from "../utils"; import { ParamType } from "./types"; @@ -26,7 +26,7 @@ export class ParameterHelper { type === CommandType.CMD_WALL_LIGHT_SETTINGS_COLORED_LIGHTING_COLORS || type === CommandType.CMD_WALL_LIGHT_SETTINGS_DYNAMIC_LIGHTING_THEMES) { if (typeof value === "string") { - const parsedValue = parseJSON(decodeBase64(value).toString("utf8"), log); + const parsedValue = parseJSON(getNullTerminatedString(decodeBase64(value), "utf-8"), log); if (parsedValue === undefined) { log.warn("Non-parsable parameter value received from eufy cloud. Will be ignored.", { type: type, value: value }); } diff --git a/src/http/station.ts b/src/http/station.ts index f90c5413..8a744f55 100644 --- a/src/http/station.ts +++ b/src/http/station.ts @@ -19,8 +19,9 @@ import { InvalidCommandValueError, InvalidPropertyValueError, NotSupportedError, import { PushMessage } from "../push/models"; import { CusPushEvent } from "../push/types"; import { InvalidPropertyError, LivestreamAlreadyRunningError, LivestreamNotRunningError, PropertyNotSupportedError } from "./error"; -import { validValue } from "../utils"; +import { getError, validValue } from "../utils"; import { TalkbackStream } from "../p2p/talkback"; +import { start } from "repl"; export class Station extends TypedEmitter { @@ -153,7 +154,7 @@ export class Station extends TypedEmitter { this.updateRawProperty(param.param_type, param.param_value, "http"); }); } - this.log.debug("Normalized Properties", { stationSN: this.getSerial(), properties: this.properties }); + this.log.debug("Update station cloud properties", { stationSN: this.getSerial(), properties: this.properties }); } public updateProperty(name: string, value: PropertyValue, force = false): boolean { @@ -168,9 +169,9 @@ export class Station extends TypedEmitter { } catch (err) { const error = ensureError(err); if (error instanceof InvalidPropertyError) { - this.log.error(`Invalid Property ${name} error`, error); + this.log.error(`Station update property - Invalid Property error`, { error: getError(error), stationSN: this.getSerial(), propertyName: name, propertyValue: value, force: force }); } else { - this.log.error(`Property ${name} error`, error); + this.log.error(`Station update property - Property error`, { error: getError(error), stationSN: this.getSerial(), propertyName: name, propertyValue: value, force: force }); } } return true; @@ -231,7 +232,7 @@ export class Station extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error("Number conversion error", error); + this.log.error("Station update raw property - Number conversion error", { error: getError(error), stationSN: this.getSerial(), type: type, value: value, source: source }); } } @@ -244,9 +245,9 @@ export class Station extends TypedEmitter { } catch (err) { const error = ensureError(err); if (error instanceof PropertyNotSupportedError) { - this.log.debug("Property not supported error", error); + this.log.debug("Station update raw property - Property not supported error", { error: getError(error), stationSN: this.getSerial(), type: type, value: value, source: source }); } else { - this.log.error("Property error", error); + this.log.error("Station update raw property - Property error", { error: getError(error), stationSN: this.getSerial(), type: type, value: value, source: source }); } } } @@ -300,7 +301,7 @@ export class Station extends TypedEmitter { return value !== undefined ? Number.parseInt(value) : 1; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_HUB_ALARM_TONE Error", { property: property, value: value, error: error }); + this.log.error("Station convert raw property - CMD_HUB_ALARM_TONE Error", { error: getError(error), stationSN: this.getSerial(), property: property, value: value }); return 1; } case CommandType.CMD_SET_HUB_SPK_VOLUME: @@ -308,7 +309,7 @@ export class Station extends TypedEmitter { return value !== undefined ? Number.parseInt(value) : 26; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_HUB_SPK_VOLUME Error", { property: property, value: value, error: error }); + this.log.error("Station convert raw property - CMD_SET_HUB_SPK_VOLUME Error", { error: getError(error), stationSN: this.getSerial(), property: property, value: value }); return 26; } case CommandType.CMD_SET_PROMPT_VOLUME: @@ -316,7 +317,7 @@ export class Station extends TypedEmitter { return value !== undefined ? Number.parseInt(value) : 26; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_PROMPT_VOLUME Error", { property: property, value: value, error: error }); + this.log.error("Station convert raw property - CMD_SET_PROMPT_VOLUME Error", { error: getError(error), stationSN: this.getSerial(), property: property, value: value }); return 26; } case CommandType.CMD_SET_HUB_OSD: @@ -324,7 +325,7 @@ export class Station extends TypedEmitter { return value !== undefined ? Number.parseInt(value) : 0; } catch (err) { const error = ensureError(err); - this.log.error("Convert CMD_SET_HUB_OSD Error", { property: property, value: value, error: error }); + this.log.error("Station convert raw property - CMD_SET_HUB_OSD Error", { error: getError(error), stationSN: this.getSerial(), property: property, value: value }); return 0; } case CommandType.CMD_SET_HUB_ALARM_AUTO_END: @@ -338,7 +339,7 @@ export class Station extends TypedEmitter { return value !== undefined ? Number.parseInt(value) : (numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0)); } catch (err) { const error = ensureError(err); - this.log.warn("PropertyMetadataNumeric Convert Error", { property: property, value: value, error: error }); + this.log.warn("Station convert raw property - PropertyMetadataNumeric Convert Error", { error: getError(error), stationSN: this.getSerial(), property: property, value: value }); return numericProperty.default !== undefined ? numericProperty.default : (numericProperty.min !== undefined ? numericProperty.min : 0); } } else if (property.type === "boolean") { @@ -347,7 +348,7 @@ export class Station extends TypedEmitter { return value !== undefined ? (value === "1" || value.toLowerCase() === "true" ? true : false) : (booleanProperty.default !== undefined ? booleanProperty.default : false); } catch (err) { const error = ensureError(err); - this.log.warn("PropertyMetadataBoolean Convert Error", { property: property, value: value, error: error }); + this.log.warn("Station convert raw property - PropertyMetadataBoolean Convert Error", { error: getError(error), stationSN: this.getSerial(), property: property, value: value }); return booleanProperty.default !== undefined ? booleanProperty.default : false; } } else if (property.type === "string") { @@ -359,7 +360,7 @@ export class Station extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error("Convert Error", { property: property, value: value, error: error }); + this.log.error("Station convert raw property - Error", { error: getError(error), stationSN: this.getSerial(), property: property, value: value }); } return value; } @@ -525,7 +526,7 @@ export class Station extends TypedEmitter { this.updateRawProperty(CommandType.CMD_GET_ALARM_MODE, message.station_current_mode.toString(), "push"); } catch (err) { const error = ensureError(err); - this.log.debug(`Station ${message.station_sn} MODE_SWITCH event (${message.event_type}) - Error`, error); + this.log.debug(`Station process push notification - MODE_SWITCH event error`, { error: getError(error), stationSN: this.getSerial(), message: JSON.stringify(message) }); } } else if (message.event_type === CusPushEvent.ALARM && message.station_sn === this.getSerial() && !this.isStation()) { this.log.info("Received push notification for alarm event", { stationSN: message.station_sn, alarmType: message.alarm_type }); @@ -559,7 +560,7 @@ export class Station extends TypedEmitter { } public async connect(): Promise { - this.log.debug(`Connecting to station ${this.getSerial()}...`, { p2pConnectionType: P2PConnectionType[this.p2pConnectionType] }); + this.log.debug(`Connecting to station ${this.getSerial()}...`, { stationSN: this.getSerial(), p2pConnectionType: P2PConnectionType[this.p2pConnectionType] }); this.p2pSession.setConnectionType(this.p2pConnectionType); this.p2pSession.connect(); } @@ -690,9 +691,9 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, mode); - this.log.debug(`Sending guard mode command to station ${this.getSerial()} with value: ${GuardMode[mode]}`); + this.log.debug(`Station set guard mode - sending command`, { stationSN: this.getSerial(), mode: mode }); if (((isGreaterEqualMinVersion("2.0.7.9", this.getSoftwareVersion()) && !Device.isIntegratedDeviceBySn(this.getSerial())) || Device.isSoloCameraBySn(this.getSerial())) || this.rawStation.device_type === DeviceType.HB3) { - this.log.debug(`Using CMD_SET_PAYLOAD for station ${this.getSerial()}`, { main_sw_version: this.getSoftwareVersion() }); + this.log.debug(`Station set guard mode - Using CMD_SET_PAYLOAD`, { stationSN: this.getSerial(), mode: mode, main_sw_version: this.getSoftwareVersion() }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ @@ -709,7 +710,7 @@ export class Station extends TypedEmitter { property: propertyData }); } else { - this.log.debug(`Using CMD_SET_ARMING for station ${this.getSerial()}`); + this.log.debug(`Station set guard mode - Using CMD_SET_ARMING`, { stationSN: this.getSerial(), mode: mode }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_SET_ARMING, value: mode, @@ -722,7 +723,7 @@ export class Station extends TypedEmitter { } public async getCameraInfo(): Promise { - this.log.debug(`Sending get camera infos command to station ${this.getSerial()}`); + this.log.debug(`Station send get camera info command`, { stationSN: this.getSerial() }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_CAMERA_INFO, value: 255, @@ -731,7 +732,7 @@ export class Station extends TypedEmitter { } public async getStorageInfoEx(): Promise { - this.log.debug(`Sending get storage info command to station ${this.getSerial()}`); + this.log.debug(`Station send get storage info command`, { stationSN: this.getSerial() }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SDINFO_EX, value: 0, @@ -742,7 +743,7 @@ export class Station extends TypedEmitter { } private async onAlarmMode(mode: AlarmMode): Promise { - this.log.info(`Alarm mode for station ${this.getSerial()} changed to: ${AlarmMode[mode]}`); + this.log.debug(`Station alarm mode changed`, { stationSN: this.getSerial(), mode: mode }); this.updateRawProperty(CommandType.CMD_GET_ALARM_MODE, mode.toString(), "p2p"); const armDelay = this.getArmDelay(mode); if (armDelay > 0) { @@ -805,7 +806,7 @@ export class Station extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.debug(`Station ${this.getSerial()} - getArmDelay - Error`, { error: error, mode: mode, propertyName: propertyName, settings: settings }); + this.log.debug(`Station get arm delay - Error`, { error: getError(error), stationSN: this.getSerial(), mode: mode, propertyName: propertyName, settings: settings }); } } return 0; @@ -834,7 +835,7 @@ export class Station extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.debug(`Station ${this.getSerial()} - getGuardModeActionSetting - Error`, { error: error, mode: mode }); + this.log.debug(`Station get guard mode action setting - Error`, { error: getError(error), stationSN: this.getSerial(), mode: mode }); } return value; } @@ -859,7 +860,7 @@ export class Station extends TypedEmitter { } private onCameraInfo(cameraInfo: CmdCameraInfoResponse): void { - this.log.debug("Got camera infos", { station: this.getSerial(), cameraInfo: cameraInfo }); + this.log.debug("Station got camera info", { station: this.getSerial(), cameraInfo: cameraInfo }); const devices: { [index: string]: RawValues; } = {}; cameraInfo.params.forEach(param => { if (param.dev_type === Station.CHANNEL || param.dev_type === Station.CHANNEL_INDOOR || this.isIntegratedDevice()) { @@ -904,12 +905,12 @@ export class Station extends TypedEmitter { } private onCommandResponse(result: CommandResult): void { - this.log.debug("Got p2p command response", { station: this.getSerial(), commandType: result.command_type, channel: result.channel, returnCodeName: ErrorCode[result.return_code], returnCode: result.return_code, customData: result.customData }); + this.log.debug("Station got p2p command response", { station: this.getSerial(), commandType: result.command_type, channel: result.channel, returnCodeName: ErrorCode[result.return_code], returnCode: result.return_code, customData: result.customData }); this.emit("command result", this, result); } private onSecondaryCommandResponse(result: CommandResult): void { - this.log.debug("Got p2p secondary command response", { station: this.getSerial(), commandType: result.command_type, channel: result.channel, returnCode: result.return_code, customData: result.customData }); + this.log.debug("Station got p2p secondary command response", { station: this.getSerial(), commandType: result.command_type, channel: result.channel, returnCode: result.return_code, customData: result.customData }); this.emit("secondary command result", this, result); if (result.command_type === CommandType.CMD_SMARTSAFE_SETTINGS && result.customData?.command?.name === "deviceVerifyPIN") { if (result.return_code === 0) { @@ -965,7 +966,7 @@ export class Station extends TypedEmitter { private scheduleReconnect(): void { if (!this.reconnectTimeout) { const delay = this.getCurrentDelay(); - this.log.debug(`Schedule reconnect to station ${this.getSerial()}...`, { delay: delay }); + this.log.debug(`Station schedule reconnect`, { stationSN: this.getSerial(), delay: delay }); this.reconnectTimeout = setTimeout(async () => { this.reconnectTimeout = undefined; this.connect(); @@ -980,7 +981,7 @@ export class Station extends TypedEmitter { if (!this.hasCommand(CommandName.StationReboot)) { throw new NotSupportedError("This functionality is not implemented or supported", { context: { commandName: commandData.name, station: this.getSerial()} }); } - this.log.debug(`Sending reboot command to station ${this.getSerial()}`); + this.log.debug(`Station reboot - sending command`, { stationSN: this.getSerial() }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_HUB_REBOOT, value: 0, @@ -1005,7 +1006,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending status led command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set status led - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isCamera2Product() || device.isCamera3Product() || device.getDeviceType() === DeviceType.CAMERA || device.getDeviceType() === DeviceType.CAMERA_E) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_DEV_LED_SWITCH, @@ -1025,6 +1026,26 @@ export class Station extends TypedEmitter { }, { property: propertyData }); + } else if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8424) { + await this.p2pSession.sendCommandWithStringPayload({ + commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, + value: JSON.stringify({ + "commandType": CommandType.CMD_INDOOR_LED_SWITCH, + "data":{ + "enable": 0, + "index": 0, + "status": 0, + "type": 0, + "value": value === true ? 1 : 0, + "voiceID": 0, + "zonecount": 0, + "transaction": `${new Date().getTime()}`, + } + }), + channel: device.getChannel() + }, { + property: propertyData + }); } else if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423 || (device.getDeviceType() === DeviceType.FLOODLIGHT && !device.isFloodLightT8420X()) || device.isGarageCamera()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_DEV_LED_SWITCH, @@ -1172,7 +1193,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending autonightvision command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set auto night vision - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -1210,7 +1231,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending nightvision command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set night vision - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ @@ -1242,7 +1263,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending motion detection command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set motion detection - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamera() || (device.isFloodLight() && device.getDeviceType() !== DeviceType.FLOODLIGHT) || device.isFloodLightT8420X() || device.isWiredDoorbellT8200X() || device.isStarlight4GLTE() || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -1324,7 +1345,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending sound detection command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set sound detection - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -1359,7 +1380,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending sound detection type command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set sound detection type - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -1394,7 +1415,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending sound detection sensitivity command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set sound detection sensitivity - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -1429,7 +1450,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending pet detection command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set pet detection - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -1464,7 +1485,8 @@ export class Station extends TypedEmitter { if (!(direction in PanTiltDirection)) { throw new InvalidCommandValueError("Invalid value for this command", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending pan and tilt command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${PanTiltDirection[direction]}`); + + this.log.debug(`Station pan adn tilt - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), direction: PanTiltDirection[direction], command }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -1513,7 +1535,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending switch light command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station switch light - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isFloodLight() || device.isSoloCameraSpotlight1080() || device.isSoloCameraSpotlight2k() || device.isSoloCameraSpotlightSolar() || device.isCamera2C() || device.isCamera2CPro() || device.isIndoorOutdoorCamera1080p() || device.isIndoorOutdoorCamera2k() || device.isCamera3() || device.isCamera3C()) { @@ -1573,7 +1595,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending motion detection sensitivity command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set motion detection sensitivity - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if ((device.isFloodLight() && device.getDeviceType() !== DeviceType.FLOODLIGHT) || device.isIndoorCamera() || device.isFloodLightT8420X() || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -1761,7 +1783,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending motion detection type command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set motion detection type - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isCamera2Product() || device.isBatteryDoorbell() || device.getDeviceType() === DeviceType.CAMERA || device.getDeviceType() === DeviceType.CAMERA_E || device.isSoloCameras() || device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423 || device.isWiredDoorbellDual() || device.isStarlight4GLTE() || device.isGarageCamera()) { @@ -1824,7 +1846,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending motion detection type homebase 3 command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set motion detection type HB3 - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), type: type, value: value }); try { const aiDetectionType = device.getRawProperty(device.getPropertyMetadata(propertyData.name).key as number) !== undefined ? device.getRawProperty(device.getPropertyMetadata(propertyData.name).key as number)! : "0"; await this.p2pSession.sendCommandWithStringPayload({ @@ -1845,7 +1867,7 @@ export class Station extends TypedEmitter { }); } catch (err) { const error = ensureError(err); - this.log.error(`setMotionDetectionTypeHB3 - station ${this.getSerial()} device ${device.getSerial()}`, error); + this.log.error(`setMotionDetectionTypeHB3 Error`, { error: getError(error), stationSN: this.getSerial(), deviceSN: device.getSerial() }); } } @@ -1863,7 +1885,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending motion zone command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set motion zone - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -1890,7 +1912,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending motion tracking command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set motion tracking - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -1926,7 +1948,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending pan and tilt rotation speed command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set pan and tilt rotation speed - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -1962,7 +1984,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending mic mute command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set mic mute - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_DEV_MIC_MUTE, value: value === true ? 1 : 0, @@ -1988,7 +2010,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending audio recording command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set audio recording - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423 || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -2118,7 +2140,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending enable speaker command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station enable speaker - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_DEV_SPEAKER_MUTE, value: value === true ? 1 : 0, @@ -2144,7 +2166,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending speaker volume command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set speaker volume - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -2183,7 +2205,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending ringtone volume command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set ringtone volume - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbell() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_BAT_DOORBELL_SET_RINGTONE_VOLUME, @@ -2239,7 +2261,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending enable indoor chime command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station enable indoor chime - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbell()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_BAT_DOORBELL_MECHANICAL_CHIME_SWITCH, @@ -2282,7 +2304,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending enable homebase chime command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station enable homebase chime - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbell()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_BAT_DOORBELL_CHIME_SWITCH, @@ -2312,7 +2334,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending homebase chime ringtone volume command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set homebase chime ringtone volume - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbell()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -2347,7 +2369,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending homebase chime ringtone type command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set homebase chime ringtone type - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbell()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -2382,7 +2404,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification type command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification type - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isFloodLight() || device.isIndoorCamera() || device.isSoloCameras() || device.isStarlight4GLTE() || device.isGarageCamera()) { if (!Object.values(NotificationType).includes(value as NotificationType)) { this.log.error(`The device ${device.getSerial()} accepts only this type of values:`, NotificationType); @@ -2515,7 +2537,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification person command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification person - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamera() || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -2566,7 +2588,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification pet command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification pet - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -2606,7 +2628,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification all other motion command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification all other motion - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamera() || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -2657,7 +2679,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification all sound command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification all sound - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -2697,7 +2719,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification crying command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification crying - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -2737,7 +2759,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification ring command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification ring - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbell() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -2787,7 +2809,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification motion command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification motion - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbell() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -2837,7 +2859,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending power source command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set power source - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isStarlight4GLTE()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -2884,7 +2906,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending power working mode command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set power working mode - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_PIR_POWERMODE, value: value, @@ -2910,7 +2932,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending recording clip length command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set recording clip length - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_DEV_RECORD_TIMEOUT, value: value, @@ -2935,7 +2957,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending recording retrigger interval command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set recording retrigger interval - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_DEV_RECORD_INTERVAL, value: value, @@ -2960,7 +2982,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending recording end clip motion stops command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set recording end clip motion stops - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_DEV_RECORD_AUTOSTOP, value: value === true ? 0 : 1, @@ -2985,7 +3007,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending video streaming quality command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set video streaming quality - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamera() || device.isSoloCameras() || device.isFloodLight() || device.isWiredDoorbell() || device.isStarlight4GLTE() || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -3039,7 +3061,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending video recording quality command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set video recording quality - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamera() || device.isWiredDoorbell() || device.isFloodLight() || device.isSoloCameras() || device.isStarlight4GLTE() || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -3098,7 +3120,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending wdr command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set wdr - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_BAT_DOORBELL_WDR_SWITCH, value: value === true ? 1 : 0, @@ -3124,7 +3146,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending floodlight light settings enable command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings enable - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_FLOODLIGHT_TOTAL_SWITCH, value: value === true ? 1 : 0, @@ -3150,7 +3172,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending floodlight light settings brightness manual command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings brightness manual - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isFloodLight() || device.isSoloCameraSpotlight1080() || device.isSoloCameraSpotlight2k() || device.isSoloCameraSpotlightSolar() || device.isCamera2C() || device.isCamera2CPro() || device.isIndoorOutdoorCamera1080p() || device.isIndoorOutdoorCamera2k() || device.isCamera3() || device.isCamera3C()) { @@ -3196,7 +3218,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending floodlight light settings brightness motion command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings brightness motion - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isFloodLight()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_LIGHT_CTRL_BRIGHT_PIR, @@ -3240,7 +3262,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending floodlight light settings brightness schedule command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings brightness schedule - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isFloodLight()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_LIGHT_CTRL_BRIGHT_SCH, @@ -3284,7 +3306,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending floodlight light settings motion triggered command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings motion triggered - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isFloodLight()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_LIGHT_CTRL_PIR_SWITCH, @@ -3341,7 +3363,7 @@ export class Station extends TypedEmitter { throw new InvalidPropertyValueError("Invalid value for this property", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending floodlight light settings motion triggered distance command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${newValue}`); + this.log.debug(`Station set light settings motion triggered distance - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: newValue }); if (device.isFloodLight()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_PIRSENSITIVITY, @@ -3371,7 +3393,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, seconds); - this.log.debug(`Sending floodlight light settings motion triggered timer command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${seconds}`); + this.log.debug(`Station set light settings motion triggered timer - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: seconds }); if (device.isFloodLight()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_LIGHT_CTRL_PIR_TIME, @@ -3406,7 +3428,7 @@ export class Station extends TypedEmitter { if (!this.hasCommand(CommandName.StationTriggerAlarmSound)) { throw new NotSupportedError("This functionality is not implemented or supported", { context: { commandName: commandData.name, station: this.getSerial()} }); } - this.log.debug(`Sending trigger station alarm sound command to station ${this.getSerial()} with value: ${seconds}`); + this.log.debug(`Station trigger station alarm sound - sending command`, { stationSN: this.getSerial(), value: seconds }); if (!isGreaterEqualMinVersion("2.0.7.9", this.getSoftwareVersion()) || Device.isIntegratedDeviceBySn(this.getSerial())) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_TONE_FILE, @@ -3451,7 +3473,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceTriggerAlarmSound)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending trigger device alarm sound command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${seconds}`); + this.log.debug(`Station trigger device alarm sound - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: seconds }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_DEVS_TONE_FILE, value: seconds, @@ -3478,7 +3500,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station alarm ringtone volume command to station ${this.getSerial()} with value: ${value}`); + this.log.debug(`Station set station alarm ringtone volume - sending command`, { stationSN: this.getSerial(), value: value }); if (Device.isWallLightCam(this.getDeviceType())) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -3513,7 +3535,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station alarm tone command to station ${this.getSerial()} with value: ${AlarmTone[value]}`); + this.log.debug(`Station set station alarm tone - sending command`, { stationSN: this.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ @@ -3541,7 +3563,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station prompt volume command to station ${this.getSerial()} with value: ${value}`); + this.log.debug(`Station set station prompt volume - sending command`, { stationSN: this.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ @@ -3572,7 +3594,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station notification switch mode command to station ${this.getSerial()} with value: ${value}`); + this.log.debug(`Station set station notification switch mode - sending command`, { stationSN: this.getSerial(), mode: mode, value: value }); if (isGreaterEqualMinVersion("2.1.1.6", this.getSoftwareVersion())) { let oldvalue = 0; const rawproperty = this.getRawProperty(CommandType.CMD_HUB_NOTIFY_MODE); @@ -3638,7 +3660,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station notification start alarm delay command to station ${this.getSerial()} with value: ${value}`); + this.log.debug(`Station set station notification start alarm delay - sending command`, { stationSN: this.getSerial(), value: value }); if (isGreaterEqualMinVersion("2.1.1.6", this.getSoftwareVersion())) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -3687,7 +3709,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station time format command to station ${this.getSerial()} with value: ${TimeFormat[value]}`); + this.log.debug(`Station set station time format - sending command`, { stationSN: this.getSerial(), value: value }); if (Device.isWallLightCam(this.getDeviceType())) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -3725,7 +3747,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending rtsp stream command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set rtsp stream - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_NAS_SWITCH, value: value === true ? 1 : 0, @@ -3751,7 +3773,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending antitheft detection command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set anti theft detection - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_EAS_SWITCH, value: value === true ? 1 : 0, @@ -3777,12 +3799,12 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); + this.log.debug(`Station set watermark - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isCamera2Product() || device.isCamera3Product()) { if (!Object.values(WatermarkSetting3).includes(value as WatermarkSetting3)) { this.log.error(`The device ${device.getSerial()} accepts only this type of values:`, WatermarkSetting3); return; } - this.log.debug(`Sending watermark command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${WatermarkSetting3[value]}`); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_DEVS_OSD, value: value, @@ -3797,7 +3819,6 @@ export class Station extends TypedEmitter { this.log.error(`The device ${device.getSerial()} accepts only this type of values:`, WatermarkSetting1); return; } - this.log.debug(`Sending watermark command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${WatermarkSetting1[value]}`); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_DEVS_OSD, value: value, @@ -3812,7 +3833,6 @@ export class Station extends TypedEmitter { this.log.error(`The device ${device.getSerial()} accepts only this type of values:`, WatermarkSetting4); return; } - this.log.debug(`Sending watermark command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${WatermarkSetting4[value]}`); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_DEVS_OSD, value: value, @@ -3827,7 +3847,6 @@ export class Station extends TypedEmitter { this.log.error(`The device ${device.getSerial()} accepts only this type of values: `, WatermarkSetting2); return; } - this.log.debug(`Sending matermark command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${WatermarkSetting2[value]}`); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_DEVS_OSD, value: value, @@ -3842,7 +3861,6 @@ export class Station extends TypedEmitter { this.log.error(`The device ${device.getSerial()} accepts only this type of values:`, WatermarkSetting1); return; } - this.log.debug(`Sending watermark command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${WatermarkSetting1[value]}`); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -3858,7 +3876,6 @@ export class Station extends TypedEmitter { this.log.error(`The device ${device.getSerial()} accepts only this type of values:`, WatermarkSetting5); return; } - this.log.debug(`Sending watermark command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${WatermarkSetting5[value]}`); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_DEVS_OSD, value: value, @@ -3891,7 +3908,7 @@ export class Station extends TypedEmitter { if ((device.isIndoorCamera() && !device.isIndoorCamMini()) || (device.isWiredDoorbell() && !device.isWiredDoorbellT8200X()) || device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8422 || device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8424 || device.isFloodLightT8420X()) param_value = value === true ? 1 : 0; - this.log.debug(`Sending enable device command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station enable device - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isIndoorCamMini()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -3932,10 +3949,10 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceStartDownload)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } + this.log.debug(`Station start download - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), path: path, cipherID: cipher_id }); if (this.getDeviceType() === DeviceType.HB3) { //TODO: Implement HB3 Support! Actually doesn't work and returns return_code -104 (ERROR_INVALID_ACCOUNT). It could be that we need the new encrypted p2p protocol to make this work... const rsa_key = this.p2pSession.getDownloadRSAPrivateKey(); - this.log.debug(`Sending start download command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${path}`); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOWNLOAD_VIDEO, value: JSON.stringify({ @@ -3955,7 +3972,6 @@ export class Station extends TypedEmitter { } else if (cipher_id !== undefined) { const cipher = await this.api.getCipher(cipher_id, this.rawStation.member.admin_user_id); if (Object.keys(cipher).length > 0) { - this.log.debug(`Sending start download command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${path}`); this.p2pSession.setDownloadRSAPrivateKeyPem(cipher.private_key); await this.p2pSession.sendCommandWithString({ commandType: CommandType.CMD_DOWNLOAD_VIDEO, @@ -3999,7 +4015,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceCancelDownload)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending cancel download command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station cancel download - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_DOWNLOAD_CANCEL, value: device.getChannel(), @@ -4024,11 +4040,11 @@ export class Station extends TypedEmitter { if (this.isLiveStreaming(device)) { throw new LivestreamAlreadyRunningError("Livestream for device is already running", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending start livestream command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station start livestream - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), videoCodec: videoCodec }); const rsa_key = this.p2pSession.getRSAPrivateKey(); - if (device.isSoloCameras() || device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423 || device.isWiredDoorbellT8200X() || device.isWallLightCam() || device.isGarageCamera()) { - this.log.debug(`Using CMD_DOORBELL_SET_PAYLOAD (1) for station ${this.getSerial()} (main_sw_version: ${this.getSoftwareVersion()})`); + if (device.isSoloCameras() || device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423 || device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8424 || device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8424 || device.isWiredDoorbellT8200X() || device.isWallLightCam() || device.isGarageCamera()) { + this.log.debug(`Station start livestream - sending command using CMD_DOORBELL_SET_PAYLOAD (1)`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), videoCodec: videoCodec, main_sw_version: this.getSoftwareVersion() }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -4044,7 +4060,7 @@ export class Station extends TypedEmitter { command: commandData }); } else if (device.isWiredDoorbell() || (device.isFloodLight() && device.getDeviceType() !== DeviceType.FLOODLIGHT) || device.isIndoorCamera() || (device.getSerial().startsWith("T8420") && isGreaterEqualMinVersion("2.0.4.8", this.getSoftwareVersion()))) { - this.log.debug(`Using CMD_DOORBELL_SET_PAYLOAD (2) for station ${this.getSerial()} (main_sw_version: ${this.getSoftwareVersion()})`); + this.log.debug(`Station start livestream - sending command using CMD_DOORBELL_SET_PAYLOAD (2)`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), videoCodec: videoCodec, main_sw_version: this.getSoftwareVersion() }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -4061,7 +4077,7 @@ export class Station extends TypedEmitter { }); } else { if ((Device.isIntegratedDeviceBySn(this.getSerial()) || !isGreaterEqualMinVersion("2.0.9.7", this.getSoftwareVersion())) && (!this.getSerial().startsWith("T8420") || !isGreaterEqualMinVersion("1.0.0.25", this.getSoftwareVersion()))) { - this.log.debug(`Using CMD_START_REALTIME_MEDIA for station ${this.getSerial()} (main_sw_version: ${this.getSoftwareVersion()})`); + this.log.debug(`Station start livestream - sending command using CMD_START_REALTIME_MEDIA`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), videoCodec: videoCodec, main_sw_version: this.getSoftwareVersion() }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_START_REALTIME_MEDIA, value: device.getChannel(), @@ -4071,7 +4087,7 @@ export class Station extends TypedEmitter { command: commandData }); } else { - this.log.debug(`Using CMD_SET_PAYLOAD for station ${this.getSerial()} (main_sw_version: ${this.getSoftwareVersion()})`); + this.log.debug(`Station start livestream - sending command using CMD_SET_PAYLOAD`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), videoCodec: videoCodec, main_sw_version: this.getSoftwareVersion() }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ @@ -4105,7 +4121,7 @@ export class Station extends TypedEmitter { if (!this.isLiveStreaming(device)) { throw new LivestreamNotRunningError("Livestream for device is not running", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending stop livestream command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station stop livestream - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_STOP_REALTIME_MEDIA, value: device.getChannel(), @@ -4138,9 +4154,9 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceQuickResponse)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending quick response command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${voice_id}`); + this.log.debug(`Station quick response - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), voiceID: voice_id }); if (device.isBatteryDoorbell()) { - this.log.debug(`Using CMD_BAT_DOORBELL_QUICK_RESPONSE for station ${this.getSerial()}`); + this.log.debug(`Station quick response - sending command using CMD_BAT_DOORBELL_QUICK_RESPONSE`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), voiceID: voice_id }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_BAT_DOORBELL_QUICK_RESPONSE, value: voice_id, @@ -4151,7 +4167,7 @@ export class Station extends TypedEmitter { command: commandData }); } else if (device.isWiredDoorbell()) { - this.log.debug(`Using CMD_DOORBELL_SET_PAYLOAD for station ${this.getSerial()}`); + this.log.debug(`Station quick response - sending command using CMD_DOORBELL_SET_PAYLOAD`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), voiceID: voice_id }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -4183,7 +4199,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending chirp volume command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set chirp volume - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isEntrySensor()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -4219,7 +4235,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending chirp tone command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set chirp tone - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isEntrySensor()) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SENSOR_SET_CHIRP_TONE, @@ -4249,7 +4265,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending hdr command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set hdr - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWiredDoorbell()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4282,7 +4298,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending distortion correction command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set distortion correction - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWiredDoorbell()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4315,7 +4331,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending ring record command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set ring record - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWiredDoorbell()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4348,7 +4364,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending lock device command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station lock device - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockBleNoFinger() || device.isLockBle()) { const key = generateBasicLockAESKey(this.rawStation.member.admin_user_id, this.getSerial()); const iv = getLockVectorBytes(this.getSerial()); @@ -4361,7 +4377,7 @@ export class Station extends TypedEmitter { }; const encPayload = encryptLockAESData(key, iv, encodeLockPayload(JSON.stringify(payload))); - this.log.debug("Locking/unlocking device...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: payload, encPayload: encPayload.toString("hex") }); + this.log.debug("Station lock device - Locking/unlocking device...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: payload, encPayload: encPayload.toString("hex") }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -4394,7 +4410,7 @@ export class Station extends TypedEmitter { nestedPayload ); this.p2pSession.setLockAESKey(CommandType.P2P_ON_OFF_LOCK, command.aesKey); - this.log.debug("Locking/unlocking device...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); + this.log.debug("Station lock device - Locking/unlocking device...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); await this.p2pSession.sendCommandWithStringPayload(command, { property: propertyData @@ -4409,7 +4425,7 @@ export class Station extends TypedEmitter { this.p2pSession.incLockSequenceNumber(), Lock.encodeCmdUnlock(this.rawStation.member.short_user_id, value === true ? 1 : 0, this.rawStation.member.nick_name) ); - this.log.debug("Locking/unlocking device...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command.payload }); + this.log.debug("Station lock device - Locking/unlocking device...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command.payload }); await this._sendLockV12P2PCommand(command, { property: propertyData @@ -4430,7 +4446,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station switch mode with access code command to station ${this.getSerial()} with value: ${value}`); + this.log.debug(`Station set station switch mode with access code - sending command`, { stationSN: this.getSerial(), value: value }); if (this.isStation()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -4462,7 +4478,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station auto end alarm command to station ${this.getSerial()} with value: ${value}`); + this.log.debug(`Station station auto end alarm - sending command`, { stationSN: this.getSerial(), value: value }); if (this.isStation()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -4494,7 +4510,7 @@ export class Station extends TypedEmitter { const property = this.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending station turn off alarm with button command to station ${this.getSerial()} with value: ${value}`); + this.log.debug(`Station set station turn off alarm with button - sending command`, { stationSN: this.getSerial(), value: value }); if (this.isStation()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -4530,7 +4546,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(PropertyName.DeviceRTSPStream)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Start RTSP stream command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station start rtsp stream - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_NAS_TEST, value: 1, @@ -4557,7 +4573,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(PropertyName.DeviceRTSPStream)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Stop RTSP stream command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station stop rtsp stream - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_NAS_TEST, value: 0, @@ -4583,7 +4599,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, type); - this.log.debug(`Sending motion detection range command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${type}`); + this.log.debug(`Station set motion detection range - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: type }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4616,7 +4632,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, sensitivity); - this.log.debug(`Sending motion detection range standard sensitivity command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${sensitivity}`); + this.log.debug(`Station set motion detection range standard sensitivity - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: sensitivity }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4649,7 +4665,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, sensitivity); - this.log.debug(`Sending motion detection range advanced left sensitivity command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${sensitivity}`); + this.log.debug(`Station motion detection range advanced left sensitivity - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: sensitivity }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4682,7 +4698,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, sensitivity); - this.log.debug(`Sending motion detection range advanced middle sensitivity command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${sensitivity}`); + this.log.debug(`Station set motion detection range advanced middle sensitivity - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: sensitivity }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4715,7 +4731,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, sensitivity); - this.log.debug(`Sending motion detection range advanced right sensitivity command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${sensitivity}`); + this.log.debug(`Station set motion detection range advanced right sensitivity - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: sensitivity }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4748,7 +4764,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, enabled); - this.log.debug(`Sending motion detection test mode command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${enabled}`); + this.log.debug(`Station set motion detection test mode - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: enabled }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423 || device.getDeviceType() === DeviceType.FLOODLIGHT) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_PIR_TEST_MODE, @@ -4778,7 +4794,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, sensitivity); - this.log.debug(`Sending motion tracking sensitivity command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${sensitivity}`); + this.log.debug(`Station set motion tracking sensitivity - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: sensitivity }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4811,7 +4827,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, enabled); - this.log.debug(`Sending motion auto cruise command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${enabled}`); + this.log.debug(`Station set motion auto cruise - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: enabled }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4844,7 +4860,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, enabled); - this.log.debug(`Sending motion out-of-view detection command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${enabled}`); + this.log.debug(`Station set motion out of view detection - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: enabled }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4877,7 +4893,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting color temperature manual command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings color temperature manual - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4910,7 +4926,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting color temperature motion command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings color temperature motion - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4943,7 +4959,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting color temperature schedule command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings color temperature schedule - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -4976,7 +4992,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting motion activation mode command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings motion activation mode - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithIntString({ commandType: CommandType.CMD_SET_FLOODLIGHT_STREET_LAMP, @@ -5017,7 +5033,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, enabled); - this.log.debug(`Sending video nightvision image adjustment command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${enabled}`); + this.log.debug(`Station set video night vision image adjustment - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: enabled }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -5050,7 +5066,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, enabled); - this.log.debug(`Sending video color nightvision command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${enabled}`); + this.log.debug(`Station set video color night vision - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: enabled }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -5083,7 +5099,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, enabled); - this.log.debug(`Sending auto calibration command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${enabled}`); + this.log.debug(`Station set auto calibration - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: enabled }); if (device.getDeviceType() === DeviceType.FLOODLIGHT_CAMERA_8423) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -5154,7 +5170,7 @@ export class Station extends TypedEmitter { if (!this.hasCommand(CommandName.DeviceLockCalibration)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } - this.log.debug(`Sending calibrate lock command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station calibrate lock - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { const nestedPayload = { seq_num: this.p2pSession.incLockSequenceNumber() @@ -5168,7 +5184,7 @@ export class Station extends TypedEmitter { nestedPayload ); this.p2pSession.setLockAESKey(CommandType.P2P_CALIBRATE_LOCK, command.aesKey); - this.log.debug("Calibrate lock...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); + this.log.debug("Station calibrate lock - Calibrate lock...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); await this.p2pSession.sendCommandWithStringPayload(command, { command: commandData @@ -5183,7 +5199,7 @@ export class Station extends TypedEmitter { this.p2pSession.incLockSequenceNumber(), Lock.encodeCmdCalibrate(this.rawStation.member.admin_user_id) ); - this.log.debug("Locking/unlocking device...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command.payload }); + this.log.debug("Station calibrate lock - Locking/unlocking device...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command.payload }); await this._sendLockV12P2PCommand(command, { command: commandData @@ -5289,7 +5305,7 @@ export class Station extends TypedEmitter { const propertyMetadata = device.getPropertyMetadata(propertyData.name); validValue(propertyMetadata, value); - this.log.debug(`Sending set advanced lock settings command to station ${this.getSerial()} for device ${device.getSerial()} property ${property}`); + this.log.debug(`Station set advanced lock params - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), property: property, value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { const payload = this.getAdvancedLockSettingsPayload(device.getPropertyMetadata(property).key as number, device); const p2pParamName = this.getAdvancedLockSettingName(property); @@ -5304,7 +5320,7 @@ export class Station extends TypedEmitter { payload ); this.p2pSession.setLockAESKey(CommandType.P2P_SET_LOCK_PARAM, command.aesKey); - this.log.debug("Set lock param...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, property: property, value: value, payload: command, nestedPayload: payload }); + this.log.debug("Station set advanced lock params - Set lock param...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, property: property, value: value, payload: command, nestedPayload: payload }); await this.p2pSession.sendCommandWithStringPayload(command, { property: propertyData @@ -5332,7 +5348,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending loitering detection command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set loitering detection - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5368,7 +5384,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending loitering detection range command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set loitering detection range - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5404,7 +5420,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending loitering detection length command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set loitering detection length - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5436,7 +5452,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, propertyData.value); - this.log.debug(`Sending motion detection sensitivity dual command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${propertyData.value}`); + this.log.debug(`Station set motion detection sensitivty - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), propertyData: propertyData, mode: mode, blocklist: blocklist }); if (device.isBatteryDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5585,7 +5601,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, propertyData.value); - this.log.debug(`Sending loitering custom response command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${propertyData.value}`); + this.log.debug(`Station set loitering custom response - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), propertyData: propertyData, voiceID: voiceID, autoVoiceResponse: autoVoiceResponse, homebaseAlert: homebaseAlert, pushNotification: pushNotification, startTime: startTime, endTime: endTime }); if (device.isBatteryDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5736,7 +5752,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending delivery guard command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set delivery guard - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5773,7 +5789,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending delivery guard package guarding command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set delivery guard package guarding - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5809,7 +5825,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, propertyData.value); - this.log.debug(`Sending delivery guard package guarding voice response voice command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set delivery guard package guarding voice response voice - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5842,7 +5858,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, propertyData.value); - this.log.debug(`Sending delivery guard package guarding activeted time command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${propertyData.value}`); + this.log.debug(`Station set delivery guard guarding activated time - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), propertyData: propertyData, startTime: start, endTime: endTime }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5907,7 +5923,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending delivery guard uncollected package alert command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set delivery guard uncollected package alert - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5943,7 +5959,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, propertyData.value); - this.log.debug(`Sending delivery guard uncollected package alert time to check command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set delivery guard uncollected package alert time to check - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -5980,7 +5996,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending delivery guard package live check assistance command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set delivery guard package live check assistance - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -6016,7 +6032,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, propertyData.value); - this.log.debug(`Sending dual cam watch view mode command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set dual cam watch view mode - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -6050,7 +6066,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, propertyData.value); - this.log.debug(`Sending ring auto response command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${propertyData.value}`); + this.log.debug(`Station set ring auto response - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), propertyData: propertyData, enabled: enabled, voiceID: voiceID, autoVoiceResponse: autoVoiceResponse, startTime: startTime, endTime: endTime }); if (device.isBatteryDoorbellDual() || device.isWiredDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -6177,7 +6193,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification radar detector command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification radar detector - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isBatteryDoorbellDual()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -6209,7 +6225,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceCalibrate)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } - this.log.debug(`Sending calibrate command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station calibrate - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); if (device.isPanAndTiltCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -6239,7 +6255,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending continuous recording command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set continuous recording - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -6275,7 +6291,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending continuous recording type command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set continuous recording type - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -6311,7 +6327,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending default angle command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station enable default angle - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -6340,7 +6356,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending default angle idle time command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set default angle idle time - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -6365,7 +6381,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceSetDefaultAngle)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } - this.log.debug(`Sending set default angle command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set default angle - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -6390,7 +6406,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceSetPrivacyAngle)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } - this.log.debug(`Sending set privacy angle command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set privacy angle - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -6419,7 +6435,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending notification interval time command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set notification interval time - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithInt({ commandType: CommandType.CMD_DEV_RECORD_INTERVAL, value: value, @@ -6444,7 +6460,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending sound detection round look command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set sound detection round look - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -6472,7 +6488,7 @@ export class Station extends TypedEmitter { if (!this.isLiveStreaming(device)) { throw new LivestreamNotRunningError("Livestream for device is not running", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } - this.log.debug(`Sending start talkback command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station start talkback - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); if (device.isIndoorCamera() || device.isSoloCamera() || device.isFloodLight() || device.isWiredDoorbell() || device.isSmartDrop() || device.isStarlight4GLTE() || device.isWallLightCam() || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -6517,7 +6533,7 @@ export class Station extends TypedEmitter { if (!this.isLiveStreaming(device)) { throw new LivestreamNotRunningError("Livestream for device is not running", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } - this.log.debug(`Sending stop talkback command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station stop talkback - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); if (device.isIndoorCamera() || device.isSoloCamera() || device.isFloodLight() || device.isWiredDoorbell() || device.isSmartDrop() || device.isStarlight4GLTE() || device.isWallLightCam() || device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -6578,7 +6594,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending scramble passcode command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set scramble passcode - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceScramblePasscode, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -6601,7 +6617,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending wrong try protection command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set wrong try protection - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceWrongTryProtection, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -6624,7 +6640,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending wrong try attempts command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set wrong try attempts - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceWrongTryAttempts, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -6647,7 +6663,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending wrong try lockdown time command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set wrong try lockdown time - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceWrongTryLockdownTime, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -6686,7 +6702,7 @@ export class Station extends TypedEmitter { const propertyMetadata = device.getPropertyMetadata(propertyData.name); validValue(propertyMetadata, value); - this.log.debug(`Sending set smart safe settings command to station ${this.getSerial()} for device ${device.getSerial()} property ${property}`); + this.log.debug(`Station set smart safe params - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), property: property, value: value }); if (device.isSmartSafe()) { let payload: Buffer; let command: number; @@ -6851,7 +6867,7 @@ export class Station extends TypedEmitter { break; } - this.log.debug(`device: ${device.getSerial()} property: ${property} value: ${value} payload: ${payload.toString("hex")}`); + this.log.debug(`Station set smart safe params - payload`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), property: property, value: value, payload: payload.toString("hex") }); await this._sendSmartSafeCommand(device, command, payload, { property: propertyData }); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); @@ -6869,7 +6885,7 @@ export class Station extends TypedEmitter { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } const payload = SmartSafe.encodeCmdUnlock(this.rawStation.member.admin_user_id); - this.log.debug(`Sending trigger device unlock command to station ${this.getSerial()} for device ${device.getSerial()}`, { payload: payload.toString("hex") }); + this.log.debug(`Station unlock - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), payload: payload.toString("hex") }); await this._sendSmartSafeCommand(device, SmartSafeCommandCode.UNLOCK, payload, { command: commandData }); } @@ -6887,7 +6903,7 @@ export class Station extends TypedEmitter { throw new InvalidCommandValueError("PIN should contain only numbers (1-6) and be between 4 and 8 long", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } const payload = SmartSafe.encodeCmdVerifyPIN(this.rawStation.member.admin_user_id, pin); - this.log.debug(`Sending device verify pin command to station ${this.getSerial()} for device ${device.getSerial()}`, { payload: payload.toString("hex") }); + this.log.debug(`Station verify pin - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), payload: payload.toString("hex") }); await this._sendSmartSafeCommand(device, SmartSafeCommandCode.SET_VERIFY_PIN, payload, { command: commandData }); } @@ -6933,7 +6949,7 @@ export class Station extends TypedEmitter { await this.setContinuousRecording(device, true); } - this.log.debug(`Sending video type store to NAS command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set video type store to nas - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, value: JSON.stringify({ @@ -6966,7 +6982,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceSnooze)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending snooze command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station snooze - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isDoorbell()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_SNOOZE_MODE, @@ -7015,7 +7031,7 @@ export class Station extends TypedEmitter { if (!/^\d{4,8}$/.test(passcode)) { throw new InvalidCommandValueError("Passcode should contain only numbers and be between 4 and 8 long", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending add user command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station add user - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), username: username, shortUserId: shortUserId, schedule: schedule }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { // passcode: min 4 max 8 // passcode: 13579753 => 3133353739373533 @@ -7084,7 +7100,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceDeleteUser)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending delete user command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station delete user - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), username: username, shortUserId: shortUserId }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { const nestedPayload = { userId: shortUserId, @@ -7099,7 +7115,7 @@ export class Station extends TypedEmitter { nestedPayload ); this.p2pSession.setLockAESKey(CommandType.P2P_DELETE_USER, command.aesKey); - this.log.debug("Delete user...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); + this.log.debug("Station delete user - payload", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); await this.p2pSession.sendCommandWithStringPayload(command, { command: commandData @@ -7114,7 +7130,7 @@ export class Station extends TypedEmitter { this.p2pSession.incLockSequenceNumber(), Lock.encodeCmdDeleteUser(shortUserId) ); - this.log.debug("Delete user...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command }); + this.log.debug("Station delete user - payload", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command }); await this._sendLockV12P2PCommand(command, { command: commandData @@ -7139,7 +7155,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceUpdateUserSchedule)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending update user schedule command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station update user schedule - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), username: username, shortUserId: shortUserId, schedule: schedule }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { const nestedPayload = { endDay: schedule !== undefined && schedule.endDateTime !== undefined ? hexDate(schedule.endDateTime) : "ffffffff", @@ -7159,7 +7175,7 @@ export class Station extends TypedEmitter { nestedPayload ); this.p2pSession.setLockAESKey(CommandType.P2P_UPDATE_USER_TIME, command.aesKey); - this.log.debug("Update user time...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); + this.log.debug("Station update user schedule - payload", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); await this.p2pSession.sendCommandWithStringPayload(command, { command: commandData @@ -7174,7 +7190,7 @@ export class Station extends TypedEmitter { this.p2pSession.incLockSequenceNumber(), Lock.encodeCmdUpdateSchedule(shortUserId, schedule) ); - this.log.debug("Update user time...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command }); + this.log.debug("Station update user schedule - payload", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command }); await this._sendLockV12P2PCommand(command, { command: commandData @@ -7202,7 +7218,7 @@ export class Station extends TypedEmitter { if (passcode.length < 4 || passcode.length > 8 || !/^\d+$/.test(passcode)) { throw new InvalidCommandValueError("Passcode should contain only numbers and be between 4 and 8 long", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name, commandValue: commandData.value } }); } - this.log.debug(`Sending update user passcode command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station update user passcode - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), username: username, shortUserId: shortUserId }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { const nestedPayload = { passcode: encodePasscode(passcode), @@ -7218,7 +7234,7 @@ export class Station extends TypedEmitter { nestedPayload ); this.p2pSession.setLockAESKey(CommandType.P2P_UPDATE_PW, command.aesKey); - this.log.debug("Update user time...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); + this.log.debug("Station update user passcode - payload", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command, nestedPayload: nestedPayload }); await this.p2pSession.sendCommandWithStringPayload(command, { command: commandData @@ -7233,7 +7249,7 @@ export class Station extends TypedEmitter { this.p2pSession.incLockSequenceNumber(), Lock.encodeCmdModifyPassword(shortUserId, encodePasscode(passcode)) ); - this.log.debug("Update user time...", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command }); + this.log.debug("Station update user passcode - payload", { station: this.getSerial(), device: device.getSerial(), admin_user_id: this.rawStation.member.admin_user_id, payload: command }); await this._sendLockV12P2PCommand(command, { command: commandData @@ -7257,7 +7273,7 @@ export class Station extends TypedEmitter { const propertyMetadata = device.getPropertyMetadata(propertyData.name); validValue(propertyMetadata, value); - this.log.debug(`Sending set lock v12 settings command to station ${this.getSerial()} for device ${device.getSerial()} property ${property}`); + this.log.debug(`Station set lock v12 settings - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), property: property, value: value }); if (device.isLockWifiR10() || device.isLockWifiR20()) { let payload: Buffer; switch (property) { @@ -7335,7 +7351,7 @@ export class Station extends TypedEmitter { break; } - this.log.debug(`device: ${device.getSerial()} property: ${property} value: ${value} payload: ${payload.toString("hex")}`); + this.log.debug(`Station set lock v12 settings - payload`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), property: property, value: value, payload: payload.toString("hex") }); const lockCommand = getLockV12P2PCommand( this.rawStation.station_sn, this.rawStation.member.admin_user_id, @@ -7364,7 +7380,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending auto lock command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set auto lock - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceAutoLock, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -7385,7 +7401,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending auto lock schedule command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set auto lock schedule - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceAutoLockSchedule, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -7406,7 +7422,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending auto lock schedule start time command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set auto lock schedule start time - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceAutoLockScheduleStartTime, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -7427,7 +7443,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending auto lock schedule end time command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set auto lock schedule end time - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceAutoLockScheduleEndTime, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -7448,7 +7464,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending auto lock timer command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set auto lock timer - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceAutoLockTimer, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -7469,7 +7485,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending one touch locking command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set one touch locking - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceOneTouchLocking, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -7490,7 +7506,7 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending sound command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set sound - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceSound, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { @@ -7511,11 +7527,12 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending notification command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set notification - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceNotification, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { //TODO: Implement LockWifiR10 / LockWifiR20 commnand + throw new NotSupportedError("This functionality is not implemented by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } else if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -7543,11 +7560,12 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending notification locked command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set notification locked - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceNotificationLocked, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { //TODO: Implement LockWifiR10 / LockWifiR20 commnand + throw new NotSupportedError("This functionality is not implemented by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } @@ -7564,11 +7582,12 @@ export class Station extends TypedEmitter { if (!device.hasProperty(propertyData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending notification unlocked command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station set notification unlocked - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isLockWifi() || device.isLockWifiNoFinger()) { await this.setAdvancedLockParams(device, PropertyName.DeviceNotificationUnlocked, value); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { //TODO: Implement LockWifiR10 / LockWifiR20 commnand + throw new NotSupportedError("This functionality is not implemented by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } else { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } @@ -7589,8 +7608,9 @@ export class Station extends TypedEmitter { if (!device.hasCommand(commandData.name)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } - this.log.debug(`Sending query all user id command to station ${this.getSerial()} for device ${device.getSerial()}`); + this.log.debug(`Station query all user id - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial() }); if (device.isLockBleNoFinger() || device.isLockBle()) { + throw new NotSupportedError("This functionality is not implemented by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); //TODO: Finish implementation of query all user id for LockBleNoFinger / LockBle /*const key = generateBasicLockAESKey(this.rawStation.member.admin_user_id, this.getSerial()); const iv = getLockVectorBytes(this.getSerial()); @@ -7638,6 +7658,7 @@ export class Station extends TypedEmitter { command: commandData }); } else if (device.isLockWifiR10() || device.isLockWifiR20()) { + throw new NotSupportedError("This functionality is not implemented by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); //TODO: Finish implementation of query all user id for r10 / r20 /*const command = getLockV12P2PCommand( this.rawStation.station_sn, @@ -7673,7 +7694,7 @@ export class Station extends TypedEmitter { } }); } - this.log.debug(`Sending homebase chime command to station ${this.getSerial()} with value: ${value}`); + this.log.debug(`Station chime homebase - sending command`, { stationSN: this.getSerial(), value: value }); if (this.isStation()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, @@ -7706,7 +7727,7 @@ export class Station extends TypedEmitter { if (!this.hasCommand(CommandName.StationDownloadImage)) { throw new NotSupportedError("This functionality is not implemented or supported", { context: { commandName: commandData.name, commandValue: commandData.value, station: this.getSerial()} }); } - this.log.debug(`Sending download image command to station ${this.getSerial()} for file ${cover_path}`); + this.log.debug(`Station download image - sending command`, { stationSN: this.getSerial(), value: cover_path }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ @@ -7735,7 +7756,7 @@ export class Station extends TypedEmitter { throw new NotSupportedError("This functionality is not implemented or supported", { context: { commandName: commandData.name, station: this.getSerial()} }); } - this.log.debug(`Sending database query latest info command to station ${this.getSerial()}`); + this.log.debug(`Station database query latest info - sending command`, { stationSN: this.getSerial() }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ @@ -7768,7 +7789,7 @@ export class Station extends TypedEmitter { throw new NotSupportedError("This functionality is not implemented or supported", { context: { commandName: commandData.name, commandValue: commandData.value, station: this.getSerial()} }); } - this.log.debug(`Sending database query local command to station ${this.getSerial()}`, { serialNumbers: serialNumbers, startDate: startDate, endDate: endDate, eventType: eventType, detectionType:detectionType, storageType: storageType }); + this.log.debug(`Station database query local - sending command`, { stationSN: this.getSerial(), serialNumbers: serialNumbers, startDate: startDate, endDate: endDate, eventType: eventType, detectionType:detectionType, storageType: storageType }); const devices: Array<{ device_sn: string; }> = []; for(const serial of serialNumbers) { devices.push({ device_sn: serial }); @@ -7814,7 +7835,7 @@ export class Station extends TypedEmitter { throw new NotSupportedError("This functionality is not implemented or supported", { context: { commandName: commandData.name, commandValue: commandData.value, station: this.getSerial()} }); } - this.log.debug(`Sending database delete command to station ${this.getSerial()}`, { ids: ids }); + this.log.debug(`Station database delete - sending command`, { stationSN: this.getSerial(), ids: ids }); const lids: Array<{ "id": number; }> = []; for (const id of ids) { lids.push({ "id": id }); @@ -7851,7 +7872,7 @@ export class Station extends TypedEmitter { throw new NotSupportedError("This functionality is not implemented or supported", { context: { commandName: commandData.name, commandValue: commandData.value, station: this.getSerial()} }); } - this.log.debug(`Sending database count by date command to station ${this.getSerial()}`, { startDate: startDate, endDate: endDate }); + this.log.debug(`Station database count by date - sending command`, { stationSN: this.getSerial(), startDate: startDate, endDate: endDate }); await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_SET_PAYLOAD, value: JSON.stringify({ @@ -7909,7 +7930,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending motion detection type human command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set motion detection type human - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -7940,7 +7961,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending motion detection type all other motions command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set motion detection type all other motions - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -7971,7 +7992,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting ${type} lighting active mode command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${JSON.stringify(value)}`); + this.log.debug(`Station set set light settings lighting active mode - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), propertyName: propertyName, value: value, type: type }); if (device.isWallLightCam()) { switch(value) { case LightingActiveMode.DAILY: { @@ -8083,7 +8104,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting manual daily lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings manual daily lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8122,7 +8143,7 @@ export class Station extends TypedEmitter { throw new InvalidPropertyValueError("Invalid value for this property", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending light setting manual colored lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${JSON.stringify(value)}`); + this.log.debug(`Station set light settings manual colored lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8158,7 +8179,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting manual dynamic lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings manual dynamic lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8196,7 +8217,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting motion daily lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings motion daily lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8235,7 +8256,7 @@ export class Station extends TypedEmitter { throw new InvalidPropertyValueError("Invalid value for this property", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending light setting motion colored lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${JSON.stringify(value)}`); + this.log.debug(`Station set light settings motion colored lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8271,7 +8292,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting motion dynamic lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings motion dynamic lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8309,7 +8330,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting schedule daily lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings schedule daily lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8348,7 +8369,7 @@ export class Station extends TypedEmitter { throw new InvalidPropertyValueError("Invalid value for this property", { context: { device: device.getSerial(), station: this.getSerial(), propertyName: propertyData.name, propertyValue: propertyData.value } }); } - this.log.debug(`Sending light setting schedule colored lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${JSON.stringify(value)}`); + this.log.debug(`Station set light settings schedule colored lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8384,7 +8405,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting schedule dynamic lighting command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set light settings schedule dynamic lighting - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8418,7 +8439,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting colored lighting colors command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${JSON.stringify(value)}`); + this.log.debug(`Station set light settings colored lighting colors - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { const colors: Array = [{"color":16760832}, {"color":16744448}, {"color":16728320}, {"color":16720384}, {"color":16711696}, {"color":3927961}, {"color":1568995}, {"color":485368}, {"color":9983}, {"color":4664060}]; if (value.length > 0 && value.length <= 15) { @@ -8469,7 +8490,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending light setting dynamic lighting themes command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${JSON.stringify(value)}`); + this.log.debug(`Station set light settings dynamic lighting themes - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isWallLightCam()) { const themes:Array = [{"name":"Aurora","mode":1,"id":0,"speed":4000,"colors":[65321,65468,28671,9215,42239]},{"name":"Warmth","mode":1,"id":1,"speed":4000,"colors":[16758528,16744448,16732160,16719360,16742144]},{"name":"Let's Party","mode":2,"id":2,"speed":500,"colors":[16718080,16756736,65298,40703,4980991]}]; if (value.length > 0 && value.length <= 23) { @@ -8526,7 +8547,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending door control warning command to station ${this.getSerial()} for device ${device.getSerial()} with value: ${value}`); + this.log.debug(`Station set door control warning - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value }); if (device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8563,7 +8584,7 @@ export class Station extends TypedEmitter { const property = device.getPropertyMetadata(propertyData.name); validValue(property, value); - this.log.debug(`Sending open door command to station ${this.getSerial()} for device ${device.getSerial()} doorId ${doorId} with value: ${value}`); + this.log.debug(`Station open door - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), value: value, doorId: doorId }); if (device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, @@ -8600,7 +8621,7 @@ export class Station extends TypedEmitter { if (!device.hasCommand(CommandName.DeviceCalibrateGarageDoor)) { throw new NotSupportedError("This functionality is not implemented or supported by this device", { context: { device: device.getSerial(), station: this.getSerial(), commandName: commandData.name } }); } - this.log.debug(`Sending calibrate garage door command to station ${this.getSerial()} for device ${device.getSerial()} doorId ${doorId} type ${CalibrateGarageType[type]}`); + this.log.debug(`Station calibrate garage door - sending command`, { stationSN: this.getSerial(), deviceSN: device.getSerial(), doorId: doorId, type: type }); if (device.isGarageCamera()) { await this.p2pSession.sendCommandWithStringPayload({ commandType: CommandType.CMD_DOORBELL_SET_PAYLOAD, diff --git a/src/http/types.ts b/src/http/types.ts index e22ac415..4048c0cc 100644 --- a/src/http/types.ts +++ b/src/http/types.ts @@ -5065,7 +5065,7 @@ export const DeviceProperties: Properties = { [PropertyName.DeviceSnoozeStartTime]: DeviceSnoozeStartTimeProperty, [PropertyName.DevicePersonName]: DevicePersonNameProperty, }, - [DeviceType.FLOODLIGHT_CAMERA_8424]: { + [DeviceType.FLOODLIGHT_CAMERA_8424]: { // T8424 Firmware: 2.0.8.8 (20230807) ...GenericDeviceProperties, [PropertyName.DeviceEnabled]: DeviceEnabledStandaloneProperty, [PropertyName.DeviceAutoNightvision]: DeviceAutoNightvisionProperty, @@ -5095,8 +5095,8 @@ export const DeviceProperties: Properties = { [PropertyName.DeviceVideoStreamingQuality]: DeviceVideoStreamingQualityProperty, [PropertyName.DeviceNotificationType]: DeviceNotificationTypeIndoorFloodlightProperty, [PropertyName.DeviceVideoRecordingQuality]: DeviceVideoRecordingQualityIndoorProperty, - [PropertyName.DeviceWifiRSSI]: DeviceWifiRSSIProperty, - [PropertyName.DeviceWifiSignalLevel]: DeviceWifiSignalLevelProperty, + //[PropertyName.DeviceWifiRSSI]: DeviceWifiRSSIProperty, + //[PropertyName.DeviceWifiSignalLevel]: DeviceWifiSignalLevelProperty, [PropertyName.DeviceSnooze]: DeviceSnoozeProperty, [PropertyName.DeviceSnoozeTime]: DeviceSnoozeTimeProperty, [PropertyName.DeviceSnoozeStartTime]: DeviceSnoozeStartTimeProperty, diff --git a/src/interfaces.ts b/src/interfaces.ts index 96449422..30bf65c9 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -119,4 +119,9 @@ export interface EufySecurityEvents { "user username updated": (device: Device, username: string) => void; "user schedule updated": (device: Device, username: string, schedule: Schedule) => void; "user passcode updated": (device: Device, username: string) => void; +} + +export interface ErrorObject { + message: string; + stacktrace?: string; } \ No newline at end of file diff --git a/src/mqtt/service.ts b/src/mqtt/service.ts index dd038a2c..ba7f2c22 100644 --- a/src/mqtt/service.ts +++ b/src/mqtt/service.ts @@ -7,6 +7,7 @@ import { load, Root } from "protobufjs"; import { MQTTServiceEvents } from "./interface"; import { DeviceSmartLockMessage } from "./model"; +import { getError } from "../utils"; export class MQTTService extends TypedEmitter { @@ -110,17 +111,17 @@ export class MQTTService extends TypedEmitter { }); this.client.on("error", (error) => { this.connecting = false; - this.log.error("MQTT Error", error); + this.log.error("MQTT Error", { error: getError(error) }); if ((error as any).code === 1 || (error as any).code === 2 || (error as any).code === 4 || (error as any).code === 5) this.client?.end(); }); this.client.on("message", (topic, message, _packet) => { if (topic.includes("smart_lock")) { const parsedMessage = this.parseSmartLockMessage(message); - this.log.debug("Received a smart lock message over MQTT", parsedMessage); + this.log.debug("Received a smart lock message over MQTT", { message: parsedMessage }); this.emit("lock message", parsedMessage); } else { - this.log.debug("MQTT message received", topic, message.toString("hex")); + this.log.debug("MQTT message received", { topic: topic, message: message.toString("hex") }); } }); } @@ -129,7 +130,7 @@ export class MQTTService extends TypedEmitter { private _subscribeLock(deviceSN: string): void { this.client?.subscribe(this.SUBSCRIBE_LOCK_FORMAT.replace("", deviceSN), { qos: 1 }, (error, granted) => { if (error) { - this.log.error(`Subscribe error for lock ${deviceSN}`, error); + this.log.error(`Subscribe error for lock ${deviceSN}`, { error: getError(error), deviceSN: deviceSN }); } if (granted) { this.log.info(`Successfully registered to MQTT notifications for lock ${deviceSN}`); diff --git a/src/p2p/interfaces.ts b/src/p2p/interfaces.ts index 0b212eef..14e7ec40 100644 --- a/src/p2p/interfaces.ts +++ b/src/p2p/interfaces.ts @@ -5,7 +5,7 @@ import { SortedMap } from "sweet-collections"; import { AlarmMode, DeviceType, MicStatus, TriggerType, VideoType } from "../http/types"; import { Address, CmdCameraInfoResponse, CommandResult, CustomData } from "./models"; import { TalkbackStream } from "./talkback"; -import { AlarmEvent, AudioCodec, ChargingType, CommandType, DatabaseReturnCode, IndoorSoloSmartdropCommandType, P2PDataType, SmartSafeAlarm911Event, SmartSafeShakeAlarmEvent, P2PStorageType, TFCardStatus, VideoCodec } from "./types"; +import { AlarmEvent, AudioCodec, ChargingType, CommandType, DatabaseReturnCode, IndoorSoloSmartdropCommandType, P2PDataType, SmartSafeAlarm911Event, SmartSafeShakeAlarmEvent, P2PStorageType, TFCardStatus, VideoCodec, InternalP2PCommandType } from "./types"; export interface P2PClientProtocolEvents { "alarm mode": (mode: AlarmMode) => void; @@ -51,10 +51,12 @@ export interface P2PClientProtocolEvents { } export interface P2PQueueMessage { - commandType: CommandType; + p2pCommandType: InternalP2PCommandType; + p2pCommand: P2PCommand; + //commandType: CommandType; nestedCommandType?: CommandType; - channel: number; - payload: Buffer; + //channel: number; + //payload: Buffer; timestamp: number; customData?: CustomData; } diff --git a/src/p2p/session.ts b/src/p2p/session.ts index 1a520dfa..f04cf09e 100644 --- a/src/p2p/session.ts +++ b/src/p2p/session.ts @@ -7,8 +7,8 @@ import { SortedMap } from "sweet-collections"; import date from "date-and-time"; import { Address, CmdCameraInfoResponse, CmdNotifyPayload, CommandResult, ESLAdvancedLockStatusNotification, ESLStationP2PThroughData, SmartSafeSettingsNotification, SmartSafeStatusNotification, CustomData, ESLBleV12P2PThroughData, CmdDatabaseImageResponse, EntrySensorStatus, GarageDoorStatus } from "./models"; -import { sendMessage, hasHeader, buildCheckCamPayload, buildIntCommandPayload, buildIntStringCommandPayload, buildCommandHeader, MAGIC_WORD, buildCommandWithStringTypePayload, isPrivateIp, buildLookupWithKeyPayload, sortP2PMessageParts, buildStringTypeCommandPayload, getRSAPrivateKey, decryptAESData, getNewRSAPrivateKey, findStartCode, isIFrame, generateLockSequence, decodeLockPayload, generateBasicLockAESKey, getLockVectorBytes, decryptLockAESData, buildLookupWithKeyPayload2, buildCheckCamPayload2, buildLookupWithKeyPayload3, decodeBase64, getVideoCodec, checkT8420, buildVoidCommandPayload, isP2PQueueMessage, buildTalkbackAudioFrameHeader, getLocalIpAddress, decodeP2PCloudIPs, getLockV12P2PCommand, decodeSmartSafeData, decryptPayloadData } from "./utils"; -import { RequestMessageType, ResponseMessageType, CommandType, ErrorCode, P2PDataType, P2PDataTypeHeader, AudioCodec, VideoCodec, P2PConnectionType, ChargingType, AlarmEvent, IndoorSoloSmartdropCommandType, SmartSafeCommandCode, ESLCommand, ESLBleCommand, TFCardStatus } from "./types"; +import { sendMessage, hasHeader, buildCheckCamPayload, buildIntCommandPayload, buildIntStringCommandPayload, buildCommandHeader, MAGIC_WORD, buildCommandWithStringTypePayload, isPrivateIp, buildLookupWithKeyPayload, sortP2PMessageParts, buildStringTypeCommandPayload, getRSAPrivateKey, decryptAESData, getNewRSAPrivateKey, findStartCode, isIFrame, generateLockSequence, decodeLockPayload, generateBasicLockAESKey, getLockVectorBytes, decryptLockAESData, buildLookupWithKeyPayload2, buildCheckCamPayload2, buildLookupWithKeyPayload3, decodeBase64, getVideoCodec, checkT8420, buildVoidCommandPayload, isP2PQueueMessage, buildTalkbackAudioFrameHeader, getLocalIpAddress, decodeP2PCloudIPs, getLockV12P2PCommand, decodeSmartSafeData, decryptPayloadData, decryptP2PData, getP2PCommandEncryptionKey, getNullTerminatedString } from "./utils"; +import { RequestMessageType, ResponseMessageType, CommandType, ErrorCode, P2PDataType, P2PDataTypeHeader, AudioCodec, VideoCodec, P2PConnectionType, ChargingType, AlarmEvent, IndoorSoloSmartdropCommandType, SmartSafeCommandCode, ESLCommand, ESLBleCommand, TFCardStatus, EncryptionType, InternalP2PCommandType } from "./types"; import { AlarmMode } from "../http/types"; import { P2PDataMessage, P2PDataMessageAudio, P2PDataMessageBuilder, P2PMessageState, P2PDataMessageVideo, P2PMessage, P2PDataHeader, P2PDataMessageState, P2PClientProtocolEvents, DeviceSerial, P2PQueueMessage, P2PCommand, P2PVideoMessageState, P2PDatabaseResponse, P2PDatabaseQueryLatestInfoResponse, P2PDatabaseDeleteResponse, DatabaseQueryLatestInfo, DatabaseCountByDate, P2PDatabaseCountByDateResponse, P2PDatabaseQueryLocalResponse, DatabaseQueryLocal, P2PDatabaseQueryLocalHistoryRecordInfo, P2PDatabaseQueryLocalRecordCropPictureInfo } from "./interfaces"; import { DskKeyResponse, ResultResponse, StationListResponse } from "../http/models"; @@ -21,7 +21,7 @@ import { SmartSafeEvent } from "../push/types"; import { SmartSafeEventValueDetail } from "../push/models"; import { BleCommandFactory } from "./ble"; import { CommandName, Station } from "../http"; -import { parseJSON } from "../utils"; +import { getError, parseJSON } from "../utils"; export class P2PClientProtocol extends TypedEmitter { @@ -103,8 +103,9 @@ export class P2PClientProtocol extends TypedEmitter { private connectionType: P2PConnectionType = P2PConnectionType.QUICKEST; private energySavingDevice = false; - private energySavingDeviceP2PSeqMapping: Map = new Map(); - private energySavingDeviceP2PDataSeqNumber = 0; + + private p2pSeqMapping: Map = new Map(); + private p2pDataSeqNumber = 0; private connectAddress: Address | undefined = undefined; private localIPAddress: string | undefined = undefined; @@ -120,6 +121,8 @@ export class P2PClientProtocol extends TypedEmitter { private lockPublicKey: string; private lockAESKeys: Map = new Map(); private channel = 255; + private encryption: EncryptionType = EncryptionType.NONE; + private p2pKey?: Buffer; constructor(rawStation: StationListResponse, api: HTTPApi, ipAddress?:string, publicKey = "") { super(); @@ -128,7 +131,7 @@ export class P2PClientProtocol extends TypedEmitter { this.preferredIPAddress = ipAddress; this.log = api.getLog(); this.cloudAddresses = decodeP2PCloudIPs(rawStation.app_conn); - this.log.debug("Loaded P2P cloud ip addresses", this.cloudAddresses); + this.log.debug("Loaded P2P cloud ip addresses", { stationSN: rawStation.station_sn, ipAddress: ipAddress, cloudAddresses: this.cloudAddresses }); this.updateRawStation(rawStation); this.socket = createSocket("udp4"); @@ -173,18 +176,20 @@ export class P2PClientProtocol extends TypedEmitter { this.seqNumber = 0; this.offsetDataSeqNumber = 0; this.videoSeqNumber = 0; - this.energySavingDeviceP2PDataSeqNumber = 0; + this.p2pDataSeqNumber = 0; this.lockSeqNumber = -1; this.connectAddress = undefined; this.lastChannel = undefined; this.lastCustomData = undefined; + this.encryption = EncryptionType.NONE; + this.p2pKey = undefined; this.lockAESKeys.clear(); this._clearMessageStateTimeouts(); this._clearMessageVideoStateTimeouts(); this.messageStates.clear(); this.messageVideoStates.clear(); - this.energySavingDeviceP2PSeqMapping.clear(); + this.p2pSeqMapping.clear(); for(let datatype = 0; datatype < 4; datatype++) { @@ -305,7 +310,7 @@ export class P2PClientProtocol extends TypedEmitter { private async sendMessage(errorSubject: string, address: Address, msgID: Buffer, payload?: Buffer): Promise { await sendMessage(this.socket, address, msgID, payload).catch((err) => { const error = ensureError(err); - this.log.error(`${errorSubject} - msgID: ${msgID.toString("hex")} payload: ${payload?.toString("hex")} - Error`, error); + this.log.error(`${errorSubject} - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, address: address, msgID: msgID.toString("hex"), payload: payload?.toString("hex") }); }); } @@ -329,7 +334,7 @@ export class P2PClientProtocol extends TypedEmitter { for (const channel in this.currentMessageState[P2PDataType.DATA].rtspStreaming) { this.endRTSPStream(Number.parseInt(channel)); } - this.sendQueue = this.sendQueue.filter((queue) => queue.commandType !== CommandType.CMD_PING && queue.commandType !== CommandType.CMD_GET_DEVICE_PING); + this.sendQueue = this.sendQueue.filter((queue) => queue.p2pCommand.commandType !== CommandType.CMD_PING && queue.p2pCommand.commandType !== CommandType.CMD_GET_DEVICE_PING); if (this.connected) { this.emit("close"); } else if (!this.terminating) { @@ -339,15 +344,15 @@ export class P2PClientProtocol extends TypedEmitter { } private closeEnergySavingDevice(): void { - if (this.sendQueue.filter((queue) => queue.commandType !== CommandType.CMD_PING && queue.commandType !== CommandType.CMD_GET_DEVICE_PING).length === 0 && + if (this.sendQueue.filter((queue) => queue.p2pCommand.commandType !== CommandType.CMD_PING && queue.p2pCommand.commandType !== CommandType.CMD_GET_DEVICE_PING).length === 0 && this.energySavingDevice && !this.isCurrentlyStreaming() && Array.from(this.messageStates.values()).filter((msgState) => msgState.acknowledged === false).length === 0) { if (this.esdDisconnectTimeout === undefined) { - this.log.debug(`Station ${this.rawStation.station_sn} - Energy saving device - No more p2p commands to execute or running streams, initiate disconnect timeout in ${this.ESD_DISCONNECT_TIMEOUT} milliseconds...`); + this.log.debug(`Energy saving device - No more p2p commands to execute or running streams, initiate disconnect timeout in ${this.ESD_DISCONNECT_TIMEOUT} milliseconds...`, { stationSN: this.rawStation.station_sn }); this.esdDisconnectTimeout = setTimeout(() => { this.esdDisconnectTimeout = undefined; - this.sendMessage(`Station ${this.rawStation.station_sn}`, this.connectAddress!, RequestMessageType.END); + this.sendMessage(`Closing of connection for battery saving`, this.connectAddress!, RequestMessageType.END); this.log.info(`Initiated closing of connection to station ${this.rawStation.station_sn} for saving battery.`); this.terminating = true; this._disconnected(); @@ -358,7 +363,7 @@ export class P2PClientProtocol extends TypedEmitter { private async renewDSKKey(): Promise { if (this.dskKey === "" || (this.dskExpiration && (new Date()).getTime() >= this.dskExpiration.getTime())) { - this.log.debug(`Station ${this.rawStation.station_sn} DSK keys not present or expired, get/renew it`, { dskKey: this.dskKey, dskExpiration: this.dskExpiration }); + this.log.debug(`DSK keys not present or expired, get/renew it`, { stationSN: this.rawStation.station_sn, dskKey: this.dskKey, dskExpiration: this.dskExpiration }); await this.getDSKKeys(); } } @@ -387,28 +392,28 @@ export class P2PClientProtocol extends TypedEmitter { // Send lookup message const msgId = RequestMessageType.LOCAL_LOOKUP; const payload = Buffer.from([0, 0]); - await this.sendMessage(`Local lookup address for station ${this.rawStation.station_sn}`, address, msgId, payload); + await this.sendMessage(`Local lookup address`, address, msgId, payload); } private async cloudLookupByAddress(address: Address): Promise { // Send lookup message const msgId = RequestMessageType.LOOKUP_WITH_KEY; const payload = buildLookupWithKeyPayload(this.socket, this.rawStation.p2p_did, this.dskKey); - await this.sendMessage(`Cloud lookup addresses for station ${this.rawStation.station_sn}`, address, msgId, payload); + await this.sendMessage(`Cloud lookup addresses`, address, msgId, payload); } private async cloudLookupByAddress2(address: Address): Promise { // Send lookup message2 const msgId = RequestMessageType.LOOKUP_WITH_KEY2; const payload = buildLookupWithKeyPayload2(this.rawStation.p2p_did, this.dskKey); - await this.sendMessage(`Cloud lookup addresses (2) for station ${this.rawStation.station_sn}`, address, msgId, payload); + await this.sendMessage(`Cloud lookup addresses (2)`, address, msgId, payload); } private async cloudLookupByAddress3(address: Address, origAddress: Address, data: Buffer): Promise { // Send lookup message3 const msgId = RequestMessageType.LOOKUP_WITH_KEY3; const payload = buildLookupWithKeyPayload3(this.rawStation.p2p_did, origAddress, data); - await this.sendMessage(`Cloud lookup addresses (3) for station ${this.rawStation.station_sn}`, address, msgId, payload); + await this.sendMessage(`Cloud lookup addresses (3)`, address, msgId, payload); } public isConnected(): boolean { @@ -418,13 +423,13 @@ export class P2PClientProtocol extends TypedEmitter { private _startConnectTimeout(): void { if (this.connectTimeout === undefined) this.connectTimeout = setTimeout(() => { - this.log.warn(`Station ${this.rawStation.station_sn} - Tried all hosts, no connection could be established`); + this.log.warn(`Tried all hosts, no connection could be established to station ${this.rawStation.station_sn}.`); this._disconnected(); }, this.MAX_AKNOWLEDGE_TIMEOUT); } private _connect(address: Address, p2p_did: string): void { - this.log.debug(`Station ${this.rawStation.station_sn} - CHECK_CAM - Connecting to host ${address.host} on port ${address.port}...`); + this.log.debug(`Connecting to host ${address.host} on port ${address.port} (CHECK_CAM)`, { stationSN: this.rawStation.station_sn, address: address, p2pDid: p2p_did }); for (let i = 0; i < 4; i++) this.sendCamCheck(address, p2p_did); @@ -449,7 +454,7 @@ export class P2PClientProtocol extends TypedEmitter { this.lookupTimeout = setTimeout(() => { this.lookupTimeout = undefined; - this.log.error(`Station ${this.rawStation.station_sn} - All address lookup tentatives failed.`); + this.log.error(`All address lookup tentatives failed.`, { stationSN: this.rawStation.station_sn }); if (this.localIPAddress !== undefined) this.localIPAddress = undefined this._disconnected(); @@ -469,7 +474,7 @@ export class P2PClientProtocol extends TypedEmitter { this.socket.setBroadcast(true); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - Error`, { error: error, currentRecBufferSize: this.socket.getRecvBufferSize(), recBufferRequestedSize: this.UDP_RECVBUFFERSIZE_BYTES }); + this.log.error(`connect - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, host: host, currentRecBufferSize: this.socket.getRecvBufferSize(), recBufferRequestedSize: this.UDP_RECVBUFFERSIZE_BYTES }); } this.lookup(host); }); @@ -481,22 +486,22 @@ export class P2PClientProtocol extends TypedEmitter { private async sendCamCheck(address: Address, p2p_did: string): Promise { const payload = buildCheckCamPayload(p2p_did); - await this.sendMessage(`Send cam check to station ${this.rawStation.station_sn}`, address, RequestMessageType.CHECK_CAM, payload); + await this.sendMessage(`Send cam check`, address, RequestMessageType.CHECK_CAM, payload); } private async sendCamCheck2(address: Address, data: Buffer): Promise { const payload = buildCheckCamPayload2(this.rawStation.p2p_did, data); - await this.sendMessage(`Send cam check (2) to station ${this.rawStation.station_sn}`, address, RequestMessageType.CHECK_CAM2, payload); + await this.sendMessage(`Send cam check (2)`, address, RequestMessageType.CHECK_CAM2, payload); } public async sendPing(address: Address): Promise { if ((this.lastPong && ((new Date().getTime() - this.lastPong) / this.getHeartbeatInterval() >= this.MAX_RETRIES)) || (this.connectTime && !this.lastPong && ((new Date().getTime() - this.connectTime) / this.getHeartbeatInterval() >= this.MAX_RETRIES))) { if (!this.energySavingDevice) - this.log.warn(`Station ${this.rawStation.station_sn} - Heartbeat check failed. Connection seems lost. Try to reconnect...`); + this.log.warn(`Heartbeat check failed for station ${this.rawStation.station_sn}. Connection seems lost. Try to reconnect...`); this._disconnected(); } - await this.sendMessage(`Send ping to station ${this.rawStation.station_sn}`, address, RequestMessageType.PING, this.lastPongData); + await this.sendMessage(`Send ping`, address, RequestMessageType.PING, this.lastPongData); } public sendCommandWithIntString(p2pcommand: P2PCommand, customData?: CustomData): void { @@ -505,11 +510,7 @@ export class P2PClientProtocol extends TypedEmitter { if (p2pcommand.value === undefined || typeof p2pcommand.value !== "number") throw new TypeError("value must be a number"); - const payload = buildIntStringCommandPayload(this.rawStation.station_sn, this.rawStation.p2p_did, p2pcommand.commandType, p2pcommand.value, p2pcommand.valueSub === undefined ? 0 : p2pcommand.valueSub, p2pcommand.strValue === undefined ? "" : p2pcommand.strValue , p2pcommand.strValueSub === undefined ? "" : p2pcommand.strValueSub, p2pcommand.channel); - if (p2pcommand.commandType === CommandType.CMD_NAS_TEST) { - this.currentMessageState[P2PDataType.DATA].rtspStream[p2pcommand.channel] = p2pcommand.value === 1 ? true : false; - } - this.sendCommand(p2pcommand.commandType, payload, p2pcommand.channel, undefined, customData); + this.sendCommand(p2pcommand, InternalP2PCommandType.WithIntString, undefined, customData); } public sendCommandWithInt(p2pcommand: P2PCommand, customData?: CustomData): void { @@ -518,8 +519,7 @@ export class P2PClientProtocol extends TypedEmitter { if (p2pcommand.value === undefined || typeof p2pcommand.value !== "number") throw new TypeError("value must be a number"); - const payload = buildIntCommandPayload(this.rawStation.station_sn, this.rawStation.p2p_did, p2pcommand.commandType, p2pcommand.value, p2pcommand.strValue === undefined ? "" : p2pcommand.strValue, p2pcommand.channel); - this.sendCommand(p2pcommand.commandType, payload, p2pcommand.channel, undefined, customData); + this.sendCommand(p2pcommand, InternalP2PCommandType.WithInt, undefined, customData); } public sendCommandWithStringPayload(p2pcommand: P2PCommand, customData?: CustomData): void { @@ -538,7 +538,7 @@ export class P2PClientProtocol extends TypedEmitter { nested_commandType = json.cmd; } catch (err) { const error = ensureError(err); - this.log.error(`CMD_SET_PAYLOAD - Station ${this.rawStation.station_sn} - Error`, error); + this.log.error(`sendCommandWithStringPayload CMD_SET_PAYLOAD - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, p2pcommand: p2pcommand, customData: customData }); } } else if (p2pcommand.commandType == CommandType.CMD_DOORBELL_SET_PAYLOAD) { try { @@ -546,11 +546,11 @@ export class P2PClientProtocol extends TypedEmitter { nested_commandType = json.commandType; } catch (err) { const error = ensureError(err); - this.log.error(`CMD_DOORBELL_SET_PAYLOAD - Station ${this.rawStation.station_sn} - Error`, error); + this.log.error(`sendCommandWithStringPayload CMD_DOORBELL_SET_PAYLOAD - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, p2pcommand: p2pcommand, customData: customData }); } } - const payload = buildCommandWithStringTypePayload(this.rawStation.station_sn, this.rawStation.p2p_did, p2pcommand.commandType, p2pcommand.value, p2pcommand.channel); - this.sendCommand(p2pcommand.commandType, payload, p2pcommand.channel, nested_commandType, customData); + + this.sendCommand(p2pcommand, InternalP2PCommandType.WithStringPayload, nested_commandType, customData); } public sendCommandWithString(p2pcommand: P2PCommand, customData?: CustomData): void { @@ -561,23 +561,28 @@ export class P2PClientProtocol extends TypedEmitter { if (p2pcommand.strValueSub === undefined) throw new TypeError("strValueSub must be defined"); - const payload = buildStringTypeCommandPayload(this.rawStation.station_sn, this.rawStation.p2p_did, p2pcommand.commandType, p2pcommand.strValue, p2pcommand.strValueSub, p2pcommand.channel); - this.sendCommand(p2pcommand.commandType, payload, p2pcommand.channel, p2pcommand.commandType, customData); + this.sendCommand(p2pcommand, InternalP2PCommandType.WithString, p2pcommand.commandType, customData); } public sendCommandPing(channel = this.channel): void { - const payload = buildVoidCommandPayload(channel); - this.sendCommand(CommandType.CMD_PING, payload, channel); + this.sendCommand({ + commandType: CommandType.CMD_PING, + channel: channel + }, InternalP2PCommandType.WithoutData); } public sendCommandDevicePing(channel = this.channel): void { - const payload = buildVoidCommandPayload(channel); - this.sendCommand(CommandType.CMD_GET_DEVICE_PING, payload, channel); + this.sendCommand({ + commandType: CommandType.CMD_GET_DEVICE_PING, + channel: channel + }, InternalP2PCommandType.WithoutData); } public sendCommandWithoutData(commandType: CommandType, channel = this.channel): void { - const payload = buildVoidCommandPayload(channel); - this.sendCommand(commandType, payload, channel); + this.sendCommand({ + commandType: commandType, + channel: channel + }, InternalP2PCommandType.WithoutData); } private sendQueuedMessage(): void { @@ -588,10 +593,10 @@ export class P2PClientProtocol extends TypedEmitter { let exists = false; let waitingAcknowledge = false; this.messageStates.forEach(stateMessage => { - if (stateMessage.commandType === queuedMessage.commandType && stateMessage.nestedCommandType === queuedMessage.nestedCommandType && !stateMessage.acknowledged) { + if (stateMessage.commandType === queuedMessage.p2pCommand.commandType && stateMessage.nestedCommandType === queuedMessage.nestedCommandType && !stateMessage.acknowledged) { exists = true; } - if (!stateMessage.acknowledged) { + if (!stateMessage.acknowledged || stateMessage.commandType === CommandType.CMD_GATEWAYINFO) { waitingAcknowledge = true; } }); @@ -610,17 +615,16 @@ export class P2PClientProtocol extends TypedEmitter { this.closeEnergySavingDevice(); } - private sendCommand(commandType: CommandType, payload: Buffer, channel: number, nestedCommandType?: CommandType, customData?: CustomData): void { + private sendCommand(p2pcommand: P2PCommand, p2pcommandType: InternalP2PCommandType, nestedCommandType?: CommandType, customData?: CustomData): void { const message: P2PQueueMessage = { - commandType: commandType, + p2pCommand: p2pcommand, nestedCommandType: nestedCommandType, - channel: channel, - payload: payload, timestamp: +new Date, - customData: customData + customData: customData, + p2pCommandType: p2pcommandType }; this.sendQueue.push(message); - if (message.commandType !== CommandType.CMD_PING && message.commandType !== CommandType.CMD_GET_DEVICE_PING) + if (p2pcommand.commandType !== CommandType.CMD_PING && p2pcommand.commandType !== CommandType.CMD_GET_DEVICE_PING) this._clearESDDisconnectTimeout(); this.sendQueuedMessage(); } @@ -632,7 +636,7 @@ export class P2PClientProtocol extends TypedEmitter { if (this.connectAddress) { sendMessage(this.socket, this.connectAddress, RequestMessageType.DATA, messageState.data).catch((err) => { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - Error`, error); + this.log.error(`resendNotAcknowledgedCommand - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, sequence: sequence }); }); this.resendNotAcknowledgedCommand(sequence); } @@ -644,13 +648,36 @@ export class P2PClientProtocol extends TypedEmitter { if (isP2PQueueMessage(message)) { const ageing = +new Date - message.timestamp; if (ageing <= this.MAX_COMMAND_QUEUE_TIMEOUT) { - const commandHeader = buildCommandHeader(this.seqNumber, message.commandType); - const data = Buffer.concat([commandHeader, message.payload]); + const commandHeader = buildCommandHeader(this.seqNumber, message.p2pCommand.commandType); + let payload: Buffer; + const channel = message.p2pCommand.channel !== undefined ? message.p2pCommand.channel : 0; + switch(message.p2pCommandType) { + case InternalP2PCommandType.WithInt: + payload = buildIntCommandPayload(this.encryption, this.p2pKey, this.rawStation.station_sn, this.rawStation.p2p_did, message.p2pCommand.commandType, message.p2pCommand.value as number, message.p2pCommand.strValue === undefined ? "" : message.p2pCommand.strValue, channel); + break; + case InternalP2PCommandType.WithIntString: + payload = buildIntStringCommandPayload(this.encryption, this.p2pKey, this.rawStation.station_sn, this.rawStation.p2p_did, message.p2pCommand.commandType, message.p2pCommand.value as number, message.p2pCommand.valueSub === undefined ? 0 : message.p2pCommand.valueSub, message.p2pCommand.strValue === undefined ? "" : message.p2pCommand.strValue , message.p2pCommand.strValueSub === undefined ? "" : message.p2pCommand.strValueSub, channel); + //TODO: Check if this "if" can be moved elsewhere + if (message.p2pCommand.commandType === CommandType.CMD_NAS_TEST) { + this.currentMessageState[P2PDataType.DATA].rtspStream[channel] = message.p2pCommand.value === 1 ? true : false; + } + break; + case InternalP2PCommandType.WithString: + payload = buildStringTypeCommandPayload(this.encryption, this.p2pKey, this.rawStation.station_sn, this.rawStation.p2p_did, message.p2pCommand.commandType, message.p2pCommand.strValue as string, message.p2pCommand.strValueSub as string, channel); + break; + case InternalP2PCommandType.WithStringPayload: + payload = buildCommandWithStringTypePayload(this.encryption, this.p2pKey, this.rawStation.station_sn, this.rawStation.p2p_did, message.p2pCommand.commandType, message.p2pCommand.value as string, channel); + break; + default: + payload = buildVoidCommandPayload(channel); + break; + } + const data = Buffer.concat([commandHeader, payload]); const messageState: P2PMessageState = { sequence: this.seqNumber, - commandType: message.commandType, + commandType: message.p2pCommand.commandType, nestedCommandType: message.nestedCommandType, - channel: message.channel, + channel: channel, data: data, retries: 0, acknowledged: false, @@ -659,13 +686,13 @@ export class P2PClientProtocol extends TypedEmitter { }; message = messageState; this.seqNumber = this._incrementSequence(this.seqNumber); - } else if (message.commandType === CommandType.CMD_PING || message.commandType === CommandType.CMD_GET_DEVICE_PING) { + } else if (message.p2pCommand.commandType === CommandType.CMD_PING || message.p2pCommand.commandType === CommandType.CMD_GET_DEVICE_PING) { return; } else { - this.log.warn(`Station ${this.rawStation.station_sn} - Command aged out from queue`, { commandType: message.commandType, nestedCommandType: message.nestedCommandType, channel: message.channel, ageing: ageing, maxAgeing: this.MAX_COMMAND_QUEUE_TIMEOUT }); + this.log.warn(`Command aged out from send queue for station ${this.rawStation.station_sn}`, { commandType: message.p2pCommand.commandType, nestedCommandType: message.nestedCommandType, channel: message.p2pCommand.channel, ageing: ageing, maxAgeing: this.MAX_COMMAND_QUEUE_TIMEOUT }); this.emit("command", { - command_type: message.nestedCommandType !== undefined ? message.nestedCommandType : message.commandType, - channel: message.channel, + command_type: message.nestedCommandType !== undefined ? message.nestedCommandType : message.p2pCommand.commandType, + channel: message.p2pCommand.channel, return_code: ErrorCode.ERROR_CONNECT_TIMEOUT, customData: message.customData } as CommandResult); @@ -682,7 +709,7 @@ export class P2PClientProtocol extends TypedEmitter { } message.retries++; } else { - this.log.error(`Station ${this.rawStation.station_sn} - Max retries ${this.messageStates.get(message.sequence)?.retries} - stop with error ${ErrorCode[message.returnCode]}`, { sequence: message.sequence, commandType: message.commandType, channel: message.channel, retries: message.retries, returnCode: message.returnCode }); + this.log.error(`Max p2p command send retries reached.`, { stationSN: this.rawStation.station_sn, sequence: message.sequence, commandType: message.commandType, channel: message.channel, retries: message.retries, returnCode: message.returnCode }); this.emit("command", { command_type: message.nestedCommandType !== undefined ? message.nestedCommandType : message.commandType, channel: message.channel, @@ -708,14 +735,14 @@ export class P2PClientProtocol extends TypedEmitter { this.resendNotAcknowledgedCommand(messageState.sequence); }, this.RESEND_NOT_ACKNOWLEDGED_COMMAND); - if (messageState.commandType !== CommandType.CMD_PING && this.energySavingDevice) { - this.energySavingDeviceP2PSeqMapping.set(this.energySavingDeviceP2PDataSeqNumber, message.sequence); - this.log.debug(`Station ${this.rawStation.station_sn} - Energy saving Device - Added sequence number mapping`, { commandType: message.commandType, seqNumber: message.sequence, energySavingDeviceP2PDataSeqNumber: this.energySavingDeviceP2PDataSeqNumber, energySavingDeviceP2PSeqMappingCount: this.energySavingDeviceP2PSeqMapping.size }); - this.energySavingDeviceP2PDataSeqNumber = this._incrementSequence(this.energySavingDeviceP2PDataSeqNumber); + if (messageState.commandType !== CommandType.CMD_PING && messageState.commandType !== CommandType.CMD_GATEWAYINFO) { + this.p2pSeqMapping.set(this.p2pDataSeqNumber, message.sequence); + this.log.debug(`Added sequence number mapping`, { stationSN: this.rawStation.station_sn, commandType: message.commandType, seqNumber: message.sequence, p2pDataSeqNumber: this.p2pDataSeqNumber, p2pSeqMappingCount: this.p2pSeqMapping.size }); + this.p2pDataSeqNumber = this._incrementSequence(this.p2pDataSeqNumber); } this.log.debug("Sending p2p command...", { station: this.rawStation.station_sn, sequence: messageState.sequence, commandType: messageState.commandType, channel: messageState.channel, retries: messageState.retries, messageStatesSize: this.messageStates.size }); - await this.sendMessage(`Send command to station ${this.rawStation.station_sn}`, this.connectAddress!, RequestMessageType.DATA, messageState.data); + await this.sendMessage(`Send p2p command`, this.connectAddress!, RequestMessageType.DATA, messageState.data); if (messageState.retries === 0) { if (messageState.commandType === CommandType.CMD_START_REALTIME_MEDIA || @@ -756,13 +783,13 @@ export class P2PClientProtocol extends TypedEmitter { this._clearLookupRetryTimeout(); const p2pDid = `${msg.slice(4, 12).toString("utf8").replace(/[\0]+$/g, "")}-${msg.slice(12, 16).readUInt32BE().toString().padStart(6, "0")}-${msg.slice(16, 24).toString("utf8").replace(/[\0]+$/g, "")}`; - this.log.debug(`Station ${this.rawStation.station_sn} - LOCAL_LOOKUP_RESP - Got response`, { ip: rinfo.address, port: rinfo.port, p2pDid: p2pDid }); + this.log.debug(`Received message - LOCAL_LOOKUP_RESP - Got response`, { stationSN: this.rawStation.station_sn, ip: rinfo.address, port: rinfo.port, p2pDid: p2pDid }); if (p2pDid === this.rawStation.p2p_did) { - this.log.debug(`Station ${this.rawStation.station_sn} - LOCAL_LOOKUP_RESP - Wanted device was found, connect to it`, { ip: rinfo.address, port: rinfo.port, p2pDid: p2pDid }); + this.log.debug(`Received message - LOCAL_LOOKUP_RESP - Wanted device was found, connect to it`, { stationSN: this.rawStation.station_sn, ip: rinfo.address, port: rinfo.port, p2pDid: p2pDid }); this._connect({ host: rinfo.address, port: rinfo.port }, p2pDid); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - LOCAL_LOOKUP_RESP - Unwanted device was found, don't connect to it`, { ip: rinfo.address, port: rinfo.port, p2pDid: p2pDid }); + this.log.debug(`Received message - LOCAL_LOOKUP_RESP - Unwanted device was found, don't connect to it`, { stationSN: this.rawStation.station_sn, ip: rinfo.address, port: rinfo.port, p2pDid: p2pDid }); } } } else if (hasHeader(msg, ResponseMessageType.LOOKUP_ADDR)) { @@ -770,10 +797,10 @@ export class P2PClientProtocol extends TypedEmitter { const port = msg.slice(6, 8).readUInt16LE(); const ip = `${msg[11]}.${msg[10]}.${msg[9]}.${msg[8]}`; - this.log.debug(`Station ${this.rawStation.station_sn} - LOOKUP_ADDR - Got response`, { remoteAddress: rinfo.address, remotePort: rinfo.port, response: { ip: ip, port: port }}); + this.log.debug(`Received message - LOOKUP_ADDR - Got response`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, response: { ip: ip, port: port } }); if (ip === "0.0.0.0") { - this.log.debug(`Station ${this.rawStation.station_sn} - LOOKUP_ADDR - Got invalid ip address 0.0.0.0, ignoring response...`); + this.log.debug(`Received message - LOOKUP_ADDR - Got invalid ip address 0.0.0.0, ignoring response...`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, response: { ip: ip, port: port } }); return; } @@ -784,20 +811,20 @@ export class P2PClientProtocol extends TypedEmitter { if (isPrivateIp(ip)) { this._clearLookupTimeout(); this._clearLookupRetryTimeout(); - this.log.debug(`Station ${this.rawStation.station_sn} - ONLY_LOCAL - Try to connect to ${ip}:${port}...`); + this.log.debug(`Trying to connect in ONLY_LOCAL mode...`, { stationSN: this.rawStation.station_sn, ip: ip, port: port }); this._connect({ host: ip, port: port }, this.rawStation.p2p_did); } } else if (this.connectionType === P2PConnectionType.QUICKEST) { this._clearLookupTimeout(); this._clearLookupRetryTimeout(); - this.log.debug(`Station ${this.rawStation.station_sn} - QUICKEST - Try to connect to ${ip}:${port}...`); + this.log.debug(`Trying to connect in QUICKEST mode...`, { stationSN: this.rawStation.station_sn, ip: ip, port: port }); this._connect({ host: ip, port: port }, this.rawStation.p2p_did); } } } else if (hasHeader(msg, ResponseMessageType.CAM_ID) || hasHeader(msg, ResponseMessageType.CAM_ID2)) { // Answer from the device to a CAM_CHECK message if (!this.connected) { - this.log.debug(`Station ${this.rawStation.station_sn} - CAM_ID - Connected to station ${this.rawStation.station_sn} on host ${rinfo.address} port ${rinfo.port}`); + this.log.debug(`Received message - CAM_ID - Connected to station ${this.rawStation.station_sn} on host ${rinfo.address} port ${rinfo.port}`); this._clearLookupRetryTimeout(); this._clearLookupTimeout(); this._clearConnectTimeout(); @@ -858,7 +885,7 @@ export class P2PClientProtocol extends TypedEmitter { }, this.RESEND_NOT_ACKNOWLEDGED_COMMAND); this.seqNumber = this._incrementSequence(this.seqNumber); - this.sendMessage(`Send smartsafe gateway command to station ${this.rawStation.station_sn}`, this.connectAddress!, RequestMessageType.DATA, data); + this.sendMessage(`Send smartsafe gateway command to station`, this.connectAddress!, RequestMessageType.DATA, data); const tmpSendQueue: Array = [ ...this.sendQueue ]; this.sendQueue = []; this.sendCommandPing(); @@ -868,13 +895,6 @@ export class P2PClientProtocol extends TypedEmitter { } else if (Device.isLockWifiR10(this.rawStation.device_type) || Device.isLockWifiR20(this.rawStation.device_type)) { const tmpSendQueue: Array = [ ...this.sendQueue ]; this.sendQueue = []; - /*const payload = buildVoidCommandPayload(255); - const data = Buffer.concat([buildCommandHeader(0, CommandType.CMD_GATEWAYINFO), payload]); - sendMessage(this.socket, this.connectAddress!, RequestMessageType.DATA, data).catch((err) => { - const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - Error`, error); - }); - this.sendCommand(CommandType.CMD_PING, payload, 255);*/ const payload = buildVoidCommandPayload(255); const data = Buffer.concat([buildCommandHeader(0, CommandType.CMD_GATEWAYINFO), payload.slice(0, payload.length - 2), buildCommandHeader(0, CommandType.CMD_PING).slice(2), payload]); const message: P2PMessageState = { @@ -891,7 +911,7 @@ export class P2PClientProtocol extends TypedEmitter { this.resendNotAcknowledgedCommand(message.sequence); }, this.RESEND_NOT_ACKNOWLEDGED_COMMAND); this.seqNumber = this._incrementSequence(this.seqNumber); - this.sendMessage(`Send lock wifi gateway command to station ${this.rawStation.station_sn}`, this.connectAddress!, RequestMessageType.DATA, data); + this.sendMessage(`Send lock wifi gateway command to station`, this.connectAddress!, RequestMessageType.DATA, data); try { const command = getLockV12P2PCommand( this.rawStation.station_sn, @@ -905,11 +925,18 @@ export class P2PClientProtocol extends TypedEmitter { this.sendCommandWithStringPayload(command.payload); } catch (err) { const error = ensureError(err); - this.log.error(`Send query status lock command to station ${this.rawStation.station_sn} - Error`, error); + this.log.error(`Send query status lock command to station - Error`, { error: getError(error), stationSN: this.rawStation.station_sn }); } tmpSendQueue.forEach(element => { this.sendQueue.push(element); }); + } else { + const tmpSendQueue: Array = [ ...this.sendQueue ]; + this.sendQueue = []; + this.sendCommandWithoutData(CommandType.CMD_GATEWAYINFO, Station.CHANNEL); + tmpSendQueue.forEach(element => { + this.sendQueue.push(element); + }); } this.sendQueuedMessage(); this.emit("connect", this.connectAddress); @@ -926,11 +953,11 @@ export class P2PClientProtocol extends TypedEmitter { return; } else if (hasHeader(msg, ResponseMessageType.PING)) { // Response with PONG to keep alive - this.sendMessage(`Send pong to station ${this.rawStation.station_sn}`, { host: rinfo.address, port: rinfo.port }, RequestMessageType.PONG); + this.sendMessage(`Send pong`, { host: rinfo.address, port: rinfo.port }, RequestMessageType.PONG); return; } else if (hasHeader(msg, ResponseMessageType.END)) { // Connection is closed by device - this.log.debug(`Station ${this.rawStation.station_sn} - END - received from host ${rinfo.address}:${rinfo.port}`); + this.log.debug(`Received message - END`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port }); this.onClose(); return; } else if (hasHeader(msg, ResponseMessageType.ACK)) { @@ -946,7 +973,7 @@ export class P2PClientProtocol extends TypedEmitter { const seqBuffer = msg.slice(idx, idx + 2); const ackedSeqNo = seqBuffer.readUIntBE(0, seqBuffer.length); // -> Message with seqNo was received at the station - this.log.debug(`Station ${this.rawStation.station_sn} - ACK ${P2PDataType[dataType]} - received from host ${rinfo.address}:${rinfo.port} for sequence ${ackedSeqNo}`); + this.log.debug(`Received message - ACK ${P2PDataType[dataType]} - sequence ${ackedSeqNo}`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, ackedSeqNo: ackedSeqNo, dataType: P2PDataType[dataType] }); if (dataType === P2PDataType.DATA) { const msg_state = this.messageStates.get(ackedSeqNo); if (msg_state && !msg_state.acknowledged) { @@ -957,24 +984,23 @@ export class P2PClientProtocol extends TypedEmitter { this.sendQueuedMessage(); } else { msg_state.acknowledged = true; - if (Device.isSmartSafe(this.rawStation.device_type) && msg_state.commandType === CommandType.CMD_GATEWAYINFO) { - //In this case no result data is received. + msg_state.timeout = setTimeout(() => { + //TODO: Retry command in these case? this.messageStates.delete(ackedSeqNo); - } else { - msg_state.timeout = setTimeout(() => { - //TODO: Retry command in these case? - this.log.warn(`Station ${this.rawStation.station_sn} - Result data for command not received`, { message: { sequence: msg_state.sequence, commandType: msg_state.commandType, nestedCommandType: msg_state.nestedCommandType, channel: msg_state.channel, acknowledged: msg_state.acknowledged, retries: msg_state.retries, returnCode: msg_state.returnCode, data: msg_state.data } }); - this.messageStates.delete(ackedSeqNo); + if (msg_state.commandType !== CommandType.CMD_GATEWAYINFO) { + this.log.warn(`Result data for command not received`, { stationSN: this.rawStation.station_sn, message: { sequence: msg_state.sequence, commandType: msg_state.commandType, nestedCommandType: msg_state.nestedCommandType, channel: msg_state.channel, acknowledged: msg_state.acknowledged, retries: msg_state.retries, returnCode: msg_state.returnCode, data: msg_state.data } }); this.emit("command", { command_type: msg_state.nestedCommandType !== undefined ? msg_state.nestedCommandType : msg_state.commandType, channel: msg_state.channel, return_code: ErrorCode.ERROR_COMMAND_TIMEOUT, customData: msg_state.customData } as CommandResult); - this.sendQueuedMessage(); - }, this.MAX_COMMAND_RESULT_WAIT); - this.messageStates.set(ackedSeqNo, msg_state); - } + } else { + this.log.debug(`Result data for command CMD_GATEWAYINFO not received`, { stationSN: this.rawStation.station_sn, message: { sequence: msg_state.sequence, commandType: msg_state.commandType, nestedCommandType: msg_state.nestedCommandType, channel: msg_state.channel, acknowledged: msg_state.acknowledged, retries: msg_state.retries, returnCode: msg_state.returnCode, data: msg_state.data } }); + } + this.sendQueuedMessage(); + }, this.MAX_COMMAND_RESULT_WAIT); + this.messageStates.set(ackedSeqNo, msg_state); this.sendQueuedMessage(); } } @@ -1000,7 +1026,7 @@ export class P2PClientProtocol extends TypedEmitter { }; this.sendAck({ host: rinfo.address, port: rinfo.port}, dataTypeBuffer, seqNo); - this.log.debug(`Station ${this.rawStation.station_sn} - DATA ${P2PDataType[message.type]} - received from host ${rinfo.address}:${rinfo.port} - Processing sequence ${message.seqNo}...`); + this.log.debug(`Received message - DATA ${P2PDataType[message.type]} - Processing sequence ${message.seqNo}...`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, dataType: P2PDataType[message.type], seqNo: message.seqNo }); if (message.seqNo === this.expectedSeqNo[dataType]) { // expected seq packet arrived @@ -1014,11 +1040,11 @@ export class P2PClientProtocol extends TypedEmitter { this.expectedSeqNo[dataType] = this._incrementSequence(this.expectedSeqNo[dataType]); this.parseDataMessage(message); - this.log.debug(`Station ${this.rawStation.station_sn} - DATA ${P2PDataType[message.type]} - Received expected sequence (expectedSeqNo: ${this.expectedSeqNo[dataType]} seqNo: ${message.seqNo} queuedData.size: ${this.currentMessageState[dataType].queuedData.size})`); + this.log.debug(`Received message - DATA ${P2PDataType[message.type]} - Received expected sequence`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, dataType: P2PDataType[message.type], seqNo: message.seqNo, expectedSeqNo: this.expectedSeqNo[dataType], queuedDataSize: this.currentMessageState[dataType].queuedData.size }); let queuedMessage = this.currentMessageState[dataType].queuedData.get(this.expectedSeqNo[dataType]); while (queuedMessage) { - this.log.debug(`Station ${this.rawStation.station_sn} - DATA ${P2PDataType[queuedMessage.type]} - Work off queued data (expectedSeqNo: ${this.expectedSeqNo[dataType]} seqNo: ${queuedMessage.seqNo} queuedData.size: ${this.currentMessageState[dataType].queuedData.size})`); + this.log.debug(`Received message - DATA ${P2PDataType[queuedMessage.type]} - Work off queued data`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, dataType: P2PDataType[message.type], seqNo: queuedMessage.seqNo, expectedSeqNo: this.expectedSeqNo[dataType], queuedDataSize: this.currentMessageState[dataType].queuedData.size }); this.expectedSeqNo[dataType] = this._incrementSequence(this.expectedSeqNo[dataType]); this.parseDataMessage(queuedMessage); this.currentMessageState[dataType].queuedData.delete(queuedMessage.seqNo); @@ -1029,7 +1055,7 @@ export class P2PClientProtocol extends TypedEmitter { // We have already seen this message, skip! // This can happen because the device is sending the message till it gets a ACK // which can take some time. - this.log.debug(`Station ${this.rawStation.station_sn} - DATA ${P2PDataType[message.type]} - Received already processed sequence (expectedSeqNo: ${this.expectedSeqNo[dataType]} seqNo: ${message.seqNo} queuedData.size: ${this.currentMessageState[dataType].queuedData.size})`); + this.log.debug(`Received message - DATA ${P2PDataType[message.type]} - Received already processed sequence`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, dataType: P2PDataType[message.type], seqNo: message.seqNo, expectedSeqNo: this.expectedSeqNo[dataType], queuedDataSize: this.currentMessageState[dataType].queuedData.size }); return; } else { if (!this.currentMessageState[dataType].waitForSeqNoTimeout) @@ -1040,9 +1066,9 @@ export class P2PClientProtocol extends TypedEmitter { if (!this.currentMessageState[dataType].queuedData.get(message.seqNo)) { this.currentMessageState[dataType].queuedData.set(message.seqNo, message); - this.log.debug(`Station ${this.rawStation.station_sn} - DATA ${P2PDataType[message.type]} - Received not expected sequence, added to the queue for future processing (expectedSeqNo: ${this.expectedSeqNo[dataType]} seqNo: ${message.seqNo} queuedData.size: ${this.currentMessageState[dataType].queuedData.size})`); + this.log.debug(`Received message - DATA ${P2PDataType[message.type]} - Received not expected sequence, added to the queue for future processing`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, dataType: P2PDataType[message.type], seqNo: message.seqNo, expectedSeqNo: this.expectedSeqNo[dataType], queuedDataSize: this.currentMessageState[dataType].queuedData.size }); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - DATA ${P2PDataType[message.type]} - Received not expected sequence, discarded since already present in queue for future processing (expectedSeqNo: ${this.expectedSeqNo[dataType]} seqNo: ${message.seqNo} queuedData.size: ${this.currentMessageState[dataType].queuedData.size})`); + this.log.debug(`Received message - DATA ${P2PDataType[message.type]} - Received not expected sequence, discarded since already present in queue for future processing`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, dataType: P2PDataType[message.type], seqNo: message.seqNo, expectedSeqNo: this.expectedSeqNo[dataType], queuedDataSize: this.currentMessageState[dataType].queuedData.size }); } } } @@ -1055,19 +1081,19 @@ export class P2PClientProtocol extends TypedEmitter { this._clearLookupTimeout(); this._clearLookupRetryTimeout(); - this.log.debug(`Station ${this.rawStation.station_sn} - LOOKUP_ADDR2 - Got response`, { remoteAddress: rinfo.address, remotePort: rinfo.port, response: { ip: ip, port: port, data: data.toString("hex") }}); - this.log.debug(`Station ${this.rawStation.station_sn} - CHECK_CAM2 - Connecting to host ${ip} on port ${port}...`); + this.log.debug(`Received message - LOOKUP_ADDR2 - Got response`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, response: { ip: ip, port: port, data: data.toString("hex") }}); + this.log.debug(`Connecting to host ${ip} on port ${port} (CHECK_CAM2)...`, { stationSN: this.rawStation.station_sn, ip: ip, port: port, data: data.toString("hex") }); for (let i = 0; i < 4; i++) this.sendCamCheck2({ host: ip, port: port }, data); this._startConnectTimeout(); - this.sendMessage(`Send UNKNOWN_70 to station ${this.rawStation.station_sn}`, { host: ip, port: port }, RequestMessageType.UNKNOWN_70); + this.sendMessage(`Send UNKNOWN_70`, { host: ip, port: port }, RequestMessageType.UNKNOWN_70); } } else if (hasHeader(msg, ResponseMessageType.UNKNOWN_71)) { if (!this.connected && !this.handshake_UNKNOWN71) { - this.log.debug(`Station ${this.rawStation.station_sn} - UNKNOWN_71 - Got response`, { remoteAddress: rinfo.address, remotePort: rinfo.port, response: { message: msg.toString("hex"), length: msg.length }}); - this.sendMessage(`Send UNKNOWN_71 to station ${this.rawStation.station_sn}`, { host: rinfo.address, port: rinfo.port }, RequestMessageType.UNKNOWN_71); + this.log.debug(`Received message - UNKNOWN_71 - Got response`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, response: { message: msg.toString("hex"), length: msg.length }}); + this.sendMessage(`Send UNKNOWN_71`, { host: rinfo.address, port: rinfo.port }, RequestMessageType.UNKNOWN_71); this.handshake_UNKNOWN71 = true; } } else if (hasHeader(msg, ResponseMessageType.UNKNOWN_73)) { @@ -1075,7 +1101,7 @@ export class P2PClientProtocol extends TypedEmitter { const port = msg.slice(8, 10).readUInt16BE(); const data = msg.slice(4, 8); - this.log.debug(`Station ${this.rawStation.station_sn} - UNKNOWN_73 - Got response`, { remoteAddress: rinfo.address, remotePort: rinfo.port, response: { port: port, data: data.toString("hex") }}); + this.log.debug(`Received message - UNKNOWN_73 - Got response`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, response: { port: port, data: data.toString("hex") }}); this.cloudLookup3({ host: rinfo.address, port: port }, data); } } else if (hasHeader(msg, ResponseMessageType.UNKNOWN_81) || hasHeader(msg, ResponseMessageType.UNKNOWN_83)) { @@ -1084,7 +1110,7 @@ export class P2PClientProtocol extends TypedEmitter { if (!this.connected) { const responseCode = msg.slice(4, 6).readUInt16LE(); - this.log.debug(`Station ${this.rawStation.station_sn} - LOOKUP_RESP - Got response`, { remoteAddress: rinfo.address, remotePort: rinfo.port, response: { responseCode: responseCode }}); + this.log.debug(`Received message - LOOKUP_RESP - Got response`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, response: { responseCode: responseCode }}); if (responseCode !== 0 && this.lookupTimeout !== undefined && this.lookupRetryTimeout === undefined) { this.lookupRetryTimeout = setTimeout(() => { @@ -1094,13 +1120,13 @@ export class P2PClientProtocol extends TypedEmitter { } } } else { - this.log.debug(`Station ${this.rawStation.station_sn} - received unknown message`, { remoteAddress: rinfo.address, remotePort: rinfo.port, response: { message: msg.toString("hex"), length: msg.length }}); + this.log.debug(`Received unknown message`, { stationSN: this.rawStation.station_sn, remoteAddress: rinfo.address, remotePort: rinfo.port, response: { message: msg.toString("hex"), length: msg.length }}); } } private parseDataMessage(message: P2PMessage): void { if ((message.type === P2PDataType.BINARY || message.type === P2PDataType.VIDEO) && !this.currentMessageState[message.type].p2pStreaming) { - this.log.debug(`Station ${this.rawStation.station_sn} - DATA ${P2PDataType[message.type]} - Stream not started ignore this data`, {seqNo: message.seqNo, header: this.currentMessageBuilder[message.type].header, bytesRead: this.currentMessageBuilder[message.type].bytesRead, bytesToRead: this.currentMessageBuilder[message.type].header.bytesToRead, messageSize: message.data.length }); + this.log.debug(`Parsing message - DATA ${P2PDataType[message.type]} - Stream not started ignore this data`, { stationSN: this.rawStation.station_sn, seqNo: message.seqNo, header: this.currentMessageBuilder[message.type].header, bytesRead: this.currentMessageBuilder[message.type].bytesRead, bytesToRead: this.currentMessageBuilder[message.type].header.bytesToRead, messageSize: message.data.length }); } else { if (this.currentMessageState[message.type].leftoverData.length > 0) { message.data = Buffer.concat([this.currentMessageState[message.type].leftoverData, message.data]); @@ -1171,7 +1197,7 @@ export class P2PClientProtocol extends TypedEmitter { data = Buffer.from([]); } } - this.log.debug(`Station ${this.rawStation.station_sn} - Received data`, { seqNo: message.seqNo, header: this.currentMessageBuilder[message.type].header, bytesRead: this.currentMessageBuilder[message.type].bytesRead, bytesToRead: this.currentMessageBuilder[message.type].header.bytesToRead, firstPartMessage: firstPartMessage, messageSize: message.data.length }); + this.log.debug(`Parsing message - DATA ${P2PDataType[message.type]} - Received data`, { stationSN: this.rawStation.station_sn, seqNo: message.seqNo, header: this.currentMessageBuilder[message.type].header, bytesRead: this.currentMessageBuilder[message.type].bytesRead, bytesToRead: this.currentMessageBuilder[message.type].header.bytesToRead, firstPartMessage: firstPartMessage, messageSize: message.data.length }); if (this.currentMessageBuilder[message.type].bytesRead === this.currentMessageBuilder[message.type].header.bytesToRead) { const completeMessage = sortP2PMessageParts(this.currentMessageBuilder[message.type].messages); const data_message: P2PDataMessage = { @@ -1183,7 +1209,7 @@ export class P2PClientProtocol extends TypedEmitter { this.handleData(data_message); this.initializeMessageBuilder(message.type); if (data.length > 0 && message.type === P2PDataType.DATA) { - this.log.debug(`Station ${this.rawStation.station_sn} - Parsed data`, { seqNo: message.seqNo, data_message: data_message, datalen: data.length, data: data.toString("hex"), offsetDataSeqNumber: this.offsetDataSeqNumber, seqNumber: this.seqNumber, energySavingDeviceP2PDataSeqNumber: this.energySavingDeviceP2PDataSeqNumber }); + this.log.debug(`Parsing message - DATA ${P2PDataType[message.type]} - Parsed data`, { stationSN: this.rawStation.station_sn, seqNo: message.seqNo, data_message: data_message, datalen: data.length, data: data.toString("hex"), offsetDataSeqNumber: this.offsetDataSeqNumber, seqNumber: this.seqNumber, p2pDataSeqNumber: this.p2pDataSeqNumber }); this.offsetDataSeqNumber++; } } @@ -1207,40 +1233,44 @@ export class P2PClientProtocol extends TypedEmitter { } const error_codeStr = ErrorCode[return_code]; - this.log.debug(`Station ${this.rawStation.station_sn} - Received data`, { commandIdName: commandStr, commandId: message.commandId, resultCodeName: error_codeStr, resultCode: return_code, message: return_msg, data: message.data.toString("hex"), seqNumber: this.seqNumber, energySavingDeviceP2PDataSeqNumber: this.energySavingDeviceP2PDataSeqNumber, offsetDataSeqNumber: this.offsetDataSeqNumber }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Received data`, { stationSN: this.rawStation.station_sn, commandIdName: commandStr, commandId: message.commandId, resultCodeName: error_codeStr, resultCode: return_code, message: return_msg, data: message.data.toString("hex"), seqNumber: this.seqNumber, p2pDataSeqNumber: this.p2pDataSeqNumber, offsetDataSeqNumber: this.offsetDataSeqNumber }); let msg_state = this.messageStates.get(message.seqNo); - if (this.energySavingDevice) { - const goodSeqNumber = this.energySavingDeviceP2PSeqMapping.get(message.seqNo); + if (message.commandId !== CommandType.CMD_GATEWAYINFO) { + const goodSeqNumber = this.p2pSeqMapping.get(message.seqNo); if (goodSeqNumber) { - this.energySavingDeviceP2PSeqMapping.delete(message.seqNo); + this.p2pSeqMapping.delete(message.seqNo); msg_state = this.messageStates.get(goodSeqNumber); - this.log.debug(`Station ${this.rawStation.station_sn} - Energy saving Device - Result data received - Detecting correct sequence number`, { commandIdName: commandStr, commandId: message.commandId, seqNumber: message.seqNo, newSeqNumber: goodSeqNumber, energySavingDeviceP2PSeqMappingCount: this.energySavingDeviceP2PSeqMapping.size }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Result data received - Detecting correct sequence number`, { stationSN: this.rawStation.station_sn, commandIdName: commandStr, commandId: message.commandId, seqNumber: message.seqNo, newSeqNumber: goodSeqNumber, p2pSeqMappingCount: this.p2pSeqMapping.size }); message.seqNo = goodSeqNumber; } + } else { + this.p2pSeqMapping.delete(message.seqNo); + this.p2pDataSeqNumber--; } if (msg_state) { if (msg_state.commandType === message.commandId) { this._clearTimeout(msg_state.timeout); const command_type = msg_state.nestedCommandType !== undefined ? msg_state.nestedCommandType : msg_state.commandType; - this.log.debug(`Station ${this.rawStation.station_sn} - Result data for command received`, { message: { sequence: msg_state.sequence, commandType: msg_state.commandType, nestedCommandType: msg_state.nestedCommandType, channel: msg_state.channel, acknowledged: msg_state.acknowledged, retries: msg_state.retries, returnCode: msg_state.returnCode, data: msg_state.data, customData: msg_state.customData }, resultCodeName: error_codeStr, resultCode: return_code }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Result data for command received`, { stationSN: this.rawStation.station_sn, message: { sequence: msg_state.sequence, commandType: msg_state.commandType, nestedCommandType: msg_state.nestedCommandType, channel: msg_state.channel, acknowledged: msg_state.acknowledged, retries: msg_state.retries, returnCode: msg_state.returnCode, data: msg_state.data, customData: msg_state.customData }, resultCodeName: error_codeStr, resultCode: return_code }); if (return_code === ErrorCode.ERROR_FAILED_TO_REQUEST) { msg_state.returnCode = return_code; this._sendCommand(msg_state); } else { - this.emit("command", { - command_type: command_type, - channel: msg_state.channel, - return_code: return_code, - customData: msg_state.customData - } as CommandResult); + if (command_type !== CommandType.CMD_GATEWAYINFO) + this.emit("command", { + command_type: command_type, + channel: msg_state.channel, + return_code: return_code, + customData: msg_state.customData + } as CommandResult); this.messageStates.delete(message.seqNo); if (command_type === CommandType.CMD_SMARTSAFE_SETTINGS || command_type === CommandType.CMD_SET_PAYLOAD_LOCKV12) { this.lastCustomData = msg_state.customData; this.lastChannel = msg_state.channel; this.secondaryCommandTimeout = setTimeout(() => { - this.log.warn(`Station ${this.rawStation.station_sn} - Result data for secondary command not received`, { message: { sequence: msg_state!.sequence, commandType: msg_state!.commandType, nestedCommandType: msg_state!.nestedCommandType, channel: msg_state!.channel, acknowledged: msg_state!.acknowledged, retries: msg_state!.retries, returnCode: msg_state!.returnCode, data: msg_state!.data, customData: msg_state!.customData } }); + this.log.warn(`Handle DATA ${P2PDataType[message.type]} - Result data for secondary command not received`, { stationSN: this.rawStation.station_sn, message: { sequence: msg_state!.sequence, commandType: msg_state!.commandType, nestedCommandType: msg_state!.nestedCommandType, channel: msg_state!.channel, acknowledged: msg_state!.acknowledged, retries: msg_state!.retries, returnCode: msg_state!.returnCode, data: msg_state!.data, customData: msg_state!.customData } }); this.secondaryCommandTimeout = undefined; this.emit("secondary command", { command_type: msg_state!.nestedCommandType !== undefined ? msg_state!.nestedCommandType : msg_state!.commandType, @@ -1282,19 +1312,19 @@ export class P2PClientProtocol extends TypedEmitter { } } else { this.messageStates.delete(message.seqNo); - this.log.debug(`Station ${this.rawStation.station_sn} - dataType: ${P2PDataType[message.dataType]} commandtype and sequencenumber different!`, { msg_sequence: msg_state.sequence, msg_channel: msg_state.channel, msg_commandType: msg_state.commandType, message: message, seqNumber: this.seqNumber, energySavingDeviceP2PDataSeqNumber: this.energySavingDeviceP2PDataSeqNumber, offsetDataSeqNumber: this.offsetDataSeqNumber }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Expected different command type for received sequencenumber!`, { stationSN: this.rawStation.station_sn, msg_sequence: msg_state.sequence, msg_channel: msg_state.channel, msg_commandType: msg_state.commandType, seqNumber: this.seqNumber, p2pDataSeqNumber: this.p2pDataSeqNumber, offsetDataSeqNumber: this.offsetDataSeqNumber, message: { seqNo: message.seqNo, commandType: CommandType[message.commandId], channel: message.channel, signCode: message.signCode, data: message.data.toString("hex") } }); this.log.warn(`P2P protocol instability detected for station ${this.rawStation.station_sn}. Please reinitialise the connection to solve the problem!`); } - } else if (message.commandId !== CommandType.CMD_PING && message.commandId !== CommandType.CMD_GET_DEVICE_PING) { - this.log.debug(`Station ${this.rawStation.station_sn} - dataType: ${P2PDataType[message.dataType]} commandId: ${message.commandId} sequence: ${message.seqNo} not present!`, { seqNumber: this.seqNumber, energySavingDeviceP2PDataSeqNumber: this.energySavingDeviceP2PDataSeqNumber, offsetDataSeqNumber: this.offsetDataSeqNumber }); + } else if (message.commandId !== CommandType.CMD_PING && message.commandId !== CommandType.CMD_GET_DEVICE_PING && message.commandId !== CommandType.CMD_GATEWAYINFO) { + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Received unexpected data!`, { stationSN: this.rawStation.station_sn, seqNumber: this.seqNumber, p2pDataSeqNumber: this.p2pDataSeqNumber, offsetDataSeqNumber: this.offsetDataSeqNumber, message: { seqNo: message.seqNo, commandType: CommandType[message.commandId], channel: message.channel, signCode: message.signCode, data: message.data.toString("hex") } }); } } else { - this.log.debug(`Station ${this.rawStation.station_sn} - Unsupported response`, { dataType: P2PDataType[message.dataType], commandIdName: commandStr, commandId: message.commandId, message: message.data.toString("hex") }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Unsupported response`, { stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, commandType: message.commandId, channel: message.channel, signCode: message.signCode, data: message.data.toString("hex") } }); } } else if (message.dataType === P2PDataType.VIDEO || message.dataType === P2PDataType.BINARY) { this.handleDataBinaryAndVideo(message); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - Not implemented data type`, { seqNo: message.seqNo, dataType: message.dataType, commandId: message.commandId, message: message.data.toString("hex") }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Not implemented data type`, { stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, commandType: message.commandId, channel: message.channel, signCode: message.signCode, data: message.data.toString("hex") } }); } } @@ -1358,16 +1388,16 @@ export class P2PClientProtocol extends TypedEmitter { if (rsaKey) { try { videoMetaData.aesKey = rsaKey.decrypt(key).toString("hex"); - this.log.debug(`Station ${this.rawStation.station_sn} - Decrypted AES key: ${videoMetaData.aesKey}`); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Decrypted AES key`, { stationSN: this.rawStation.station_sn, key: videoMetaData.aesKey }); } catch (err) { const error = ensureError(err); - this.log.warn(`Station ${this.rawStation.station_sn} - AES key could not be decrypted! The entire stream is discarded. - Error`, error); + this.log.warn(`Error: AES key could not be decrypted! The entire stream is discarded.`, { error: getError(error), stationSN: this.rawStation.station_sn, key: key.toString("hex") }); this.currentMessageState[message.dataType].invalidStream = true; this.emit("livestream error", message.channel, new LivestreamError("Station AES key could not be decrypted! The entire stream is discarded.", { context: { station: this.rawStation.station_sn } })); return; } } else { - this.log.warn(`Station ${this.rawStation.station_sn} - Private RSA key is missing! Stream could not be decrypted. The entire stream is discarded.`); + this.log.warn(`Private RSA key is missing! Stream could not be decrypted. The entire stream for station ${this.rawStation.station_sn} is discarded.`); this.currentMessageState[message.dataType].invalidStream = true; this.emit("livestream error", message.channel, new LivestreamError("Station Private RSA key is missing! Stream could not be decrypted. The entire stream is discarded.", { context: { station: this.rawStation.station_sn } })); return; @@ -1384,7 +1414,7 @@ export class P2PClientProtocol extends TypedEmitter { video_data = message.data.slice(payloadStart, payloadStart + videoMetaData.videoDataLength); } - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME`, { dataSize: message.data.length, metadata: videoMetaData, videoDataSize: video_data.length }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME`, { stationSN: this.rawStation.station_sn, dataSize: message.data.length, metadata: videoMetaData, videoDataSize: video_data.length }); this.currentMessageState[message.dataType].p2pStreamMetadata.videoFPS = videoMetaData.videoFPS; this.currentMessageState[message.dataType].p2pStreamMetadata.videoHeight = videoMetaData.videoHeight; @@ -1396,21 +1426,21 @@ export class P2PClientProtocol extends TypedEmitter { this.rawStation.station_sn.startsWith("T8130") || this.rawStation.station_sn.startsWith("T8131") || this.rawStation.station_sn.startsWith("T8420") || this.rawStation.station_sn.startsWith("T8440") || this.rawStation.station_sn.startsWith("T8441") || this.rawStation.station_sn.startsWith("T8442") || checkT8420(this.rawStation.station_sn)) { this.currentMessageState[message.dataType].p2pStreamMetadata.videoCodec = videoMetaData.streamType === 1 ? VideoCodec.H264 : videoMetaData.streamType === 2 ? VideoCodec.H265 : getVideoCodec(video_data); - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME - Video codec information received from packet`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME - Video codec information received from packet`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); } else if (this.isIFrame(video_data, isKeyFrame)) { this.currentMessageState[message.dataType].p2pStreamMetadata.videoCodec = getVideoCodec(video_data); - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME - Video codec extracted from video data`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME - Video codec extracted from video data`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); } else { this.currentMessageState[message.dataType].p2pStreamMetadata.videoCodec = getVideoCodec(video_data); if (this.currentMessageState[message.dataType].p2pStreamMetadata.videoCodec === VideoCodec.UNKNOWN) { this.currentMessageState[message.dataType].p2pStreamMetadata.videoCodec = videoMetaData.streamType === 1 ? VideoCodec.H264 : videoMetaData.streamType === 2 ? VideoCodec.H265 : VideoCodec.UNKNOWN; if (this.currentMessageState[message.dataType].p2pStreamMetadata.videoCodec === VideoCodec.UNKNOWN) { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME - Unknown video codec`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME - Unknown video codec`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME - Fallback, using video codec information received from packet`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME - Fallback, using video codec information received from packet`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); } } else { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME - Fallback, video codec extracted from video data`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME - Fallback, video codec extracted from video data`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, metadata: videoMetaData }); } } this.currentMessageState[message.dataType].p2pStreamFirstVideoDataReceived = true; @@ -1433,7 +1463,7 @@ export class P2PClientProtocol extends TypedEmitter { if (message.dataType === P2PDataType.VIDEO) { if (findStartCode(video_data)) { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME: startcode found`, { isKeyFrame: isKeyFrame, preFrameVideoDataLength: this.currentMessageState[message.dataType].preFrameVideoData.length }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME: startcode found`, { stationSN: this.rawStation.station_sn, isKeyFrame: isKeyFrame, preFrameVideoDataLength: this.currentMessageState[message.dataType].preFrameVideoData.length }); if (!this.currentMessageState[message.dataType].receivedFirstIFrame) this.currentMessageState[message.dataType].receivedFirstIFrame = this.isIFrame(video_data, isKeyFrame); @@ -1446,10 +1476,10 @@ export class P2PClientProtocol extends TypedEmitter { } this.currentMessageState[message.dataType].preFrameVideoData = Buffer.from(video_data); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME: Skipping because first frame is not an I frame.`); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME: Skipping because first frame is not an I frame.`, { stationSN: this.rawStation.station_sn }); } } else { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_VIDEO_FRAME: No startcode found`, {isKeyFrame: isKeyFrame, preFrameVideoDataLength: this.currentMessageState[message.dataType].preFrameVideoData.length }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_VIDEO_FRAME: No startcode found`, { stationSN: this.rawStation.station_sn, isKeyFrame: isKeyFrame, preFrameVideoDataLength: this.currentMessageState[message.dataType].preFrameVideoData.length }); if (this.currentMessageState[message.dataType].preFrameVideoData.length > 0) { this.currentMessageState[message.dataType].preFrameVideoData = Buffer.concat([this.currentMessageState[message.dataType].preFrameVideoData, video_data]); } @@ -1474,7 +1504,7 @@ export class P2PClientProtocol extends TypedEmitter { audioMetaData.audioTimestamp = message.data.slice(8, 14).readUIntLE(0, 6); const audio_data = Buffer.from(message.data.slice(16)); - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_AUDIO_FRAME`, { dataSize: message.data.length, metadata: audioMetaData, audioDataSize: audio_data.length }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_AUDIO_FRAME`, { stationSN: this.rawStation.station_sn, dataSize: message.data.length, metadata: audioMetaData, audioDataSize: audio_data.length }); if (this.currentMessageState[message.dataType].waitForAudioData !== undefined) { clearTimeout(this.currentMessageState[message.dataType].waitForAudioData!); @@ -1492,112 +1522,123 @@ export class P2PClientProtocol extends TypedEmitter { this.currentMessageState[message.dataType].audioStream?.push(audio_data); break; default: - this.log.debug(`Station ${this.rawStation.station_sn} - Not implemented message`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, data: message.data.toString("hex") }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Not implemented message`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, data: message.data.toString("hex") }); break; } } else { - this.log.debug(`Station ${this.rawStation.station_sn} - Invalid stream data, dropping complete stream`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, data: message.data.toString("hex") }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Invalid stream data, dropping complete stream`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, data: message.data.toString("hex") }); } } private handleDataControl(message: P2PDataMessage): void { try { + let data: Buffer = message.data; + if (message.signCode > 0) { + //TODO: Set key based on encryption type 1 vs 2 + if (EncryptionType.LEVEL_1) { + data = decryptP2PData(message.data, Buffer.from(getP2PCommandEncryptionKey(this.rawStation.station_sn, this.rawStation.p2p_did))); + } else if (EncryptionType.LEVEL_2) { + //TODO: Implement decryption of encryption type level 2 + } + } switch(message.commandId) { case CommandType.CMD_GET_ALARM_MODE: - this.log.debug(`Station ${this.rawStation.station_sn} - Alarm mode changed to: ${AlarmMode[message.data.readUIntBE(0, 1)]}`); - this.emit("alarm mode", message.data.readUIntBE(0, 1) as AlarmMode); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Alarm mode changed to: ${AlarmMode[data.readUIntBE(0, 1)]}`, { stationSN: this.rawStation.station_sn, }); + this.emit("alarm mode", data.readUIntBE(0, 1) as AlarmMode); break; case CommandType.CMD_CAMERA_INFO: try { - const data = message.data.toString("utf8"); - this.log.debug(`Station ${this.rawStation.station_sn} - Camera info`, { cameraInfo: data }); - this.emit("camera info", parseJSON(data, this.log) as CmdCameraInfoResponse); + const cameraData = getNullTerminatedString(data, "utf8"); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Camera info`, { stationSN: this.rawStation.station_sn, cameraInfo: cameraData }); + this.emit("camera info", parseJSON(cameraData, this.log) as CmdCameraInfoResponse); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - Camera info - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - Camera info - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_CONVERT_MP4_OK: - const totalBytes = message.data.slice(1).readUInt32LE(); - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_CONVERT_MP4_OK`, { channel: message.channel, totalBytes: totalBytes }); + const totalBytes = data.slice(1).readUInt32LE(); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_CONVERT_MP4_OK`, { stationSN: this.rawStation.station_sn, channel: message.channel, totalBytes: totalBytes }); this.downloadTotalBytes = totalBytes; this.currentMessageState[P2PDataType.BINARY].p2pStreaming = true; this.currentMessageState[P2PDataType.BINARY].p2pStreamChannel = message.channel; break; case CommandType.CMD_WIFI_CONFIG: - const rssi = message.data.readInt32LE(); - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_WIFI_CONFIG`, { channel: message.channel, rssi: rssi }); + const rssi = data.readInt32LE(); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_WIFI_CONFIG`, { stationSN: this.rawStation.station_sn, channel: message.channel, rssi: rssi }); this.emit("wifi rssi", message.channel, rssi); break; case CommandType.CMD_DOWNLOAD_FINISH: - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_DOWNLOAD_FINISH`, { channel: message.channel }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_DOWNLOAD_FINISH`, { stationSN: this.rawStation.station_sn, channel: message.channel }); this.endStream(P2PDataType.BINARY); break; case CommandType.CMD_DOORBELL_NOTIFY_PAYLOAD: try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_DOORBELL_NOTIFY_PAYLOAD`, { payload: message.data.toString() }); + const str = getNullTerminatedString(data, "utf8"); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_DOORBELL_NOTIFY_PAYLOAD`, { stationSN: this.rawStation.station_sn, payload: str }); //TODO: Finish implementation, emit an event... //VDBStreamInfo (1005) and VoltageEvent (1015) - //this.emit("", parseJSON(message.data.toString(), this.log) as xy); + //this.emit("", parseJSON(str, this.log) as xy); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_DOORBELL_NOTIFY_PAYLOAD - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_DOORBELL_NOTIFY_PAYLOAD - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_NAS_SWITCH: try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NAS_SWITCH`, { payload: message.data.toString() }); - this.emit("rtsp url", message.channel, message.data.toString("utf8", 0, message.data.indexOf("\0", 0, "utf8"))); + const str = getNullTerminatedString(data, "utf8"); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NAS_SWITCH`, { stationSN: this.rawStation.station_sn, payload: str }); + this.emit("rtsp url", message.channel, str); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_NAS_SWITCH - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_NAS_SWITCH - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.SUB1G_REP_UNPLUG_POWER_LINE: try { - this.log.debug(`Station ${this.rawStation.station_sn} - SUB1G_REP_UNPLUG_POWER_LINE`, { payload: message.data.toString() }); - const chargeType = message.data.slice(0, 4).readUInt32LE() as ChargingType; - const batteryLevel = message.data.slice(4, 8).readUInt32LE(); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - SUB1G_REP_UNPLUG_POWER_LINE`, { stationSN: this.rawStation.station_sn, payload: data.toString() }); + const chargeType = data.slice(0, 4).readUInt32LE() as ChargingType; + const batteryLevel = data.slice(4, 8).readUInt32LE(); this.emit("charging state", message.channel, chargeType, batteryLevel); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - SUB1G_REP_UNPLUG_POWER_LINE - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - SUB1G_REP_UNPLUG_POWER_LINE - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.SUB1G_REP_RUNTIME_STATE: try { - this.log.debug(`Station ${this.rawStation.station_sn} - SUB1G_REP_RUNTIME_STATE`, { payload: message.data.toString() }); - const batteryLevel = message.data.slice(0, 4).readUInt32LE(); - const temperature = message.data.slice(4, 8).readUInt32LE(); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - SUB1G_REP_RUNTIME_STATE`, { stationSN: this.rawStation.station_sn, payload: data.toString() }); + const batteryLevel = data.slice(0, 4).readUInt32LE(); + const temperature = data.slice(4, 8).readUInt32LE(); this.emit("runtime state", message.channel, batteryLevel, temperature); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - SUB1G_REP_RUNTIME_STATE - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - SUB1G_REP_RUNTIME_STATE - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_SET_FLOODLIGHT_MANUAL_SWITCH: try { - const enabled = message.data.readUIntBE(0, 1) === 1 ? true : false; - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_SET_FLOODLIGHT_MANUAL_SWITCH`, { enabled: enabled, payload: message.data.toString() }); + const enabled = data.readUIntBE(0, 1) === 1 ? true : false; + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_SET_FLOODLIGHT_MANUAL_SWITCH`, { stationSN: this.rawStation.station_sn, enabled: enabled, payload: data.toString() }); this.emit("floodlight manual switch", message.channel, enabled); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_SET_FLOODLIGHT_MANUAL_SWITCH - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_SET_FLOODLIGHT_MANUAL_SWITCH - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_GET_DEVICE_PING: try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_GET_DEVICE_PING`, { payload: message.data.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_GET_DEVICE_PING`, { stationSN: this.rawStation.station_sn, payload: data.toString() }); this.sendCommandDevicePing(message.channel); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_GET_DEVICE_PING - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_GET_DEVICE_PING - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_NOTIFY_PAYLOAD: try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD`, { payload: message.data.toString() }); - const json: CmdNotifyPayload = parseJSON(message.data.toString("utf-8"), this.log) as CmdNotifyPayload; + this.log.debug(`Station Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD`, { stationSN: this.rawStation.station_sn, payload: data.toString() }); + const json: CmdNotifyPayload = parseJSON(getNullTerminatedString(data, "utf8"), this.log) as CmdNotifyPayload; if (json !== undefined) { if (this.rawStation.station_sn.startsWith("T8520")) { //TODO: Implement notification payload or T8520 @@ -1607,7 +1648,7 @@ export class P2PClientProtocol extends TypedEmitter { const aesKey = this.getLockAESKey(json.cmd); if (aesKey !== undefined) { const decryptedPayload = decryptPayloadData(Buffer.from(json.payload as string, "base64"), Buffer.from(aesKey, "hex"), Buffer.from(getLockVectorBytes(this.rawStation.station_sn), "hex")).toString() - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD Lock - Received`, { commandIdName: CommandType[json.cmd], commandId: json.cmd, decryptedPayload: decryptedPayload, aesKey: aesKey }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD Lock - Received`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd, decryptedPayload: decryptedPayload, aesKey: aesKey }); switch (json.cmd) { case CommandType.P2P_ADD_PW: // decryptedPayload: {"code":0,"passwordId":"002C"} @@ -1620,7 +1661,7 @@ export class P2PClientProtocol extends TypedEmitter { this.emit("parameter", message.channel, CommandType.CMD_SMARTLOCK_QUERY_BATTERY_LEVEL, payload.slBattery); this.emit("parameter", message.channel, CommandType.CMD_SMARTLOCK_QUERY_STATUS, payload.slState); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD - Not implemented`, { commandIdName: CommandType[json.cmd], commandId: json.cmd, message: message.data.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD - Not implemented`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd, message: data.toString() }); } } else if (json.cmd === CommandType.CMD_DOORLOCK_P2P_SEQ) { const payload: ESLStationP2PThroughData = json.payload as ESLStationP2PThroughData; @@ -1628,11 +1669,11 @@ export class P2PClientProtocol extends TypedEmitter { case 0: if (payload.seq_num !== undefined) { this.lockSeqNumber = payload.seq_num; - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD - Lock sequence number`, { lockSeqNumber: this.lockSeqNumber }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD - Lock sequence number`, { stationSN: this.rawStation.station_sn, lockSeqNumber: this.lockSeqNumber }); } break; default: - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD - Not implemented`, { message: message.data.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD - Not implemented`, { stationSN: this.rawStation.station_sn, message: data.toString() }); break; } } else if (json.cmd === CommandType.CMD_DOORLOCK_DATA_PASS_THROUGH) { @@ -1643,7 +1684,7 @@ export class P2PClientProtocol extends TypedEmitter { const key = generateBasicLockAESKey(this.deviceSNs[message.channel].adminUserId, this.rawStation.station_sn); const iv = getLockVectorBytes(this.rawStation.station_sn); - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_DOORLOCK_DATA_PASS_THROUGH`, { commandIdName: CommandType[json.cmd], commandId: json.cmd, key: key, iv: iv, decoded: decoded.toString("hex") }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_DOORLOCK_DATA_PASS_THROUGH`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd, key: key, iv: iv, decoded: decoded.toString("hex") }); payload.lock_payload = decryptLockAESData(key, iv, decoded).toString("hex"); @@ -1654,7 +1695,7 @@ export class P2PClientProtocol extends TypedEmitter { this.emit("parameter", message.channel, CommandType.CMD_DOORLOCK_GET_STATE, notifyBuffer.slice(6, 7).readInt8().toString()); break; default: - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_DOORLOCK_DATA_PASS_THROUGH - Not implemented`, { message: message.data.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_DOORLOCK_DATA_PASS_THROUGH - Not implemented`, { stationSN: this.rawStation.station_sn, message: data.toString() }); break; } } @@ -1665,7 +1706,7 @@ export class P2PClientProtocol extends TypedEmitter { const fac = new BleCommandFactory(payload.lock_payload); if (fac.getCommandCode() !== ESLBleCommand.NOTIFY) { const aesKey = this.getLockAESKey(fac.getCommandCode()!); - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD Lock V12 - Received`, { fac: fac.toString(), aesKey: aesKey }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD Lock V12 - Received`, { stationSN: this.rawStation.station_sn, fac: fac.toString(), aesKey: aesKey }); let data = fac.getData()!; if (aesKey !== undefined) { data = decryptPayloadData(data, Buffer.from(aesKey, "hex"), Buffer.from(getLockVectorBytes(this.rawStation.station_sn), "hex")) @@ -1681,17 +1722,17 @@ export class P2PClientProtocol extends TypedEmitter { this.emit("secondary command", result); } - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD Lock V12 return code: ${returnCode}`, { commandIdName: CommandType[json.cmd], commandId: json.cmd, decoded: data, bleCommandCode: ESLBleCommand[fac.getCommandCode()!], returnCode: returnCode, channel: this.lastChannel, customData: this.lastCustomData }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD Lock V12 return code: ${returnCode}`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd, decoded: data, bleCommandCode: ESLBleCommand[fac.getCommandCode()!], returnCode: returnCode, channel: this.lastChannel, customData: this.lastCustomData }); this._clearSecondaryCommandTimeout(); this.sendQueuedMessage(); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD Lock V12 - Received notify`, { fac: fac.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD Lock V12 - Received notify`, { stationSN: this.rawStation.station_sn, fac: fac.toString() }); } } else { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD Lock V12 - Unexpected response`, { commandIdName: CommandType[json.cmd], commandId: json.cmd, message: message.data.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD Lock V12 - Unexpected response`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd, message: data.toString() }); } } else if (Device.isSmartSafe(this.rawStation.device_type)) { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD SmartSafe`, { commandIdName: CommandType[json.cmd], commandId: json.cmd }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD SmartSafe`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd }); switch (json.cmd) { case CommandType.CMD_SMARTSAFE_SETTINGS: { @@ -1709,10 +1750,10 @@ export class P2PClientProtocol extends TypedEmitter { this.emit("secondary command", result); } - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD SmartSafe return code: ${data.data.readInt8(0)}`, { commandIdName: CommandType[json.cmd], commandId: json.cmd, decoded: data, commandCode: SmartSafeCommandCode[data.commandCode], returnCode: returnCode, channel: this.lastChannel, customData: this.lastCustomData }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD SmartSafe return code: ${data.data.readInt8(0)}`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd, decoded: data, commandCode: SmartSafeCommandCode[data.commandCode], returnCode: returnCode, channel: this.lastChannel, customData: this.lastCustomData }); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD SmartSafe Error`, { commandIdName: CommandType[json.cmd], commandId: json.cmd, channel: this.lastChannel, customData: this.lastCustomData, payload: payload, error: error }); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD SmartSafe Error`, { error: getError(error), stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd, channel: this.lastChannel, customData: this.lastCustomData, payload: payload }); } this._clearSecondaryCommandTimeout(); this.sendQueuedMessage(); @@ -1726,7 +1767,7 @@ export class P2PClientProtocol extends TypedEmitter { { const eventValues = payload.event_value as SmartSafeEventValueDetail; - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD SmartSafe Status update - LOCK_STATUS`, { eventValues: eventValues }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD SmartSafe Status update - LOCK_STATUS`, { stationSN: this.rawStation.station_sn, eventValues: eventValues }); /* type values: 1: Unlocked by PIN @@ -1758,44 +1799,44 @@ export class P2PClientProtocol extends TypedEmitter { this.emit("wrong try-protect alarm", message.channel); break; default: - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD SmartSafe Status update - Not implemented`, { message: message.data.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD SmartSafe Status update - Not implemented`, { stationSN: this.rawStation.station_sn, message: data.toString() }); break; } break; } default: - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD SmartSafe - Not implemented`, { message: message.data.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD SmartSafe - Not implemented`, { stationSN: this.rawStation.station_sn, message: data.toString() }); break; } } else if (json.cmd === CommandType.CMD_ENTRY_SENSOR_STATUS) { // {"cmd":1550,"payload":{"status":1}} const payload = json.payload as EntrySensorStatus; - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD EntrySensor Status update`, { status: payload?.status }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD EntrySensor Status update`, { stationSN: this.rawStation.station_sn, status: payload?.status }); if (payload) { this.emit("sensor status", message.channel, payload.status); } } else if (json.cmd === CommandType.CMD_CAMERA_GARAGE_DOOR_STATUS) { // {"cmd":7500,"payload":{"type":24,"notify_tag":"","door_id":2}} const payload = json.payload as GarageDoorStatus; - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD GarageDoor Status update`, { doorId: payload?.door_id, status: payload?.type, notify_tag: payload?.notify_tag }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD GarageDoor Status update`, { stationSN: this.rawStation.station_sn, doorId: payload?.door_id, status: payload?.type, notify_tag: payload?.notify_tag }); if (payload) { this.emit("garage door status", message.channel, payload.door_id, payload.type); } } else { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD - Not implemented`, { commandIdName: CommandType[json.cmd], commandId: json.cmd, message: message.data.toString() }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD - Not implemented`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[json.cmd], commandId: json.cmd, message: data.toString() }); } } } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_NOTIFY_PAYLOAD Error`, { error: error, payload: message.data.toString() }); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_NOTIFY_PAYLOAD Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString() } }); } break; case CommandType.CMD_GET_DELAY_ALARM: try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_GET_DELAY_ALARM :`, { payload: message.data.toString("hex") }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_GET_DELAY_ALARM :`, { stationSN: this.rawStation.station_sn, payload: data.toString("hex") }); //When the alarm is armed, CMD_GET_DELAY_ALARM is called with event data 0, so ignore it - const alarmEventNumber = message.data.slice(0, 4).readUInt32LE(); - const alarmDelay = message.data.slice(4, 8).readUInt32LE(); + const alarmEventNumber = data.slice(0, 4).readUInt32LE(); + const alarmDelay = data.slice(4, 8).readUInt32LE(); if (alarmEventNumber === 0) { this.emit("alarm armed"); } else { @@ -1803,27 +1844,27 @@ export class P2PClientProtocol extends TypedEmitter { } } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_GET_DELAY_ALARM - Error`, { error: error, payload: message.data.toString("hex") }); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_GET_DELAY_ALARM - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_SET_TONE_FILE: try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_SET_TONE_FILE :`, { payload: message.data.toString("hex") }); - const alarmEventNumber: AlarmEvent = message.data.slice(0, 4).readUInt32LE(); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_SET_TONE_FILE :`, { stationSN: this.rawStation.station_sn, payload: data.toString("hex") }); + const alarmEventNumber: AlarmEvent = data.slice(0, 4).readUInt32LE(); this.emit("alarm event", alarmEventNumber); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_SET_TONE_FILE - Error`, { error: error, payload: message.data.toString("hex") }); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_SET_TONE_FILE - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_SET_SNOOZE_MODE: // Received for station managed devices when snooze time ends try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_SET_SNOOZE_MODE`, { payload: Buffer.from(message.data.toString(), "base64").toString() }); - this.emit("parameter", message.channel, CommandType.CMD_SET_SNOOZE_MODE, message.data.toString()); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_SET_SNOOZE_MODE`, { stationSN: this.rawStation.station_sn, payload: Buffer.from(data.toString(), "base64").toString() }); + this.emit("parameter", message.channel, CommandType.CMD_SET_SNOOZE_MODE, data.toString()); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_SET_SNOOZE_MODE - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_SET_SNOOZE_MODE - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_PING: @@ -1832,28 +1873,30 @@ export class P2PClientProtocol extends TypedEmitter { case CommandType.CMD_DATABASE_IMAGE: // Received data for preview image download try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_DATABASE_IMAGE`, { message: message.data.toString("utf-8") }); - const image = parseJSON(message.data.toString("utf-8"), this.log) as CmdDatabaseImageResponse; + const str = getNullTerminatedString(data, "utf8"); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_DATABASE_IMAGE`, { stationSN: this.rawStation.station_sn, message: str }); + const image = parseJSON(str, this.log) as CmdDatabaseImageResponse; this.emit("image download", image.file, decodeImage(this.rawStation.p2p_did, Buffer.from(image.content, "base64"))); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_DATABASE_IMAGE - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_DATABASE_IMAGE - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString() } }); } break; case CommandType.CMD_GET_TFCARD_STATUS: try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_GET_TFCARD_STATUS :`, { payload: message.data.toString("hex") }); - const tfCardStatus: TFCardStatus = message.data.slice(0, 4).readUInt32LE(); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_GET_TFCARD_STATUS :`, { stationSN: this.rawStation.station_sn, payload: data.toString("hex") }); + const tfCardStatus: TFCardStatus = data.slice(0, 4).readUInt32LE(); this.emit("tfcard status", message.channel, tfCardStatus); } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_GET_TFCARD_STATUS - Error`, { error: error, payload: message.data.toString("hex") }); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_GET_TFCARD_STATUS - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } break; case CommandType.CMD_DATABASE: try { - this.log.debug(`Station ${this.rawStation.station_sn} - CMD_DATABASE :`, { payload: message.data.toString() }); - const databaseResponse = parseJSON(message.data.toString("utf-8"), this.log) as P2PDatabaseResponse; + const str = getNullTerminatedString(data, "utf8"); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_DATABASE :`, { stationSN: this.rawStation.station_sn, payload: str }); + const databaseResponse = parseJSON(str, this.log) as P2PDatabaseResponse; switch(databaseResponse.cmd) { case CommandType.CMD_DATABASE_QUERY_LATEST_INFO: { @@ -1964,7 +2007,7 @@ export class P2PClientProtocol extends TypedEmitter { update_time: (tableRecord as P2PDatabaseQueryLocalRecordCropPictureInfo).update_time, }); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - Not implemented - CMD_DATABASE_QUERY_LOCAL - table_name: ${record.table_name}`); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Not implemented - CMD_DATABASE_QUERY_LOCAL - table_name: ${record.table_name}`, { stationSN: this.rawStation.station_sn }); } result.set(tableRecord.record_id, tmpRecord); } @@ -1981,21 +2024,51 @@ export class P2PClientProtocol extends TypedEmitter { break; } default: - this.log.debug(`Station ${this.rawStation.station_sn} - Not implemented - CMD_DATABASE message`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, databaseResponse: databaseResponse }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Not implemented - CMD_DATABASE message`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, databaseResponse: databaseResponse }); break; } } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - CMD_DATABASE - Error`, { error: error, payload: message.data.toString() }); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - CMD_DATABASE - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString() } }); } break; + case CommandType.CMD_GATEWAYINFO: + const cipherID = data.slice(0, 2).readUInt16LE(); + //const unknownNumber = data.slice(2, 2).readUInt16LE(); + const encryptedKey = data.slice(4, data.length - 1); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_GATEWAYINFO - cipherID`, { stationSN: this.rawStation.station_sn, channel: message.channel, data: data.toString("hex"), cipherID: cipherID }); + this.api.getCipher(cipherID, this.rawStation.member.admin_user_id).then((cipher) => { + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_GATEWAYINFO - get cipher with cipherID`, { stationSN: this.rawStation.station_sn, channel: message.channel, data: data.toString("hex"), cipherID: cipherID, cipher: JSON.stringify(cipher) }); + if (cipher !== undefined) { + this.encryption = EncryptionType.LEVEL_2; + const rsa = getRSAPrivateKey(cipher.private_key); + this.p2pKey = rsa.decrypt(encryptedKey); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_GATEWAYINFO - set encryption level 2`, { stationSN: this.rawStation.station_sn, key: this.p2pKey.toString("hex") }); + } else { + this.encryption = EncryptionType.LEVEL_1; + this.p2pKey = Buffer.from(getP2PCommandEncryptionKey(this.rawStation.station_sn, this.rawStation.p2p_did)); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_GATEWAYINFO - set encryption level 1`, { stationSN: this.rawStation.station_sn, key: this.p2pKey.toString("hex") }); + } + this._clearTimeout(this.messageStates.get(message.seqNo)?.timeout); + this.messageStates.delete(message.seqNo); + this.sendQueuedMessage(); + }).catch((err) => { + const error = ensureError(err); + this.encryption = EncryptionType.LEVEL_1; + this.p2pKey = Buffer.from(getP2PCommandEncryptionKey(this.rawStation.station_sn, this.rawStation.p2p_did)); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - CMD_GATEWAYINFO - set encryption level 1 (fallback)`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") }, key: this.p2pKey.toString("hex") }); + this._clearTimeout(this.messageStates.get(message.seqNo)?.timeout); + this.messageStates.delete(message.seqNo); + this.sendQueuedMessage(); + }); + break; default: - this.log.debug(`Station ${this.rawStation.station_sn} - Not implemented - CONTROL message`, { commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, data: message.data.toString("hex") }); + this.log.debug(`Handle DATA ${P2PDataType[message.type]} - Not implemented`, { stationSN: this.rawStation.station_sn, commandIdName: CommandType[message.commandId], commandId: message.commandId, channel: message.channel, data: data.toString("hex") }); break; } } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - ${CommandType[message.commandId]} - Error`, error); + this.log.error(`Handle DATA ${P2PDataType[message.type]} - Error`, { error: getError(error), stationSN: this.rawStation.station_sn, message: { seqNo: message.seqNo, channel: message.channel, commandType: CommandType[message.commandId], signCode: message.signCode, type: message.type, dataType: P2PDataType[message.dataType], data: message.data.toString("hex") } }); } } @@ -2006,7 +2079,7 @@ export class P2PClientProtocol extends TypedEmitter { const seqBuffer = Buffer.allocUnsafe(2); seqBuffer.writeUInt16BE(seqNo, 0); const payload = Buffer.concat([dataType, pendingAcksBuffer, seqBuffer]); - await this.sendMessage(`Send ack to station ${this.rawStation.station_sn}`, address, RequestMessageType.ACK, payload); + await this.sendMessage(`Send ack`, address, RequestMessageType.ACK, payload); } private getDataType(input: Buffer): P2PDataType { @@ -2034,7 +2107,7 @@ export class P2PClientProtocol extends TypedEmitter { this.sendQueue = []; if (this.socket) { if (this.connected) { - await this.sendMessage(`Send end to station ${this.rawStation.station_sn}`, this.connectAddress!, RequestMessageType.END); + await this.sendMessage(`Send end connection`, this.connectAddress!, RequestMessageType.END); this._disconnected(); } else { this._initialize(); @@ -2056,8 +2129,9 @@ export class P2PClientProtocol extends TypedEmitter { this._disconnected(); } - private onError(error: any): void { - this.log.debug(`Station ${this.rawStation.station_sn} - Error:`, error); + private onError(err: any): void { + const error = ensureError(err); + this.log.debug(`Socket Error:`, { error: getError(error), stationSN: this.rawStation.station_sn }); } private scheduleHeartbeat(): void { @@ -2067,7 +2141,7 @@ export class P2PClientProtocol extends TypedEmitter { this.scheduleHeartbeat(); }, this.getHeartbeatInterval()); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - Heartbeat disabled!`); + this.log.debug(`Heartbeat not activated because no connection is present!`, { stationSN: this.rawStation.station_sn }); } } @@ -2079,7 +2153,7 @@ export class P2PClientProtocol extends TypedEmitter { }, this.KEEPALIVE_INTERVAL); this.closeEnergySavingDevice(); } else { - this.log.debug(`Station ${this.rawStation.station_sn} - p2p keepalive disabled!`); + this.log.debug(`P2P keepalive not activated because no connection is present`, { stationSN: this.rawStation.station_sn }); } } @@ -2291,7 +2365,7 @@ export class P2PClientProtocol extends TypedEmitter { endpoint: "v1/app/equipment/get_dsk_keys", data: data }); - this.log.debug(`Station ${this.rawStation.station_sn} - Response:`, response.data); + this.log.debug(`Get DSK keys - Response:`, { stationSN: this.rawStation.station_sn, data: response.data }); if (response.status == 200) { const result: ResultResponse = response.data; @@ -2301,18 +2375,18 @@ export class P2PClientProtocol extends TypedEmitter { if (key.station_sn == this.rawStation.station_sn) { this.dskKey = key.dsk_key; this.dskExpiration = new Date(key.expiration * 1000); - this.log.debug(`${this.constructor.name}.getDSKKeys(): dskKey: ${this.dskKey} dskExpiration: ${this.dskExpiration}`); + this.log.debug(`Get DSK keys - received key and expiration`, { stationSN: this.rawStation.station_sn, dskKey: this.dskKey, dskExpiration: this.dskExpiration }); } }); } else { - this.log.error(`Station ${this.rawStation.station_sn} - Response code not ok`, { code: result.code, msg: result.msg }); + this.log.error(`Get DSK keys - Response code not ok`, { stationSN: this.rawStation.station_sn, code: result.code, msg: result.msg }); } } else { - this.log.error(`Station ${this.rawStation.station_sn} - Status return code not 200`, { status: response.status, statusText: response.statusText }); + this.log.error(`Get DSK keys - Status return code not 200`, { stationSN: this.rawStation.station_sn, status: response.status, statusText: response.statusText }); } } catch (err) { const error = ensureError(err); - this.log.error(`Station ${this.rawStation.station_sn} - Generic Error`, error); + this.log.error(`Get DSK keys - Generic Error`, { error: getError(error), stationSN: this.rawStation.station_sn }); } } } @@ -2372,15 +2446,16 @@ export class P2PClientProtocol extends TypedEmitter { this.talkbackStream?.removeAllListeners(); } - private onTalkbackStreamError(error: any): void { - this.log.debug(`Station ${this.rawStation.station_sn} - Talkback Error:`, error); + private onTalkbackStreamError(err: any): void { + const error = ensureError(err); + this.log.debug(`Talkback Stream Error:`, { error: getError(error), stationSN: this.rawStation.station_sn }); } private async _sendVideoData(message: P2PVideoMessageState): Promise { if (message.retries < this.MAX_RETRIES) { message.retries++; } else { - this.log.error(`Station ${this.rawStation.station_sn} - Max send video data retries ${this.messageVideoStates.get(message.sequence)?.retries} reached. Discard data.`, { sequence: message.sequence, channel: message.channel, retries: message.retries }); + this.log.error(`Sending video data - Max send video data retries ${this.messageVideoStates.get(message.sequence)?.retries} reached. Discard data.`, { stationSN: this.rawStation.station_sn, sequence: message.sequence, channel: message.channel, retries: message.retries }); this.messageVideoStates.delete(message.sequence); this.emit("talkback error", message.channel, new TalkbackError("Max send video data retries reached. Discard data packet.", { context: { station: this.rawStation.station_sn, channel: message.channel, retries: message.retries } })); return; @@ -2393,7 +2468,7 @@ export class P2PClientProtocol extends TypedEmitter { this.messageVideoStates.set(message.sequence, message); this.log.debug("Sending p2p video data...", { station: this.rawStation.station_sn, sequence: message.sequence, channel: message.channel, retries: message.retries, messageVideoStatesSize: this.messageVideoStates.size }); - await this.sendMessage(`Send p2p video data to station ${this.rawStation.station_sn}`, this.connectAddress!, RequestMessageType.DATA, message.data); + await this.sendMessage(`Send video data`, this.connectAddress!, RequestMessageType.DATA, message.data); } public isTalkbackOngoing(channel: number): boolean { diff --git a/src/p2p/types.ts b/src/p2p/types.ts index 2086398c..f2e2f7c8 100644 --- a/src/p2p/types.ts +++ b/src/p2p/types.ts @@ -1109,4 +1109,18 @@ export interface LockV12P2PCommand { aesKey: string; bleCommand: number; payload: LockV12P2PCommandType; +} + +export enum EncryptionType { + NONE = 0, + LEVEL_1 = 1, + LEVEL_2 = 2, +} + +export enum InternalP2PCommandType { + WithIntString, + WithInt, + WithStringPayload, + WithString, + WithoutData, } \ No newline at end of file diff --git a/src/p2p/utils.ts b/src/p2p/utils.ts index 339c0349..08e1dc6a 100644 --- a/src/p2p/utils.ts +++ b/src/p2p/utils.ts @@ -5,7 +5,7 @@ import { randomBytes, createCipheriv, createECDH, ECDH, createHmac, createDeciph import * as os from "os"; import { P2PMessageParts, P2PMessageState, P2PQueueMessage, RGBColor } from "./interfaces"; -import { CommandType, ESLCommand, ESLBleCommand, LockV12P2PCommand, P2PDataTypeHeader, SmartSafeCommandCode, VideoCodec } from "./types"; +import { CommandType, ESLCommand, ESLBleCommand, LockV12P2PCommand, P2PDataTypeHeader, SmartSafeCommandCode, VideoCodec, EncryptionType } from "./types"; import { Address, LockP2PCommandPayloadType, LockP2PCommandType, LockV12P2PCommandPayloadType, SmartSafeNotificationResponse, SmartSafeP2PCommandType } from "./models"; import { DeviceType } from "../http/types"; import { Device, Lock, SmartSafe } from "../http/device"; @@ -149,11 +149,11 @@ export const buildCheckCamPayload2 = (p2pDid: string, data: Buffer): Buffer => { return Buffer.concat([data, p2pDidBuffer, magic]); }; -export const buildIntCommandPayload = (serialNumber: string, p2pDid: string, commandType: CommandType, value: number, strValue = "", channel = 255): Buffer => { +export const buildIntCommandPayload = (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: number, strValue = "", channel = 255): Buffer => { const emptyBuffer = Buffer.from([0x00, 0x00]); const magicBuffer = Buffer.from([0x01, 0x00]); - const encrypted = isP2PCommandEncrypted(commandType); - const channelBuffer = Buffer.from([channel, encrypted ? 1 : 0]); + const encrypted = isP2PCommandEncrypted(commandType) && encryptionType !== EncryptionType.NONE && encryptionKey !== undefined; + const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]); const valueBuffer = Buffer.allocUnsafe(4); valueBuffer.writeUInt32LE(value, 0); const headerBuffer = Buffer.allocUnsafe(2); @@ -171,15 +171,15 @@ export const buildIntCommandPayload = (serialNumber: string, p2pDid: string, com magicBuffer, channelBuffer, emptyBuffer, - encrypted ? encryptP2PData(dataBuffer, Buffer.from(getP2PCommandEncryptionKey(serialNumber, p2pDid))) : dataBuffer + encrypted ? encryptP2PData(dataBuffer, encryptionKey) : dataBuffer ]); }; -export const buildStringTypeCommandPayload = (serialNumber: string, p2pDid: string, commandType: CommandType, strValue: string, strValueSub: string, channel = 255): Buffer => { +export const buildStringTypeCommandPayload = (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, strValue: string, strValueSub: string, channel = 255): Buffer => { const emptyBuffer = Buffer.from([0x00, 0x00]); const magicBuffer = Buffer.from([0x01, 0x00]); - const encrypted = isP2PCommandEncrypted(commandType); - const channelBuffer = Buffer.from([channel, encrypted ? 1 : 0]); + const encrypted = isP2PCommandEncrypted(commandType) && encryptionType !== EncryptionType.NONE && encryptionKey !== undefined; + const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]); const someBuffer = Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00]); const strValueBuffer = stringWithLength(strValue); const strValueSubBuffer = stringWithLength(strValueSub); @@ -198,15 +198,15 @@ export const buildStringTypeCommandPayload = (serialNumber: string, p2pDid: stri magicBuffer, channelBuffer, emptyBuffer, - encrypted ? encryptP2PData(dataBuffer, Buffer.from(getP2PCommandEncryptionKey(serialNumber, p2pDid))) : dataBuffer + encrypted ? encryptP2PData(dataBuffer, encryptionKey) : dataBuffer ]); }; -export const buildIntStringCommandPayload = (serialNumber: string, p2pDid: string, commandType: CommandType, value: number, valueSub = 0, strValue = "", strValueSub = "", channel = 0): Buffer => { +export const buildIntStringCommandPayload = (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: number, valueSub = 0, strValue = "", strValueSub = "", channel = 0): Buffer => { const emptyBuffer = Buffer.from([0x00, 0x00]); const magicBuffer = Buffer.from([0x01, 0x00]); - const encrypted = isP2PCommandEncrypted(commandType); - const channelBuffer = Buffer.from([channel, encrypted ? 1 : 0]); + const encrypted = isP2PCommandEncrypted(commandType) && encryptionType !== EncryptionType.NONE && encryptionKey !== undefined; + const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]); const someintBuffer = Buffer.allocUnsafe(4); someintBuffer.writeUInt32LE(valueSub, 0); const valueBuffer = Buffer.allocUnsafe(4); @@ -229,7 +229,7 @@ export const buildIntStringCommandPayload = (serialNumber: string, p2pDid: strin magicBuffer, channelBuffer, emptyBuffer, - encrypted ? encryptP2PData(dataBuffer, Buffer.from(getP2PCommandEncryptionKey(serialNumber, p2pDid))) : dataBuffer + encrypted ? encryptP2PData(dataBuffer, encryptionKey) : dataBuffer ]); }; @@ -271,12 +271,12 @@ export const buildCommandHeader = (seqNumber: number, commandType: CommandType, }; -export const buildCommandWithStringTypePayload = (serialNumber: string, p2pDid: string, commandType: CommandType, value: string, channel = 0): Buffer => { +export const buildCommandWithStringTypePayload = (encryptionType: EncryptionType, encryptionKey: Buffer | undefined, serialNumber: string, p2pDid: string, commandType: CommandType, value: string, channel = 0): Buffer => { const headerBuffer = Buffer.allocUnsafe(2); const emptyBuffer = Buffer.from([0x00, 0x00]); const magicBuffer = Buffer.from([0x01, 0x00]); - const encrypted = isP2PCommandEncrypted(commandType); - const channelBuffer = Buffer.from([channel, encrypted ? 1 : 0]); + const encrypted = isP2PCommandEncrypted(commandType) && encryptionType !== EncryptionType.NONE && encryptionKey !== undefined; + const channelBuffer = Buffer.from([channel, encrypted ? encryptionType : 0]); const dataBuffer = encrypted ? paddingP2PData(Buffer.from(value)) : Buffer.from(value); headerBuffer.writeUInt16LE(dataBuffer.length, 0); @@ -286,7 +286,7 @@ export const buildCommandWithStringTypePayload = (serialNumber: string, p2pDid: magicBuffer, channelBuffer, emptyBuffer, - encrypted ? encryptP2PData(dataBuffer, Buffer.from(getP2PCommandEncryptionKey(serialNumber, p2pDid))) : dataBuffer + encrypted ? encryptP2PData(dataBuffer, encryptionKey) : dataBuffer ]); }; @@ -302,6 +302,9 @@ export const sortP2PMessageParts = (messages: P2PMessageParts): Buffer => { export const getRSAPrivateKey = (pem: string): NodeRSA => { const key = new NodeRSA(); + if (pem.indexOf("\n") !== -1) { + pem = pem.replaceAll("\n", ""); + } if (pem.startsWith("-----BEGIN RSA PRIVATE KEY-----")) { pem = pem.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", ""); } @@ -504,7 +507,7 @@ export const buildVoidCommandPayload = (channel = 255): Buffer => { }; export function isP2PQueueMessage(type: P2PQueueMessage | P2PMessageState): type is P2PQueueMessage { - return (type as P2PQueueMessage).payload !== undefined; + return (type as P2PQueueMessage).p2pCommand !== undefined; } export const encryptPayloadData = (data: string | Buffer, key: Buffer, iv: Buffer): Buffer => { @@ -722,4 +725,9 @@ export const DecimalToRGBColor = function(color: number): RGBColor { export const RGBColorToDecimal = function(color: RGBColor): number { return (color.red << 16) + (color.green << 8) + (color.blue); +} + +export const getNullTerminatedString = function(data: Buffer, encoding?: BufferEncoding): string { + const index = data.indexOf(0); + return data.toString(encoding, 0, index === -1 ? data.length : index); } \ No newline at end of file diff --git a/src/push/client.ts b/src/push/client.ts index 67582cc5..82b10105 100644 --- a/src/push/client.ts +++ b/src/push/client.ts @@ -8,9 +8,10 @@ import { dummyLogger, Logger } from "ts-log"; import { Message, MessageTag, RawPushMessage } from "./models"; import { PushClientParser } from "./parser"; import { PushClientEvents } from "./interfaces"; -import { parseJSON } from "../utils"; +import { getError, parseJSON } from "../utils"; import { BuildHeartbeatAckRequestError, BuildHeartbeatPingRequestError, BuildLoginRequestError } from "./error"; import { ensureError } from "../error"; +import { getNullTerminatedString } from "../p2p/utils"; export class PushClient extends TypedEmitter { @@ -137,7 +138,7 @@ export class PushClient extends TypedEmitter { heartbeatPingRequest.last_stream_id_received = stream_id; } - this.log.debug(`heartbeatPingRequest`, heartbeatPingRequest); + this.log.debug(`Push client - heartbeatPingRequest`, { streamId: stream_id, request: JSON.stringify(heartbeatPingRequest) }); const HeartbeatPingRequestType = PushClient.proto!.lookupType("mcs_proto.HeartbeatPing"); const errorMessage = HeartbeatPingRequestType.verify(heartbeatPingRequest); if (errorMessage) { @@ -159,7 +160,7 @@ export class PushClient extends TypedEmitter { heartbeatAckRequest.last_stream_id_received = stream_id; heartbeatAckRequest.status = status; } - this.log.debug(`heartbeatAckRequest`, heartbeatAckRequest); + this.log.debug(`Push client - heartbeatAckRequest`, { streamId: stream_id, status: status, request: JSON.stringify(heartbeatAckRequest) }); const HeartbeatAckRequestType = PushClient.proto!.lookupType("mcs_proto.HeartbeatAck"); const errorMessage = HeartbeatAckRequestType.verify(heartbeatAckRequest); @@ -192,14 +193,14 @@ export class PushClient extends TypedEmitter { private onSocketError(err: any): void { const error = ensureError(err); - this.log.error(`onSocketError`, error); + this.log.error(`Push client - Socket Error`, { error: getError(error) }); } private handleParsedMessage(message: Message): void { this.resetCurrentDelay(); switch (message.tag) { case MessageTag.DataMessageStanza: - this.log.debug(`DataMessageStanza`, message); + this.log.debug(`Push client - DataMessageStanza`, { message: JSON.stringify(message) }); if (message.object && message.object.persistentId) this.persistentIds.push(message.object.persistentId); @@ -212,10 +213,10 @@ export class PushClient extends TypedEmitter { this.handleHeartbeatAck(message); break; case MessageTag.Close: - this.log.debug(`Close: Server requested close`, message); + this.log.debug(`Push client - Close: Server requested close`, { message: JSON.stringify(message) }); break; case MessageTag.LoginResponse: - this.log.debug("Login response: GCM -> logged in -> waiting for push messages..."); + this.log.debug("Push client - Login response: GCM -> logged in -> waiting for push messages...", { message: JSON.stringify(message) }); this.loggedIn = true; this.persistentIds = []; @@ -226,20 +227,20 @@ export class PushClient extends TypedEmitter { }, this.getHeartbeatInterval()); break; case MessageTag.LoginRequest: - this.log.debug(`Login request`, message); + this.log.debug(`Push client - Login request`, { message: JSON.stringify(message) }); break; case MessageTag.IqStanza: - this.log.debug(`IqStanza: Not implemented`, message); + this.log.debug(`Push client - IqStanza: Not implemented`, { message: JSON.stringify(message) }); break; default: - this.log.debug(`Unknown message`, message); + this.log.debug(`Push client - Unknown message`, { message: JSON.stringify(message) }); return; } this.streamId++; } private handleHeartbeatPing(message: Message): void { - this.log.debug(`Heartbeat ping`, message); + this.log.debug(`Push client - Heartbeat ping`, { message: JSON.stringify(message) }); let streamId = undefined; let status = undefined; if (this.newStreamIdAvailable()) { @@ -252,7 +253,7 @@ export class PushClient extends TypedEmitter { } private handleHeartbeatAck(message: Message): void { - this.log.debug(`Heartbeat acknowledge`, message); + this.log.debug(`Push client - Heartbeat acknowledge`, { message: JSON.stringify(message) }); } private convertPayloadMessage(message: Message): RawPushMessage { @@ -260,7 +261,7 @@ export class PushClient extends TypedEmitter { const messageData: Record = {}; appData.forEach((kv: { key: string; value: any }) => { if (kv.key === "payload") { - const payload = parseJSON(Buffer.from(kv.value, "base64").toString("utf8"), this.log); + const payload = parseJSON(getNullTerminatedString(Buffer.from(kv.value, "base64"),"utf8"), this.log); messageData[kv.key] = payload; } else { messageData[kv.key] = kv.value; @@ -288,7 +289,7 @@ export class PushClient extends TypedEmitter { this.scheduleHeartbeat(client); }, client.getHeartbeatInterval()); } else { - this.log.debug("Heartbeat disabled!"); + this.log.debug("Push client - Heartbeat disabled!"); } } @@ -299,11 +300,11 @@ export class PushClient extends TypedEmitter { } if (this.client && this.isConnected()) { - this.log.debug(`Sending heartbeat...`, streamId); + this.log.debug(`Push client - Sending heartbeat...`, { streamId: streamId }); this.client.write(this.buildHeartbeatPingRequest(streamId)); return true; } else { - this.log.debug("No more connected, reconnect..."); + this.log.debug("Push client - No more connected, reconnect..."); this.scheduleReconnect(); } return false; @@ -335,7 +336,7 @@ export class PushClient extends TypedEmitter { private scheduleReconnect(): void { const delay = this.getCurrentDelay(); - this.log.debug("Schedule reconnect...", { delay: delay }); + this.log.debug("Push client - Schedule reconnect...", { delay: delay }); if (!this.reconnectTimeout) this.reconnectTimeout = setTimeout(() => { this.connect(); diff --git a/src/push/parser.ts b/src/push/parser.ts index a09d18f0..dd748011 100644 --- a/src/push/parser.ts +++ b/src/push/parser.ts @@ -78,7 +78,7 @@ export class PushClientParser extends TypedEmitter { this.onGotMessageBytes(); break; default: - this.log.warn("Unknown state", { state: this.state }); + this.log.warn("Push Parser - Unknown state", { state: this.state }); break; } } @@ -161,7 +161,7 @@ export class PushClientParser extends TypedEmitter { if (this.messageTag === MessageTag.LoginResponse) { if (this.handshakeComplete) { - this.log.error("Unexpected login response!"); + this.log.error("Push Parser - Unexpected login response!"); } else { this.handshakeComplete = true; } diff --git a/src/push/service.ts b/src/push/service.ts index 6f0dc0a7..cb73625a 100644 --- a/src/push/service.ts +++ b/src/push/service.ts @@ -10,7 +10,7 @@ import { PushNotificationServiceEvents } from "./interfaces"; import { Device } from "../http/device"; import { DeviceType } from "../http/types"; import { getAbsoluteFilePath } from "../http/utils"; -import { getShortUrl, isEmpty, parseJSON } from "../utils"; +import { getError, getShortUrl, isEmpty, parseJSON } from "../utils"; import { ExecuteCheckInError, FidRegistrationFailedError, RegisterGcmError, RenewFidTokenFailedError, UnknownExpiryFormaError } from "./error"; import { ensureError } from "../error"; @@ -101,12 +101,12 @@ export class PushNotificationService extends TypedEmitter { if (!this.credentials || Object.keys(this.credentials).length === 0 || (this.credentials && this.credentials.fidResponse && new Date().getTime() >= this.credentials.fidResponse.authToken.expiresAt)) { - this.log.debug(`Create new push credentials...`); + this.log.debug(`Create new push credentials...`, { credentials: this.credentials, renew: renew }); this.credentials = await this.createPushCredentials().catch(err => { const error = ensureError(err); - this.log.error("Create push credentials Error", error); + this.log.error("Create push credentials Error", { error: getError(error), credentials: this.credentials, renew: renew }); return undefined; }); } else if (this.credentials && renew) { - this.log.debug(`Renew push credentials...`); + this.log.debug(`Renew push credentials...`, { credentials: this.credentials, renew: renew }); this.credentials = await this.renewPushCredentials(this.credentials).catch(err => { const error = ensureError(err); - this.log.error("Push credentials renew Error", error); + this.log.error("Push credentials renew Error", { error: getError(error), credentials: this.credentials, renew: renew }); return undefined; }); } else { - this.log.debug(`Login with previous push credentials...`, this.credentials); + this.log.debug(`Login with previous push credentials...`, { credentials: this.credentials }); this.credentials = await this.loginPushCredentials(this.credentials).catch(err => { const error = ensureError(err); - this.log.error("Push credentials login Error", error); + this.log.error("Push credentials login Error", { error: getError(error), credentials: this.credentials, renew: renew }); return undefined; }); } @@ -686,7 +686,7 @@ export class PushNotificationService extends TypedEmitter { const error = ensureError(err); - this.log.error(`Got exception trying to initialize push notifications`, error); + this.log.error(`Got exception trying to initialize push notifications`, { error: getError(error), credentials: this.credentials }); }); if (!this.credentials) { diff --git a/src/utils.ts b/src/utils.ts index bba655d1..abcf3f14 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -2,10 +2,17 @@ import * as crypto from "crypto"; import { Logger } from "ts-log"; import EventEmitter from "events"; -import { EufySecurityPersistentData } from "./interfaces"; +import { ErrorObject, EufySecurityPersistentData } from "./interfaces"; import { InvalidPropertyValueError, ensureError } from "./error"; import { PropertyMetadataAny, PropertyMetadataNumeric, PropertyMetadataObject, PropertyMetadataString } from "./http/interfaces"; +export const getError = function(error: Error): ErrorObject { + return { + message: `${error.name}: ${error.message}`, + stacktrace: error.stack + }; +} + export const removeLastChar = function(text: string, char: string): string { const strArr = [...text]; strArr.splice(text.lastIndexOf(char), 1); @@ -117,7 +124,7 @@ export const parseJSON = function(data: string, log: Logger): any { return JSON.parse(data.replace(/[\0]+$/g, "")); } catch(err) { const error = ensureError(err); - log.error("JSON parse error", { data: data, error: error }); + log.error("JSON parse error", { error: getError(error), data: data }); } return undefined; } diff --git a/tsconfig.json b/tsconfig.json index acbd6e41..bbf45273 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ "noEmitOnError": true, "outDir": "./build/", "removeComments": false, - "module": "CommonJS", + "module": "Node16", "moduleResolution": "Node16", // this is necessary for the automatic typing of the adapter config "resolveJsonModule": true,