mirror of
https://github.com/koush/scrypted.git
synced 2026-03-20 16:40:24 +00:00
zwave: update
This commit is contained in:
@@ -1,15 +1 @@
|
||||
# Z-Wave USB Controller
|
||||
|
||||
## npm commands
|
||||
* npm run scrypted-webpack
|
||||
* npm run scrypted-deploy <ipaddress>
|
||||
* npm run scrypted-debug <ipaddress>
|
||||
|
||||
## scrypted distribution via npm
|
||||
1. Ensure package.json is set up properly for publishing on npm.
|
||||
2. npm publish
|
||||
|
||||
## Visual Studio Code configuration
|
||||
|
||||
* If using a remote server, edit [.vscode/settings.json](blob/master/.vscode/settings.json) to specify the IP Address of the Scrypted server.
|
||||
* Launch Scrypted Debugger from the launch menu.
|
||||
# Z-Wave Plugin for Scrypted
|
||||
|
||||
101
plugins/zwave/package-lock.json
generated
101
plugins/zwave/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/zwave",
|
||||
"version": "0.0.39",
|
||||
"version": "0.0.41",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/zwave",
|
||||
"version": "0.0.39",
|
||||
"version": "0.0.41",
|
||||
"license": "Apache",
|
||||
"dependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
@@ -18,7 +18,7 @@
|
||||
"@types/node": "^16.7.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"zwave-js": "^8.11.3"
|
||||
"zwave-js": "^8.11.5"
|
||||
}
|
||||
},
|
||||
"../../sdk": {
|
||||
@@ -67,10 +67,11 @@
|
||||
"extraneous": true
|
||||
},
|
||||
"file-stream-rotator": {
|
||||
"name": "@zwave-js/file-stream-rotator",
|
||||
"version": "0.5.8-0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"moment": "^2.11.2"
|
||||
"date-fns-tz": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@alcalzone/jsonl-db": {
|
||||
@@ -420,9 +421,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@zwave-js/config": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@zwave-js/config/-/config-8.11.3.tgz",
|
||||
"integrity": "sha512-K5zXd5gPauWzpRqXMB1+9Xkx/wgZtnOnjWcgFV6cMiC7dzGLcQX6sCZXySMb2QFTu6J/DRrWTDWYBHACq09rVA==",
|
||||
"version": "8.11.4",
|
||||
"resolved": "https://registry.npmjs.org/@zwave-js/config/-/config-8.11.4.tgz",
|
||||
"integrity": "sha512-BsMq2ecOXm3xGyRKvcwYX5Xn84Vuwa9nmIC1VR9k2IwfAHaG6wwhqRgjrZGoHpDnHc12YfyCKvGsvvBh38mFlg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@zwave-js/core": "8.11.3",
|
||||
@@ -472,9 +473,9 @@
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@zwave-js/nvmedit": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@zwave-js/nvmedit/-/nvmedit-8.11.3.tgz",
|
||||
"integrity": "sha512-pa6PUkveZnHyU7DjM4yvdrwYlbWYVl/CZHp1lv90uxGSf1+TPM5ouaOVFEuWlhAiecUQgv6wcdDkx7O32WzCOA==",
|
||||
"version": "8.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@zwave-js/nvmedit/-/nvmedit-8.11.5.tgz",
|
||||
"integrity": "sha512-2dOVDGjT/ZaUcTMX92U/SUZPHbgtl1G02QxLx6GDBGNa1vZIeDTsAvcXdzr08XRl2wxjc8YrRCFxuR3ok3QiqA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@zwave-js/core": "8.11.3",
|
||||
@@ -907,6 +908,27 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "2.28.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz",
|
||||
"integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.11"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/date-fns"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns-tz": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.2.2.tgz",
|
||||
"integrity": "sha512-vWtn44eEqnLbkACb7T5G5gPgKR4nY8NkNMOCyoY49NsRGHrcDmY2aysCyzDeA+u+vcDBn/w6nQqEDyouRs4m8w==",
|
||||
"peerDependencies": {
|
||||
"date-fns": ">=2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dayjs": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz",
|
||||
@@ -1378,14 +1400,6 @@
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
@@ -2193,18 +2207,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/zwave-js": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/zwave-js/-/zwave-js-8.11.3.tgz",
|
||||
"integrity": "sha512-LKqj4j0i9MwkwhN1H+yZw4pAyuVnMcCYUpX+rSjtZkAZdsxp3n6QGac61da275t3SNBheiyzdsixrhVjxRVSiw==",
|
||||
"version": "8.11.5",
|
||||
"resolved": "https://registry.npmjs.org/zwave-js/-/zwave-js-8.11.5.tgz",
|
||||
"integrity": "sha512-3uK7nwUec6cyC2q6U0cTCXNHDKGWnZPVwkYr2yCn3/vBHm7qB1GLHnT+k65JM3fsNV8Y6j03rlxLq/E9WatSMg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@alcalzone/jsonl-db": "^2.4.1",
|
||||
"@alcalzone/pak": "^0.7.0",
|
||||
"@sentry/integrations": "^6.17.3",
|
||||
"@sentry/node": "^6.17.3",
|
||||
"@zwave-js/config": "8.11.3",
|
||||
"@zwave-js/config": "8.11.4",
|
||||
"@zwave-js/core": "8.11.3",
|
||||
"@zwave-js/nvmedit": "8.11.3",
|
||||
"@zwave-js/nvmedit": "8.11.5",
|
||||
"@zwave-js/serial": "8.11.3",
|
||||
"@zwave-js/shared": "8.11.3",
|
||||
"alcalzone-shared": "^4.0.1",
|
||||
@@ -2507,9 +2521,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@zwave-js/config": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@zwave-js/config/-/config-8.11.3.tgz",
|
||||
"integrity": "sha512-K5zXd5gPauWzpRqXMB1+9Xkx/wgZtnOnjWcgFV6cMiC7dzGLcQX6sCZXySMb2QFTu6J/DRrWTDWYBHACq09rVA==",
|
||||
"version": "8.11.4",
|
||||
"resolved": "https://registry.npmjs.org/@zwave-js/config/-/config-8.11.4.tgz",
|
||||
"integrity": "sha512-BsMq2ecOXm3xGyRKvcwYX5Xn84Vuwa9nmIC1VR9k2IwfAHaG6wwhqRgjrZGoHpDnHc12YfyCKvGsvvBh38mFlg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@zwave-js/core": "8.11.3",
|
||||
@@ -2545,13 +2559,13 @@
|
||||
"@zwave-js/file-stream-rotator": {
|
||||
"version": "file:file-stream-rotator",
|
||||
"requires": {
|
||||
"moment": "^2.11.2"
|
||||
"date-fns-tz": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"@zwave-js/nvmedit": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/@zwave-js/nvmedit/-/nvmedit-8.11.3.tgz",
|
||||
"integrity": "sha512-pa6PUkveZnHyU7DjM4yvdrwYlbWYVl/CZHp1lv90uxGSf1+TPM5ouaOVFEuWlhAiecUQgv6wcdDkx7O32WzCOA==",
|
||||
"version": "8.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@zwave-js/nvmedit/-/nvmedit-8.11.5.tgz",
|
||||
"integrity": "sha512-2dOVDGjT/ZaUcTMX92U/SUZPHbgtl1G02QxLx6GDBGNa1vZIeDTsAvcXdzr08XRl2wxjc8YrRCFxuR3ok3QiqA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@zwave-js/core": "8.11.3",
|
||||
@@ -2884,6 +2898,18 @@
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "2.28.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz",
|
||||
"integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==",
|
||||
"peer": true
|
||||
},
|
||||
"date-fns-tz": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-1.2.2.tgz",
|
||||
"integrity": "sha512-vWtn44eEqnLbkACb7T5G5gPgKR4nY8NkNMOCyoY49NsRGHrcDmY2aysCyzDeA+u+vcDBn/w6nQqEDyouRs4m8w==",
|
||||
"requires": {}
|
||||
},
|
||||
"dayjs": {
|
||||
"version": "1.10.7",
|
||||
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz",
|
||||
@@ -3248,11 +3274,6 @@
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
|
||||
"optional": true
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
@@ -3888,18 +3909,18 @@
|
||||
"optional": true
|
||||
},
|
||||
"zwave-js": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/zwave-js/-/zwave-js-8.11.3.tgz",
|
||||
"integrity": "sha512-LKqj4j0i9MwkwhN1H+yZw4pAyuVnMcCYUpX+rSjtZkAZdsxp3n6QGac61da275t3SNBheiyzdsixrhVjxRVSiw==",
|
||||
"version": "8.11.5",
|
||||
"resolved": "https://registry.npmjs.org/zwave-js/-/zwave-js-8.11.5.tgz",
|
||||
"integrity": "sha512-3uK7nwUec6cyC2q6U0cTCXNHDKGWnZPVwkYr2yCn3/vBHm7qB1GLHnT+k65JM3fsNV8Y6j03rlxLq/E9WatSMg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@alcalzone/jsonl-db": "^2.4.1",
|
||||
"@alcalzone/pak": "^0.7.0",
|
||||
"@sentry/integrations": "^6.17.3",
|
||||
"@sentry/node": "^6.17.3",
|
||||
"@zwave-js/config": "8.11.3",
|
||||
"@zwave-js/config": "8.11.4",
|
||||
"@zwave-js/core": "8.11.3",
|
||||
"@zwave-js/nvmedit": "8.11.3",
|
||||
"@zwave-js/nvmedit": "8.11.5",
|
||||
"@zwave-js/serial": "8.11.3",
|
||||
"@zwave-js/shared": "8.11.3",
|
||||
"alcalzone-shared": "^4.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/zwave",
|
||||
"version": "0.0.39",
|
||||
"version": "0.0.41",
|
||||
"description": "Z-Wave USB Controller for Scrypted",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache",
|
||||
@@ -40,6 +40,6 @@
|
||||
"@types/node": "^16.7.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"zwave-js": "^8.11.3"
|
||||
"zwave-js": "^8.11.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CommandClassInfo, getCommandClass, getCommandClassIndex } from "./Comma
|
||||
import { ZwaveDeviceBase } from "./CommandClasses/ZwaveDeviceBase";
|
||||
import { getHash, getNodeHash, getInstanceHash } from "./Types";
|
||||
import debounce from "lodash/debounce";
|
||||
import { Driver, Endpoint, ZWaveController, ZWaveNode, CommandClass } from "zwave-js";
|
||||
import { Driver, Endpoint, ZWaveController, ZWaveNode, CommandClass, InclusionUserCallbacks, InclusionGrant, InclusionStrategy, NodeStatus } from "zwave-js";
|
||||
import { ValueID, CommandClasses } from "@zwave-js/core"
|
||||
import { randomBytes } from "crypto";
|
||||
import path from "path";
|
||||
@@ -55,38 +55,38 @@ export class ZwaveControllerProvider extends ScryptedDeviceBase implements Devic
|
||||
let s2AccessControlKey = this.storage.getItem('s2AccessControlKey');
|
||||
let s2AuthenticatedKey = this.storage.getItem('s2AuthenticatedKey');
|
||||
let s2UnauthenticatedKey = this.storage.getItem('s2UnauthenticatedKey');
|
||||
|
||||
|
||||
// 1/17/2022: the network key was stored as base64, but for consistency with HA
|
||||
// and others, it was switched to hex. this is the data migration.
|
||||
if (!isHex(networkKey) && networkKey) {
|
||||
networkKey = Buffer.from(networkKey, 'base64').toString('hex');
|
||||
this.storage.setItem('networkKey', networkKey);
|
||||
}
|
||||
|
||||
|
||||
if (!networkKey) {
|
||||
networkKey = randomBytes(16).toString('hex').toUpperCase();
|
||||
this.storage.setItem('networkKey', networkKey);
|
||||
this.log.a('No Network Key was present, so a random one was generated. You can change the Network Key in Settings.')
|
||||
}
|
||||
|
||||
|
||||
if (!s2AccessControlKey) {
|
||||
s2AccessControlKey = randomBytes(16).toString('hex').toUpperCase();
|
||||
this.storage.setItem('s2AccessControlKey', s2AccessControlKey);
|
||||
this.log.a('No S2 Access Control Key was present, so a random one was generated. You can change the S2 Access Control Key in Settings.');
|
||||
}
|
||||
|
||||
|
||||
if (!s2AuthenticatedKey) {
|
||||
s2AuthenticatedKey = randomBytes(16).toString('hex').toUpperCase();
|
||||
this.storage.setItem('s2AuthenticatedKey', s2AuthenticatedKey);
|
||||
this.log.a('No S2 Authenticated Key was present, so a random one was generated. You can change the S2 Access Control Key in Settings.');
|
||||
this.log.a('No S2 Authenticated Key was present, so a random one was generated. You can change the S2 Access Control Key in Settings.');
|
||||
}
|
||||
|
||||
|
||||
if (!s2UnauthenticatedKey) {
|
||||
s2UnauthenticatedKey = randomBytes(16).toString('hex').toUpperCase();
|
||||
this.storage.setItem('s2UnauthenticatedKey', s2UnauthenticatedKey);
|
||||
this.log.a('No S2 Unauthenticated Key was present, so a random one was generated. You can change the S2 Unauthenticated Key in Settings.')
|
||||
}
|
||||
|
||||
|
||||
const cacheDir = path.join(process.env['SCRYPTED_PLUGIN_VOLUME'], 'cache');
|
||||
this.console.log(process.cwd());
|
||||
|
||||
@@ -103,12 +103,12 @@ export class ZwaveControllerProvider extends ScryptedDeviceBase implements Devic
|
||||
});
|
||||
this.driver = driver;
|
||||
console.log(driver.cacheDir);
|
||||
|
||||
|
||||
driver.on("error", (e) => {
|
||||
console.error('driver error', e);
|
||||
reject(e);
|
||||
});
|
||||
|
||||
|
||||
driver.once("driver ready", () => {
|
||||
this.controller = driver.controller;
|
||||
const rebuildNode = async (node: ZWaveNode) => {
|
||||
@@ -116,10 +116,15 @@ export class ZwaveControllerProvider extends ScryptedDeviceBase implements Devic
|
||||
await this.rebuildInstance(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const bindNode = (node: ZWaveNode) => {
|
||||
node.on('value added', node => rebuildNode(node));
|
||||
node.on('value removed', node => rebuildNode(node));
|
||||
node.on('value removed', node => {
|
||||
// node is being removed
|
||||
if (!this.controller.nodes.get(node.id))
|
||||
return;
|
||||
rebuildNode(node);
|
||||
});
|
||||
node.on('value updated', (node, valueId) => {
|
||||
const dirtyKey = getInstanceHash(this.controller.homeId, node.id, valueId.endpoint);
|
||||
const device: ZwaveDeviceBase = this.devices[dirtyKey];
|
||||
@@ -131,7 +136,7 @@ export class ZwaveControllerProvider extends ScryptedDeviceBase implements Devic
|
||||
});
|
||||
node.on('interview completed', node => rebuildNode(node));
|
||||
}
|
||||
|
||||
|
||||
this.controller.on('node added', node => {
|
||||
this.console.log('node added', node.nodeId);
|
||||
bindNode(node);
|
||||
@@ -140,7 +145,7 @@ export class ZwaveControllerProvider extends ScryptedDeviceBase implements Devic
|
||||
this.controller.on('node removed', node => {
|
||||
this.console.log('node removed', node?.nodeId);
|
||||
})
|
||||
|
||||
|
||||
driver.controller.nodes.forEach(node => {
|
||||
this.console.log('node loaded', node.nodeId);
|
||||
bindNode(node);
|
||||
@@ -191,10 +196,67 @@ export class ZwaveControllerProvider extends ScryptedDeviceBase implements Devic
|
||||
key: 's2UnauthenticatedKey',
|
||||
value: this.storage.getItem('s2UnauthenticatedKey'),
|
||||
description: 'The 16 byte hex encoded S2 Unauthenticated Key',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Include Device',
|
||||
key: 'inclusion',
|
||||
type: 'button',
|
||||
description: 'Enter inclusion mode and add devices.',
|
||||
},
|
||||
{
|
||||
title: 'Exclude Device',
|
||||
key: 'exclusion',
|
||||
type: 'button',
|
||||
description: 'Enter exclusion mode and remove devices.',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
async inclusion() {
|
||||
const userCallbacks: InclusionUserCallbacks = {
|
||||
grantSecurityClasses: async (requested: InclusionGrant): Promise<false | InclusionGrant> => {
|
||||
this.console.log('grantSecurityClasses');
|
||||
return requested;
|
||||
},
|
||||
validateDSKAndEnterPIN: async (dsk: string) => {
|
||||
this.console.error('validateDSKAndEnterPIN not implemented in zwave plugin');
|
||||
throw new Error("validateDSKAndEnterPIN Function not implemented.");
|
||||
},
|
||||
abort: function (): void {
|
||||
this.console.log('abort');
|
||||
}
|
||||
}
|
||||
await this.controller.stopExclusion();
|
||||
await this.controller.stopInclusion();
|
||||
const including = await this.driver.controller.beginInclusion({
|
||||
userCallbacks,
|
||||
strategy: InclusionStrategy.Default,
|
||||
});
|
||||
this.log.a('Including devices for 5 minutes.');
|
||||
this.console.log('including', including);
|
||||
|
||||
setTimeout(() => this.driver.controller.stopInclusion(), 300000);
|
||||
}
|
||||
|
||||
async exclusion() {
|
||||
await this.controller.stopExclusion();
|
||||
await this.controller.stopInclusion();
|
||||
const excluding = await this.driver.controller.beginExclusion();
|
||||
this.log.a('Excluding devices for 5 minutes.');
|
||||
this.console.log('excluding', excluding);
|
||||
setTimeout(() => this.driver.controller.stopExclusion(), 300000);
|
||||
}
|
||||
|
||||
async putSetting(key: string, value: string | number | boolean) {
|
||||
if (key === 'inclusion') {
|
||||
this.inclusion();
|
||||
return;
|
||||
}
|
||||
if (key === 'exclusion') {
|
||||
this.exclusion();
|
||||
return;
|
||||
}
|
||||
|
||||
this.storage.setItem(key, value as string);
|
||||
|
||||
await this.driver?.destroy();
|
||||
@@ -229,6 +291,9 @@ export class ZwaveControllerProvider extends ScryptedDeviceBase implements Devic
|
||||
async rebuildInstance(instance: Endpoint) {
|
||||
const nativeId = getHash(this.controller, instance);
|
||||
let scryptedDevice: ZwaveDeviceBase = this.devices[nativeId];
|
||||
if (this.controller.nodes.get(instance.nodeId).status === NodeStatus.Dead) {
|
||||
scryptedDevice.log.a('Node is dead.');
|
||||
}
|
||||
if (!scryptedDevice) {
|
||||
scryptedDevice = new ZwaveDeviceBase(this.controller, instance);
|
||||
scryptedDevice.zwaveController = this;
|
||||
|
||||
Reference in New Issue
Block a user