@zwave-js/nvmedit 13.3.0 → 13.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cli.js +6 -6
- package/build/cli.js.map +1 -1
- package/build/convert.d.ts +15 -14
- package/build/convert.d.ts.map +1 -1
- package/build/convert.js +647 -389
- package/build/convert.js.map +1 -1
- package/build/index.d.ts +12 -4
- package/build/index.d.ts.map +1 -1
- package/build/index.js +20 -2
- package/build/index.js.map +1 -1
- package/build/index_safe.d.ts +7 -4
- package/build/index_safe.d.ts.map +1 -1
- package/build/index_safe.js +4 -2
- package/build/index_safe.js.map +1 -1
- package/build/lib/NVM3.d.ts +53 -0
- package/build/lib/NVM3.d.ts.map +1 -0
- package/build/lib/NVM3.js +650 -0
- package/build/lib/NVM3.js.map +1 -0
- package/build/lib/NVM500.d.ts +46 -0
- package/build/lib/NVM500.d.ts.map +1 -0
- package/build/lib/NVM500.js +413 -0
- package/build/lib/NVM500.js.map +1 -0
- package/build/lib/common/definitions.d.ts +138 -0
- package/build/lib/common/definitions.d.ts.map +1 -0
- package/build/lib/common/definitions.js +11 -0
- package/build/lib/common/definitions.js.map +1 -0
- package/build/lib/common/routeCache.d.ts +18 -0
- package/build/lib/common/routeCache.d.ts.map +1 -0
- package/build/lib/common/routeCache.js +56 -0
- package/build/lib/common/routeCache.js.map +1 -0
- package/build/lib/common/sucUpdateEntry.d.ts +10 -0
- package/build/lib/common/sucUpdateEntry.d.ts.map +1 -0
- package/build/lib/common/sucUpdateEntry.js +35 -0
- package/build/lib/common/sucUpdateEntry.js.map +1 -0
- package/build/lib/common/utils.d.ts +9 -0
- package/build/lib/common/utils.d.ts.map +1 -0
- package/build/lib/common/utils.js +52 -0
- package/build/lib/common/utils.js.map +1 -0
- package/build/lib/io/BufferedNVMReader.d.ts +21 -0
- package/build/lib/io/BufferedNVMReader.d.ts.map +1 -0
- package/build/lib/io/BufferedNVMReader.js +79 -0
- package/build/lib/io/BufferedNVMReader.js.map +1 -0
- package/build/lib/io/NVMFileIO.d.ts +24 -0
- package/build/lib/io/NVMFileIO.d.ts.map +1 -0
- package/build/lib/io/NVMFileIO.js +86 -0
- package/build/lib/io/NVMFileIO.js.map +1 -0
- package/build/lib/io/NVMMemoryIO.d.ts +20 -0
- package/build/lib/io/NVMMemoryIO.d.ts.map +1 -0
- package/build/lib/io/NVMMemoryIO.js +48 -0
- package/build/lib/io/NVMMemoryIO.js.map +1 -0
- package/build/lib/nvm3/adapter.d.ts +33 -0
- package/build/lib/nvm3/adapter.d.ts.map +1 -0
- package/build/lib/nvm3/adapter.js +904 -0
- package/build/lib/nvm3/adapter.js.map +1 -0
- package/build/lib/nvm3/consts.d.ts.map +1 -0
- package/build/lib/nvm3/consts.js.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationCCsFile.d.ts +5 -3
- package/build/lib/nvm3/files/ApplicationCCsFile.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationCCsFile.js +4 -3
- package/build/lib/nvm3/files/ApplicationCCsFile.js.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationDataFile.d.ts +4 -4
- package/build/lib/nvm3/files/ApplicationDataFile.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationDataFile.js +7 -6
- package/build/lib/nvm3/files/ApplicationDataFile.js.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationNameFile.d.ts +5 -3
- package/build/lib/nvm3/files/ApplicationNameFile.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationNameFile.js +4 -3
- package/build/lib/nvm3/files/ApplicationNameFile.js.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationRFConfigFile.d.ts +5 -3
- package/build/lib/nvm3/files/ApplicationRFConfigFile.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationRFConfigFile.js +4 -3
- package/build/lib/nvm3/files/ApplicationRFConfigFile.js.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationTypeFile.d.ts +5 -3
- package/build/lib/nvm3/files/ApplicationTypeFile.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/ApplicationTypeFile.js +4 -3
- package/build/lib/nvm3/files/ApplicationTypeFile.js.map +1 -0
- package/build/{files → lib/nvm3/files}/ControllerInfoFile.d.ts +5 -3
- package/build/lib/nvm3/files/ControllerInfoFile.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/ControllerInfoFile.js +4 -3
- package/build/lib/nvm3/files/ControllerInfoFile.js.map +1 -0
- package/build/{files → lib/nvm3/files}/NVMFile.d.ts +18 -7
- package/build/lib/nvm3/files/NVMFile.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/NVMFile.js +45 -31
- package/build/lib/nvm3/files/NVMFile.js.map +1 -0
- package/build/{files → lib/nvm3/files}/NodeInfoFiles.d.ts +10 -4
- package/build/lib/nvm3/files/NodeInfoFiles.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/NodeInfoFiles.js +6 -3
- package/build/lib/nvm3/files/NodeInfoFiles.js.map +1 -0
- package/build/{files → lib/nvm3/files}/ProtocolNodeMaskFiles.d.ts +22 -15
- package/build/lib/nvm3/files/ProtocolNodeMaskFiles.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/ProtocolNodeMaskFiles.js +50 -30
- package/build/lib/nvm3/files/ProtocolNodeMaskFiles.js.map +1 -0
- package/build/{files → lib/nvm3/files}/RouteCacheFiles.d.ts +8 -17
- package/build/lib/nvm3/files/RouteCacheFiles.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/RouteCacheFiles.js +16 -64
- package/build/lib/nvm3/files/RouteCacheFiles.js.map +1 -0
- package/build/{files → lib/nvm3/files}/SUCUpdateEntriesFile.d.ts +10 -13
- package/build/lib/nvm3/files/SUCUpdateEntriesFile.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/SUCUpdateEntriesFile.js +15 -42
- package/build/lib/nvm3/files/SUCUpdateEntriesFile.js.map +1 -0
- package/build/{files → lib/nvm3/files}/VersionFiles.d.ts +7 -5
- package/build/lib/nvm3/files/VersionFiles.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/VersionFiles.js +10 -7
- package/build/lib/nvm3/files/VersionFiles.js.map +1 -0
- package/build/{files → lib/nvm3/files}/index.d.ts +1 -0
- package/build/lib/nvm3/files/index.d.ts.map +1 -0
- package/build/{files → lib/nvm3/files}/index.js +1 -0
- package/build/lib/nvm3/files/index.js.map +1 -0
- package/build/lib/nvm3/object.d.ts +29 -0
- package/build/lib/nvm3/object.d.ts.map +1 -0
- package/build/lib/nvm3/object.js +118 -0
- package/build/lib/nvm3/object.js.map +1 -0
- package/build/{nvm3 → lib/nvm3}/page.d.ts +1 -5
- package/build/lib/nvm3/page.d.ts.map +1 -0
- package/build/lib/nvm3/page.js +37 -0
- package/build/lib/nvm3/page.js.map +1 -0
- package/build/{nvm3 → lib/nvm3}/utils.d.ts +2 -4
- package/build/lib/nvm3/utils.d.ts.map +1 -0
- package/build/lib/nvm3/utils.js +143 -0
- package/build/lib/nvm3/utils.js.map +1 -0
- package/build/lib/nvm500/EntryParsers.d.ts.map +1 -0
- package/build/lib/nvm500/EntryParsers.js.map +1 -0
- package/build/lib/nvm500/adapter.d.ts +22 -0
- package/build/lib/nvm500/adapter.d.ts.map +1 -0
- package/build/lib/nvm500/adapter.js +371 -0
- package/build/lib/nvm500/adapter.js.map +1 -0
- package/build/lib/nvm500/impls/Bridge_6_6x.d.ts +3 -0
- package/build/lib/nvm500/impls/Bridge_6_6x.d.ts.map +1 -0
- package/build/{nvm500/parsers → lib/nvm500/impls}/Bridge_6_6x.js +1 -1
- package/build/lib/nvm500/impls/Bridge_6_6x.js.map +1 -0
- package/build/lib/nvm500/impls/Bridge_6_7x.d.ts +3 -0
- package/build/lib/nvm500/impls/Bridge_6_7x.d.ts.map +1 -0
- package/build/{nvm500/parsers → lib/nvm500/impls}/Bridge_6_7x.js +1 -1
- package/build/lib/nvm500/impls/Bridge_6_7x.js.map +1 -0
- package/build/lib/nvm500/impls/Bridge_6_8x.d.ts +3 -0
- package/build/lib/nvm500/impls/Bridge_6_8x.d.ts.map +1 -0
- package/build/{nvm500/parsers → lib/nvm500/impls}/Bridge_6_8x.js +1 -1
- package/build/lib/nvm500/impls/Bridge_6_8x.js.map +1 -0
- package/build/lib/nvm500/impls/Static_6_6x.d.ts +3 -0
- package/build/lib/nvm500/impls/Static_6_6x.d.ts.map +1 -0
- package/build/{nvm500/parsers → lib/nvm500/impls}/Static_6_6x.js +1 -1
- package/build/lib/nvm500/impls/Static_6_6x.js.map +1 -0
- package/build/lib/nvm500/impls/Static_6_7x.d.ts +3 -0
- package/build/lib/nvm500/impls/Static_6_7x.d.ts.map +1 -0
- package/build/{nvm500/parsers → lib/nvm500/impls}/Static_6_7x.js +1 -1
- package/build/lib/nvm500/impls/Static_6_7x.js.map +1 -0
- package/build/lib/nvm500/impls/Static_6_8x.d.ts +3 -0
- package/build/lib/nvm500/impls/Static_6_8x.d.ts.map +1 -0
- package/build/{nvm500/parsers → lib/nvm500/impls}/Static_6_8x.js +1 -1
- package/build/lib/nvm500/impls/Static_6_8x.js.map +1 -0
- package/build/lib/nvm500/impls/index.d.ts +2 -0
- package/build/lib/nvm500/impls/index.d.ts.map +1 -0
- package/build/lib/nvm500/impls/index.js +18 -0
- package/build/lib/nvm500/impls/index.js.map +1 -0
- package/build/{nvm500 → lib/nvm500}/shared.d.ts +19 -2
- package/build/lib/nvm500/shared.d.ts.map +1 -0
- package/build/{nvm500 → lib/nvm500}/shared.js +19 -1
- package/build/lib/nvm500/shared.js.map +1 -0
- package/build/nvm500/NVMParser.d.ts +5 -36
- package/build/nvm500/NVMParser.d.ts.map +1 -1
- package/build/nvm500/NVMParser.js +0 -524
- package/build/nvm500/NVMParser.js.map +1 -1
- package/package.json +6 -6
- package/build/files/ApplicationCCsFile.d.ts.map +0 -1
- package/build/files/ApplicationCCsFile.js.map +0 -1
- package/build/files/ApplicationDataFile.d.ts.map +0 -1
- package/build/files/ApplicationDataFile.js.map +0 -1
- package/build/files/ApplicationNameFile.d.ts.map +0 -1
- package/build/files/ApplicationNameFile.js.map +0 -1
- package/build/files/ApplicationRFConfigFile.d.ts.map +0 -1
- package/build/files/ApplicationRFConfigFile.js.map +0 -1
- package/build/files/ApplicationTypeFile.d.ts.map +0 -1
- package/build/files/ApplicationTypeFile.js.map +0 -1
- package/build/files/ControllerInfoFile.d.ts.map +0 -1
- package/build/files/ControllerInfoFile.js.map +0 -1
- package/build/files/NVMFile.d.ts.map +0 -1
- package/build/files/NVMFile.js.map +0 -1
- package/build/files/NodeInfoFiles.d.ts.map +0 -1
- package/build/files/NodeInfoFiles.js.map +0 -1
- package/build/files/ProtocolNodeMaskFiles.d.ts.map +0 -1
- package/build/files/ProtocolNodeMaskFiles.js.map +0 -1
- package/build/files/RouteCacheFiles.d.ts.map +0 -1
- package/build/files/RouteCacheFiles.js.map +0 -1
- package/build/files/SUCUpdateEntriesFile.d.ts.map +0 -1
- package/build/files/SUCUpdateEntriesFile.js.map +0 -1
- package/build/files/VersionFiles.d.ts.map +0 -1
- package/build/files/VersionFiles.js.map +0 -1
- package/build/files/index.d.ts.map +0 -1
- package/build/files/index.js.map +0 -1
- package/build/nvm3/consts.d.ts.map +0 -1
- package/build/nvm3/consts.js.map +0 -1
- package/build/nvm3/nvm.d.ts +0 -31
- package/build/nvm3/nvm.d.ts.map +0 -1
- package/build/nvm3/nvm.js +0 -184
- package/build/nvm3/nvm.js.map +0 -1
- package/build/nvm3/object.d.ts +0 -25
- package/build/nvm3/object.d.ts.map +0 -1
- package/build/nvm3/object.js +0 -197
- package/build/nvm3/object.js.map +0 -1
- package/build/nvm3/page.d.ts.map +0 -1
- package/build/nvm3/page.js +0 -129
- package/build/nvm3/page.js.map +0 -1
- package/build/nvm3/utils.d.ts.map +0 -1
- package/build/nvm3/utils.js +0 -103
- package/build/nvm3/utils.js.map +0 -1
- package/build/nvm500/EntryParsers.d.ts.map +0 -1
- package/build/nvm500/EntryParsers.js.map +0 -1
- package/build/nvm500/parsers/Bridge_6_6x.d.ts +0 -3
- package/build/nvm500/parsers/Bridge_6_6x.d.ts.map +0 -1
- package/build/nvm500/parsers/Bridge_6_6x.js.map +0 -1
- package/build/nvm500/parsers/Bridge_6_7x.d.ts +0 -3
- package/build/nvm500/parsers/Bridge_6_7x.d.ts.map +0 -1
- package/build/nvm500/parsers/Bridge_6_7x.js.map +0 -1
- package/build/nvm500/parsers/Bridge_6_8x.d.ts +0 -3
- package/build/nvm500/parsers/Bridge_6_8x.d.ts.map +0 -1
- package/build/nvm500/parsers/Bridge_6_8x.js.map +0 -1
- package/build/nvm500/parsers/Static_6_6x.d.ts +0 -3
- package/build/nvm500/parsers/Static_6_6x.d.ts.map +0 -1
- package/build/nvm500/parsers/Static_6_6x.js.map +0 -1
- package/build/nvm500/parsers/Static_6_7x.d.ts +0 -3
- package/build/nvm500/parsers/Static_6_7x.d.ts.map +0 -1
- package/build/nvm500/parsers/Static_6_7x.js.map +0 -1
- package/build/nvm500/parsers/Static_6_8x.d.ts +0 -3
- package/build/nvm500/parsers/Static_6_8x.d.ts.map +0 -1
- package/build/nvm500/parsers/Static_6_8x.js.map +0 -1
- package/build/nvm500/shared.d.ts.map +0 -1
- package/build/nvm500/shared.js.map +0 -1
- package/build/shared.d.ts +0 -2
- package/build/shared.d.ts.map +0 -1
- package/build/shared.js +0 -3
- package/build/shared.js.map +0 -1
- /package/build/{nvm3 → lib/nvm3}/consts.d.ts +0 -0
- /package/build/{nvm3 → lib/nvm3}/consts.js +0 -0
- /package/build/{nvm500 → lib/nvm500}/EntryParsers.d.ts +0 -0
- /package/build/{nvm500 → lib/nvm500}/EntryParsers.js +0 -0
package/build/convert.js
CHANGED
|
@@ -5,8 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.nodeHasInfo = nodeHasInfo;
|
|
7
7
|
exports.nvmObjectsToJSON = nvmObjectsToJSON;
|
|
8
|
-
exports.jsonToNVMObjects_v7_0_0 = jsonToNVMObjects_v7_0_0;
|
|
9
|
-
exports.jsonToNVMObjects_v7_11_0 = jsonToNVMObjects_v7_11_0;
|
|
10
8
|
exports.nvmToJSON = nvmToJSON;
|
|
11
9
|
exports.nvm500ToJSON = nvm500ToJSON;
|
|
12
10
|
exports.jsonToNVM = jsonToNVM;
|
|
@@ -19,11 +17,18 @@ const safe_2 = require("@zwave-js/shared/safe");
|
|
|
19
17
|
const typeguards_1 = require("alcalzone-shared/typeguards");
|
|
20
18
|
const semver_1 = __importDefault(require("semver"));
|
|
21
19
|
const consts_1 = require("./consts");
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
20
|
+
const NVM3_1 = require("./lib/NVM3");
|
|
21
|
+
const NVM500_1 = require("./lib/NVM500");
|
|
22
|
+
const routeCache_1 = require("./lib/common/routeCache");
|
|
23
|
+
const NVMMemoryIO_1 = require("./lib/io/NVMMemoryIO");
|
|
24
|
+
const adapter_1 = require("./lib/nvm3/adapter");
|
|
25
|
+
const consts_2 = require("./lib/nvm3/consts");
|
|
26
|
+
const files_1 = require("./lib/nvm3/files");
|
|
27
|
+
const ApplicationNameFile_1 = require("./lib/nvm3/files/ApplicationNameFile");
|
|
28
|
+
const utils_1 = require("./lib/nvm3/utils");
|
|
29
|
+
const adapter_2 = require("./lib/nvm500/adapter");
|
|
30
|
+
const impls_1 = require("./lib/nvm500/impls");
|
|
31
|
+
const shared_1 = require("./lib/nvm500/shared");
|
|
27
32
|
function nodeHasInfo(node) {
|
|
28
33
|
return !node.isVirtual || Object.keys(node).length > 1;
|
|
29
34
|
}
|
|
@@ -99,13 +104,13 @@ function nvmObjectsToJSON(objects) {
|
|
|
99
104
|
};
|
|
100
105
|
const getFileOrThrow = (id, fileVersion) => {
|
|
101
106
|
const obj = getObjectOrThrow(id);
|
|
102
|
-
return files_1.NVMFile.from(obj, fileVersion);
|
|
107
|
+
return files_1.NVMFile.from(obj.key, obj.data, fileVersion);
|
|
103
108
|
};
|
|
104
109
|
const getFile = (id, fileVersion) => {
|
|
105
110
|
const obj = getObject(id);
|
|
106
|
-
if (!obj)
|
|
111
|
+
if (!obj || !obj.data)
|
|
107
112
|
return undefined;
|
|
108
|
-
return files_1.NVMFile.from(obj, fileVersion);
|
|
113
|
+
return files_1.NVMFile.from(obj.key, obj.data, fileVersion);
|
|
109
114
|
};
|
|
110
115
|
// === Protocol NVM files ===
|
|
111
116
|
// Figure out how to parse the individual files
|
|
@@ -270,7 +275,8 @@ function nvmObjectsToJSON(objects) {
|
|
|
270
275
|
}
|
|
271
276
|
: {}),
|
|
272
277
|
sucUpdateEntries,
|
|
273
|
-
applicationData: applicationDataFile?.
|
|
278
|
+
applicationData: applicationDataFile?.applicationData.toString("hex")
|
|
279
|
+
?? null,
|
|
274
280
|
applicationName: applicationNameFile?.name ?? null,
|
|
275
281
|
};
|
|
276
282
|
// Make sure all props are defined
|
|
@@ -366,223 +372,439 @@ function nvmJSONControllerToFileOptions(ctrlr) {
|
|
|
366
372
|
}
|
|
367
373
|
return ret;
|
|
368
374
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
375
|
+
/** Reads an NVM buffer of a 700+ series stick and returns its JSON representation */
|
|
376
|
+
async function nvmToJSON(buffer, debugLogs = false) {
|
|
377
|
+
const io = new NVMMemoryIO_1.NVMMemoryIO(buffer);
|
|
378
|
+
const nvm3 = new NVM3_1.NVM3(io);
|
|
379
|
+
const info = await nvm3.init();
|
|
380
|
+
const adapter = new adapter_1.NVM3Adapter(nvm3);
|
|
381
|
+
if (debugLogs) {
|
|
382
|
+
// Dump all pages, all raw objects in each page, and each object in its final state
|
|
383
|
+
await (0, utils_1.dumpNVM)(nvm3);
|
|
384
|
+
}
|
|
385
|
+
const firstPageHeader = info.isSharedFileSystem
|
|
386
|
+
? info.sections.all.pages[0]
|
|
387
|
+
: info.sections.protocol.pages[0];
|
|
388
|
+
const meta = {
|
|
389
|
+
sharedFileSystem: info.isSharedFileSystem,
|
|
390
|
+
...(0, safe_2.pick)(firstPageHeader, [
|
|
391
|
+
"pageSize",
|
|
392
|
+
"writeSize",
|
|
393
|
+
"memoryMapped",
|
|
394
|
+
"deviceFamily",
|
|
395
|
+
]),
|
|
396
|
+
};
|
|
397
|
+
const nodes = new Map();
|
|
398
|
+
const getNode = (id) => {
|
|
399
|
+
if (!nodes.has(id))
|
|
400
|
+
nodes.set(id, createEmptyPhysicalNode());
|
|
401
|
+
return nodes.get(id);
|
|
402
|
+
};
|
|
403
|
+
const lrNodes = new Map();
|
|
404
|
+
const getLRNode = (id) => {
|
|
405
|
+
if (!lrNodes.has(id))
|
|
406
|
+
lrNodes.set(id, createEmptyLRNode());
|
|
407
|
+
return lrNodes.get(id);
|
|
408
|
+
};
|
|
409
|
+
const protocolFileFormat = await adapter.get({
|
|
410
|
+
domain: "controller",
|
|
411
|
+
type: "protocolFileFormat",
|
|
412
|
+
}, true);
|
|
413
|
+
// Bail early if the NVM uses a protocol file format that's newer than we support
|
|
414
|
+
if (protocolFileFormat > consts_1.MAX_PROTOCOL_FILE_FORMAT) {
|
|
415
|
+
throw new safe_1.ZWaveError(`Unsupported protocol file format: ${protocolFileFormat}`, safe_1.ZWaveErrorCodes.NVM_NotSupported, { protocolFileFormat });
|
|
416
|
+
}
|
|
417
|
+
const protocolVersion = await adapter.get({
|
|
418
|
+
domain: "controller",
|
|
419
|
+
type: "protocolVersion",
|
|
420
|
+
}, true);
|
|
421
|
+
// Read all flags for all nodes
|
|
422
|
+
const appRouteLock = new Set(await adapter.get({
|
|
423
|
+
domain: "controller",
|
|
424
|
+
type: "appRouteLock",
|
|
425
|
+
}, true));
|
|
426
|
+
const routeSlaveSUC = new Set(await adapter.get({
|
|
427
|
+
domain: "controller",
|
|
428
|
+
type: "routeSlaveSUC",
|
|
429
|
+
}, true));
|
|
430
|
+
const sucPendingUpdate = new Set(await adapter.get({
|
|
431
|
+
domain: "controller",
|
|
432
|
+
type: "sucPendingUpdate",
|
|
433
|
+
}, true));
|
|
434
|
+
const virtualNodeIds = new Set(await adapter.get({
|
|
435
|
+
domain: "controller",
|
|
436
|
+
type: "virtualNodeIds",
|
|
437
|
+
}, true));
|
|
438
|
+
const pendingDiscovery = new Set(await adapter.get({
|
|
439
|
+
domain: "controller",
|
|
440
|
+
type: "pendingDiscovery",
|
|
441
|
+
}, true));
|
|
442
|
+
// Figure out which nodes exist
|
|
443
|
+
const nodeIds = await adapter.get({
|
|
444
|
+
domain: "controller",
|
|
445
|
+
type: "nodeIds",
|
|
446
|
+
}, true);
|
|
447
|
+
// And create each node entry, including virtual ones
|
|
448
|
+
for (const id of nodeIds) {
|
|
449
|
+
const node = getNode(id);
|
|
450
|
+
// Find node info
|
|
451
|
+
const nodeInfo = await adapter.get({
|
|
452
|
+
domain: "node",
|
|
453
|
+
nodeId: id,
|
|
454
|
+
type: "info",
|
|
455
|
+
}, true);
|
|
456
|
+
Object.assign(node, nodeInfo);
|
|
457
|
+
// Evaluate flags
|
|
458
|
+
node.isVirtual = virtualNodeIds.has(id);
|
|
459
|
+
node.appRouteLock = appRouteLock.has(id);
|
|
460
|
+
node.routeSlaveSUC = routeSlaveSUC.has(id);
|
|
461
|
+
node.sucPendingUpdate = sucPendingUpdate.has(id);
|
|
462
|
+
node.pendingDiscovery = pendingDiscovery.has(id);
|
|
463
|
+
const routes = await adapter.get({
|
|
464
|
+
domain: "node",
|
|
465
|
+
nodeId: id,
|
|
466
|
+
type: "routes",
|
|
467
|
+
});
|
|
468
|
+
if (routes) {
|
|
469
|
+
node.lwr = routes.lwr;
|
|
470
|
+
node.nlwr = routes.nlwr;
|
|
471
|
+
}
|
|
472
|
+
// @ts-expect-error Some fields include a nodeId, but we don't need it
|
|
473
|
+
delete node.nodeId;
|
|
474
|
+
}
|
|
475
|
+
// If they exist, read info about LR nodes
|
|
476
|
+
const lrNodeIds = await adapter.get({
|
|
477
|
+
domain: "controller",
|
|
478
|
+
type: "lrNodeIds",
|
|
479
|
+
});
|
|
480
|
+
if (lrNodeIds) {
|
|
481
|
+
for (const id of lrNodeIds) {
|
|
482
|
+
const node = getLRNode(id);
|
|
483
|
+
// Find node info
|
|
484
|
+
const nodeInfo = await adapter.get({
|
|
485
|
+
domain: "lrnode",
|
|
486
|
+
nodeId: id,
|
|
487
|
+
type: "info",
|
|
488
|
+
}, true);
|
|
489
|
+
Object.assign(node, nodeInfo);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
// Read info about the controller
|
|
493
|
+
const sucUpdateEntries = await adapter.get({
|
|
494
|
+
domain: "controller",
|
|
495
|
+
type: "sucUpdateEntries",
|
|
496
|
+
}, true);
|
|
497
|
+
const applicationVersion = await adapter.get({
|
|
498
|
+
domain: "controller",
|
|
499
|
+
type: "applicationVersion",
|
|
500
|
+
}, true);
|
|
501
|
+
const applicationFileFormat = await adapter.get({
|
|
502
|
+
domain: "controller",
|
|
503
|
+
type: "applicationFileFormat",
|
|
504
|
+
}, true);
|
|
505
|
+
const applicationData = await adapter.get({
|
|
506
|
+
domain: "controller",
|
|
507
|
+
type: "applicationData",
|
|
508
|
+
});
|
|
509
|
+
const applicationName = await adapter.get({
|
|
510
|
+
domain: "controller",
|
|
511
|
+
type: "applicationName",
|
|
512
|
+
});
|
|
513
|
+
const preferredRepeaters = await adapter.get({
|
|
514
|
+
domain: "controller",
|
|
515
|
+
type: "preferredRepeaters",
|
|
516
|
+
});
|
|
517
|
+
// The following are a bit awkward to read one by one, so we just take the files
|
|
518
|
+
const controllerInfoFile = await adapter.getFile(files_1.ControllerInfoFileID, true);
|
|
519
|
+
const rfConfigFile = await adapter.getFile(files_1.ApplicationRFConfigFileID);
|
|
520
|
+
const applicationCCsFile = await adapter.getFile(files_1.ApplicationCCsFileID, true);
|
|
521
|
+
const applicationTypeFile = await adapter.getFile(files_1.ApplicationTypeFileID, true);
|
|
522
|
+
const controller = {
|
|
523
|
+
protocolVersion,
|
|
524
|
+
applicationVersion,
|
|
525
|
+
homeId: `0x${controllerInfoFile.homeId.toString("hex")}`,
|
|
526
|
+
...(0, safe_2.pick)(controllerInfoFile, [
|
|
527
|
+
"nodeId",
|
|
528
|
+
"lastNodeId",
|
|
529
|
+
"staticControllerNodeId",
|
|
530
|
+
"sucLastIndex",
|
|
531
|
+
"controllerConfiguration",
|
|
532
|
+
"sucAwarenessPushNeeded",
|
|
533
|
+
"maxNodeId",
|
|
534
|
+
"reservedId",
|
|
535
|
+
"systemState",
|
|
536
|
+
"lastNodeIdLR",
|
|
537
|
+
"maxNodeIdLR",
|
|
538
|
+
"reservedIdLR",
|
|
539
|
+
"primaryLongRangeChannelId",
|
|
540
|
+
"dcdcConfig",
|
|
541
|
+
]),
|
|
542
|
+
...(0, safe_2.pick)(applicationTypeFile, [
|
|
373
543
|
"isListening",
|
|
374
544
|
"optionalFunctionality",
|
|
375
545
|
"genericDeviceClass",
|
|
376
546
|
"specificDeviceClass",
|
|
377
547
|
]),
|
|
378
|
-
|
|
379
|
-
});
|
|
380
|
-
ret.push(applTypeFile.serialize());
|
|
381
|
-
const applCCsFile = new files_1.ApplicationCCsFile({
|
|
382
|
-
...(0, safe_2.pick)(nvm.controller.commandClasses, [
|
|
548
|
+
commandClasses: (0, safe_2.pick)(applicationCCsFile, [
|
|
383
549
|
"includedInsecurely",
|
|
384
550
|
"includedSecurelyInsecureCCs",
|
|
385
551
|
"includedSecurelySecureCCs",
|
|
386
552
|
]),
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
return ret;
|
|
421
|
-
}
|
|
422
|
-
function serializeCommonProtocolObjects(nvm) {
|
|
423
|
-
const ret = [];
|
|
424
|
-
const appRouteLock = new Set();
|
|
425
|
-
const routeSlaveSUC = new Set();
|
|
426
|
-
const sucPendingUpdate = new Set();
|
|
427
|
-
const isVirtual = new Set();
|
|
428
|
-
const pendingDiscovery = new Set();
|
|
429
|
-
for (const [id, node] of Object.entries(nvm.nodes)) {
|
|
430
|
-
const nodeId = parseInt(id);
|
|
431
|
-
if (!nodeHasInfo(node)) {
|
|
432
|
-
isVirtual.add(nodeId);
|
|
433
|
-
continue;
|
|
434
|
-
}
|
|
435
|
-
else {
|
|
436
|
-
if (node.isVirtual)
|
|
437
|
-
isVirtual.add(nodeId);
|
|
438
|
-
if (node.appRouteLock)
|
|
439
|
-
appRouteLock.add(nodeId);
|
|
440
|
-
if (node.routeSlaveSUC)
|
|
441
|
-
routeSlaveSUC.add(nodeId);
|
|
442
|
-
if (node.sucPendingUpdate)
|
|
443
|
-
sucPendingUpdate.add(nodeId);
|
|
444
|
-
if (node.pendingDiscovery)
|
|
445
|
-
pendingDiscovery.add(nodeId);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
ret.push(new files_1.ControllerInfoFile(nvmJSONControllerToFileOptions(nvm.controller)).serialize());
|
|
449
|
-
ret.push(new files_1.ProtocolAppRouteLockNodeMaskFile({
|
|
450
|
-
nodeIds: [...appRouteLock],
|
|
451
|
-
fileVersion: nvm.controller.protocolVersion,
|
|
452
|
-
}).serialize());
|
|
453
|
-
ret.push(new files_1.ProtocolRouteSlaveSUCNodeMaskFile({
|
|
454
|
-
nodeIds: [...routeSlaveSUC],
|
|
455
|
-
fileVersion: nvm.controller.protocolVersion,
|
|
456
|
-
}).serialize());
|
|
457
|
-
ret.push(new files_1.ProtocolSUCPendingUpdateNodeMaskFile({
|
|
458
|
-
nodeIds: [...sucPendingUpdate],
|
|
459
|
-
fileVersion: nvm.controller.protocolVersion,
|
|
460
|
-
}).serialize());
|
|
461
|
-
ret.push(new files_1.ProtocolVirtualNodeMaskFile({
|
|
462
|
-
nodeIds: [...isVirtual],
|
|
463
|
-
fileVersion: nvm.controller.protocolVersion,
|
|
464
|
-
}).serialize());
|
|
465
|
-
ret.push(new files_1.ProtocolPendingDiscoveryNodeMaskFile({
|
|
466
|
-
nodeIds: [...pendingDiscovery],
|
|
467
|
-
fileVersion: nvm.controller.protocolVersion,
|
|
468
|
-
}).serialize());
|
|
469
|
-
// TODO: format >= 2: { .key = FILE_ID_LRANGE_NODE_EXIST, .size = FILE_SIZE_LRANGE_NODE_EXIST, .name = "LRANGE_NODE_EXIST"},
|
|
470
|
-
if (nvm.controller.preferredRepeaters?.length) {
|
|
471
|
-
ret.push(new files_1.ProtocolPreferredRepeatersFile({
|
|
472
|
-
nodeIds: nvm.controller.preferredRepeaters,
|
|
473
|
-
fileVersion: nvm.controller.protocolVersion,
|
|
474
|
-
}).serialize());
|
|
553
|
+
preferredRepeaters,
|
|
554
|
+
...(rfConfigFile
|
|
555
|
+
? {
|
|
556
|
+
rfConfig: {
|
|
557
|
+
rfRegion: rfConfigFile.rfRegion,
|
|
558
|
+
txPower: rfConfigFile.txPower,
|
|
559
|
+
measured0dBm: rfConfigFile.measured0dBm,
|
|
560
|
+
enablePTI: rfConfigFile.enablePTI ?? null,
|
|
561
|
+
maxTXPower: rfConfigFile.maxTXPower ?? null,
|
|
562
|
+
nodeIdType: rfConfigFile.nodeIdType ?? null,
|
|
563
|
+
},
|
|
564
|
+
}
|
|
565
|
+
: {}),
|
|
566
|
+
sucUpdateEntries,
|
|
567
|
+
applicationData: applicationData?.toString("hex") ?? null,
|
|
568
|
+
applicationName: applicationName ?? null,
|
|
569
|
+
};
|
|
570
|
+
// Make sure all props are defined
|
|
571
|
+
const optionalControllerProps = [
|
|
572
|
+
"sucAwarenessPushNeeded",
|
|
573
|
+
"lastNodeIdLR",
|
|
574
|
+
"maxNodeIdLR",
|
|
575
|
+
"reservedIdLR",
|
|
576
|
+
"primaryLongRangeChannelId",
|
|
577
|
+
"dcdcConfig",
|
|
578
|
+
"rfConfig",
|
|
579
|
+
"preferredRepeaters",
|
|
580
|
+
"applicationData",
|
|
581
|
+
];
|
|
582
|
+
for (const prop of optionalControllerProps) {
|
|
583
|
+
if (controller[prop] === undefined)
|
|
584
|
+
controller[prop] = null;
|
|
475
585
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
586
|
+
const ret = {
|
|
587
|
+
format: protocolFileFormat,
|
|
588
|
+
controller,
|
|
589
|
+
nodes: (0, utils_1.mapToObject)(nodes),
|
|
590
|
+
meta,
|
|
591
|
+
};
|
|
592
|
+
if (applicationFileFormat !== 0) {
|
|
593
|
+
ret.applicationFileFormat = applicationFileFormat;
|
|
481
594
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
for (let index = 0; index < consts_1.SUC_MAX_UPDATES; index += files_1.SUC_UPDATES_PER_FILE_V5) {
|
|
485
|
-
const slice = nvm.controller.sucUpdateEntries.slice(index, index + files_1.SUC_UPDATES_PER_FILE_V5);
|
|
486
|
-
if (slice.length === 0)
|
|
487
|
-
break;
|
|
488
|
-
const file = new files_1.SUCUpdateEntriesFileV5({
|
|
489
|
-
updateEntries: slice,
|
|
490
|
-
fileVersion: nvm.controller.protocolVersion,
|
|
491
|
-
});
|
|
492
|
-
file.fileId = (0, files_1.sucUpdateIndexToSUCUpdateEntriesFileIDV5)(index);
|
|
493
|
-
ret.push(file.serialize());
|
|
494
|
-
}
|
|
595
|
+
if (lrNodes.size > 0) {
|
|
596
|
+
ret.lrNodes = (0, utils_1.mapToObject)(lrNodes);
|
|
495
597
|
}
|
|
496
598
|
return ret;
|
|
497
599
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
for (const o of objects) {
|
|
512
|
-
protocolObjects.set(o.key, o);
|
|
513
|
-
}
|
|
600
|
+
/** Reads an NVM buffer of a 500-series stick and returns its JSON representation */
|
|
601
|
+
async function nvm500ToJSON(buffer) {
|
|
602
|
+
const io = new NVMMemoryIO_1.NVMMemoryIO(buffer);
|
|
603
|
+
const nvm = new NVM500_1.NVM500(io);
|
|
604
|
+
const info = await nvm.init();
|
|
605
|
+
const meta = {
|
|
606
|
+
library: info.library,
|
|
607
|
+
...(0, safe_2.pick)(info.nvmDescriptor, [
|
|
608
|
+
"manufacturerID",
|
|
609
|
+
"firmwareID",
|
|
610
|
+
"productType",
|
|
611
|
+
"productID",
|
|
612
|
+
]),
|
|
514
613
|
};
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
for (
|
|
540
|
-
const
|
|
541
|
-
|
|
614
|
+
const adapter = new adapter_2.NVM500Adapter(nvm);
|
|
615
|
+
// Read all flags for all nodes
|
|
616
|
+
const appRouteLock = new Set(await adapter.get({
|
|
617
|
+
domain: "controller",
|
|
618
|
+
type: "appRouteLock",
|
|
619
|
+
}, true));
|
|
620
|
+
const routeSlaveSUC = new Set(await adapter.get({
|
|
621
|
+
domain: "controller",
|
|
622
|
+
type: "routeSlaveSUC",
|
|
623
|
+
}, true));
|
|
624
|
+
const sucPendingUpdate = new Set(await adapter.get({
|
|
625
|
+
domain: "controller",
|
|
626
|
+
type: "sucPendingUpdate",
|
|
627
|
+
}, true));
|
|
628
|
+
const virtualNodeIds = new Set(await adapter.get({
|
|
629
|
+
domain: "controller",
|
|
630
|
+
type: "virtualNodeIds",
|
|
631
|
+
}) ?? []);
|
|
632
|
+
const pendingDiscovery = new Set(await adapter.get({
|
|
633
|
+
domain: "controller",
|
|
634
|
+
type: "pendingDiscovery",
|
|
635
|
+
}, true));
|
|
636
|
+
// Figure out which nodes exist along with their info
|
|
637
|
+
const nodes = {};
|
|
638
|
+
for (let nodeId = 1; nodeId <= safe_1.MAX_NODES; nodeId++) {
|
|
639
|
+
const nodeInfo = await adapter.get({
|
|
640
|
+
domain: "node",
|
|
641
|
+
nodeId,
|
|
642
|
+
type: "info",
|
|
643
|
+
});
|
|
644
|
+
const isVirtual = virtualNodeIds.has(nodeId);
|
|
645
|
+
if (!nodeInfo) {
|
|
646
|
+
if (isVirtual) {
|
|
647
|
+
nodes[nodeId] = { isVirtual: true };
|
|
648
|
+
}
|
|
542
649
|
continue;
|
|
543
|
-
nodeInfoExists.add(nodeId);
|
|
544
|
-
// Create/update node info file
|
|
545
|
-
const nodeInfoFileIndex = (0, files_1.nodeIdToNodeInfoFileIDV0)(nodeId);
|
|
546
|
-
nodeInfoFiles.set(nodeInfoFileIndex, new files_1.NodeInfoFileV0({
|
|
547
|
-
nodeInfo: nvmJSONNodeToNodeInfo(nodeId, node),
|
|
548
|
-
fileVersion: target.controller.protocolVersion,
|
|
549
|
-
}));
|
|
550
|
-
// Create/update route cache file (if there is a route)
|
|
551
|
-
if (node.lwr || node.nlwr) {
|
|
552
|
-
routeCacheExists.add(nodeId);
|
|
553
|
-
const routeCacheFileIndex = (0, files_1.nodeIdToRouteCacheFileIDV0)(nodeId);
|
|
554
|
-
routeCacheFiles.set(routeCacheFileIndex, new files_1.RouteCacheFileV0({
|
|
555
|
-
routeCache: {
|
|
556
|
-
nodeId,
|
|
557
|
-
lwr: node.lwr ?? (0, files_1.getEmptyRoute)(),
|
|
558
|
-
nlwr: node.nlwr ?? (0, files_1.getEmptyRoute)(),
|
|
559
|
-
},
|
|
560
|
-
fileVersion: target.controller.protocolVersion,
|
|
561
|
-
}));
|
|
562
650
|
}
|
|
651
|
+
const routes = await adapter.get({
|
|
652
|
+
domain: "node",
|
|
653
|
+
nodeId,
|
|
654
|
+
type: "routes",
|
|
655
|
+
});
|
|
656
|
+
// @ts-expect-error Some fields include a nodeId, but we don't need it
|
|
657
|
+
delete nodeInfo.nodeId;
|
|
658
|
+
nodes[nodeId] = {
|
|
659
|
+
...nodeInfo,
|
|
660
|
+
specificDeviceClass: nodeInfo.specificDeviceClass ?? null,
|
|
661
|
+
isVirtual,
|
|
662
|
+
appRouteLock: appRouteLock.has(nodeId),
|
|
663
|
+
routeSlaveSUC: routeSlaveSUC.has(nodeId),
|
|
664
|
+
sucPendingUpdate: sucPendingUpdate.has(nodeId),
|
|
665
|
+
pendingDiscovery: pendingDiscovery.has(nodeId),
|
|
666
|
+
lwr: routes?.lwr ?? null,
|
|
667
|
+
nlwr: routes?.nlwr ?? null,
|
|
668
|
+
};
|
|
563
669
|
}
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
})
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
})
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
670
|
+
// Read info about the controller
|
|
671
|
+
const ownNodeId = await adapter.get({
|
|
672
|
+
domain: "controller",
|
|
673
|
+
type: "nodeId",
|
|
674
|
+
}, true);
|
|
675
|
+
const ownHomeId = await adapter.get({
|
|
676
|
+
domain: "controller",
|
|
677
|
+
type: "homeId",
|
|
678
|
+
}, true);
|
|
679
|
+
let learnedHomeId = await adapter.get({
|
|
680
|
+
domain: "controller",
|
|
681
|
+
type: "learnedHomeId",
|
|
682
|
+
});
|
|
683
|
+
if (learnedHomeId?.equals(Buffer.alloc(4, 0))) {
|
|
684
|
+
learnedHomeId = undefined;
|
|
578
685
|
}
|
|
686
|
+
const lastNodeId = await adapter.get({
|
|
687
|
+
domain: "controller",
|
|
688
|
+
type: "lastNodeId",
|
|
689
|
+
}, true);
|
|
690
|
+
const maxNodeId = await adapter.get({
|
|
691
|
+
domain: "controller",
|
|
692
|
+
type: "maxNodeId",
|
|
693
|
+
}, true);
|
|
694
|
+
const reservedId = await adapter.get({
|
|
695
|
+
domain: "controller",
|
|
696
|
+
type: "reservedId",
|
|
697
|
+
}, true);
|
|
698
|
+
const staticControllerNodeId = await adapter.get({
|
|
699
|
+
domain: "controller",
|
|
700
|
+
type: "staticControllerNodeId",
|
|
701
|
+
}, true);
|
|
702
|
+
const sucLastIndex = await adapter.get({
|
|
703
|
+
domain: "controller",
|
|
704
|
+
type: "sucLastIndex",
|
|
705
|
+
}, true);
|
|
706
|
+
const controllerConfiguration = await adapter.get({
|
|
707
|
+
domain: "controller",
|
|
708
|
+
type: "controllerConfiguration",
|
|
709
|
+
}, true);
|
|
710
|
+
const commandClasses = await adapter.get({
|
|
711
|
+
domain: "controller",
|
|
712
|
+
type: "commandClasses",
|
|
713
|
+
}, true);
|
|
714
|
+
const sucUpdateEntries = await adapter.get({
|
|
715
|
+
domain: "controller",
|
|
716
|
+
type: "sucUpdateEntries",
|
|
717
|
+
}, true);
|
|
718
|
+
const applicationData = await adapter.get({
|
|
719
|
+
domain: "controller",
|
|
720
|
+
type: "applicationData",
|
|
721
|
+
});
|
|
722
|
+
const preferredRepeaters = await adapter.get({
|
|
723
|
+
domain: "controller",
|
|
724
|
+
type: "preferredRepeaters",
|
|
725
|
+
}, true);
|
|
726
|
+
const systemState = await adapter.get({
|
|
727
|
+
domain: "controller",
|
|
728
|
+
type: "systemState",
|
|
729
|
+
}, true);
|
|
730
|
+
const watchdogStarted = await adapter.get({
|
|
731
|
+
domain: "controller",
|
|
732
|
+
type: "watchdogStarted",
|
|
733
|
+
}, true);
|
|
734
|
+
const powerLevelNormal = await adapter.get({
|
|
735
|
+
domain: "controller",
|
|
736
|
+
type: "powerLevelNormal",
|
|
737
|
+
}, true);
|
|
738
|
+
const powerLevelLow = await adapter.get({
|
|
739
|
+
domain: "controller",
|
|
740
|
+
type: "powerLevelLow",
|
|
741
|
+
}, true);
|
|
742
|
+
const powerMode = await adapter.get({
|
|
743
|
+
domain: "controller",
|
|
744
|
+
type: "powerMode",
|
|
745
|
+
}, true);
|
|
746
|
+
const powerModeExtintEnable = await adapter.get({
|
|
747
|
+
domain: "controller",
|
|
748
|
+
type: "powerModeExtintEnable",
|
|
749
|
+
}, true);
|
|
750
|
+
const powerModeWutTimeout = await adapter.get({
|
|
751
|
+
domain: "controller",
|
|
752
|
+
type: "powerModeWutTimeout",
|
|
753
|
+
}, true);
|
|
754
|
+
const controller = {
|
|
755
|
+
protocolVersion: info.nvmDescriptor.protocolVersion,
|
|
756
|
+
applicationVersion: info.nvmDescriptor.firmwareVersion,
|
|
757
|
+
ownHomeId: `0x${ownHomeId.toString("hex")}`,
|
|
758
|
+
learnedHomeId: learnedHomeId
|
|
759
|
+
? `0x${learnedHomeId.toString("hex")}`
|
|
760
|
+
: null,
|
|
761
|
+
nodeId: ownNodeId,
|
|
762
|
+
lastNodeId,
|
|
763
|
+
staticControllerNodeId,
|
|
764
|
+
sucLastIndex,
|
|
765
|
+
controllerConfiguration,
|
|
766
|
+
sucUpdateEntries,
|
|
767
|
+
maxNodeId,
|
|
768
|
+
reservedId,
|
|
769
|
+
systemState,
|
|
770
|
+
watchdogStarted,
|
|
771
|
+
rfConfig: {
|
|
772
|
+
powerLevelNormal,
|
|
773
|
+
powerLevelLow,
|
|
774
|
+
powerMode,
|
|
775
|
+
powerModeExtintEnable,
|
|
776
|
+
powerModeWutTimeout,
|
|
777
|
+
},
|
|
778
|
+
preferredRepeaters,
|
|
779
|
+
commandClasses,
|
|
780
|
+
applicationData: applicationData?.toString("hex") ?? null,
|
|
781
|
+
};
|
|
579
782
|
return {
|
|
580
|
-
|
|
581
|
-
|
|
783
|
+
format: 500,
|
|
784
|
+
meta,
|
|
785
|
+
controller,
|
|
786
|
+
nodes,
|
|
582
787
|
};
|
|
583
788
|
}
|
|
584
|
-
function
|
|
585
|
-
const
|
|
789
|
+
async function jsonToNVM(json, targetSDKVersion) {
|
|
790
|
+
const parsedVersion = semver_1.default.parse(targetSDKVersion);
|
|
791
|
+
if (!parsedVersion) {
|
|
792
|
+
throw new safe_1.ZWaveError(`Invalid SDK version: ${targetSDKVersion}`, safe_1.ZWaveErrorCodes.Argument_Invalid);
|
|
793
|
+
}
|
|
794
|
+
// Erase the NVM
|
|
795
|
+
const sharedFileSystem = json.meta?.sharedFileSystem;
|
|
796
|
+
const nvmSize = sharedFileSystem
|
|
797
|
+
? consts_2.ZWAVE_SHARED_NVM_SIZE
|
|
798
|
+
: (consts_2.ZWAVE_APPLICATION_NVM_SIZE + consts_2.ZWAVE_PROTOCOL_NVM_SIZE);
|
|
799
|
+
const ret = Buffer.allocUnsafe(nvmSize);
|
|
800
|
+
const io = new NVMMemoryIO_1.NVMMemoryIO(ret);
|
|
801
|
+
const nvm3 = new NVM3_1.NVM3(io);
|
|
802
|
+
await nvm3.erase(json.meta);
|
|
803
|
+
const serializeFile = async (file) => {
|
|
804
|
+
const { key, data } = file.serialize();
|
|
805
|
+
await nvm3.set(key, data);
|
|
806
|
+
};
|
|
807
|
+
// Figure out which SDK version we are targeting
|
|
586
808
|
let targetApplicationVersion;
|
|
587
809
|
let targetProtocolVersion;
|
|
588
810
|
let targetProtocolFormat;
|
|
@@ -613,39 +835,66 @@ function jsonToNVMObjects_v7_11_0(json, targetSDKVersion) {
|
|
|
613
835
|
targetProtocolVersion = semver_1.default.parse("7.12.0");
|
|
614
836
|
targetProtocolFormat = 2;
|
|
615
837
|
}
|
|
616
|
-
else {
|
|
617
|
-
// All versions below 7.11.0 are handled in the _v7_0_0 method
|
|
838
|
+
else if (semver_1.default.gte(targetSDKVersion, "7.11.0")) {
|
|
618
839
|
targetProtocolVersion = semver_1.default.parse("7.11.0");
|
|
619
840
|
targetProtocolFormat = 1;
|
|
620
841
|
}
|
|
621
|
-
|
|
622
|
-
|
|
842
|
+
else {
|
|
843
|
+
targetProtocolVersion = semver_1.default.parse("7.0.0");
|
|
844
|
+
targetProtocolFormat = 0;
|
|
845
|
+
}
|
|
846
|
+
const target = (0, safe_2.cloneDeep)(json);
|
|
623
847
|
target.controller.protocolVersion = targetProtocolVersion.format();
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
};
|
|
631
|
-
const addProtocolObjects = (...objects) => {
|
|
632
|
-
for (const o of objects) {
|
|
633
|
-
protocolObjects.set(o.key, o);
|
|
634
|
-
}
|
|
635
|
-
};
|
|
636
|
-
// Application files
|
|
637
|
-
const ApplicationVersionConstructor = json.meta?.sharedFileSystem
|
|
848
|
+
target.format = targetProtocolFormat;
|
|
849
|
+
target.controller.applicationVersion = parsedVersion.format();
|
|
850
|
+
// Write application and protocol version files, because they are required
|
|
851
|
+
// for the NVM3 adapter to work.
|
|
852
|
+
const ApplicationVersionConstructor = sharedFileSystem
|
|
638
853
|
? files_1.ApplicationVersionFile800
|
|
639
854
|
: files_1.ApplicationVersionFile;
|
|
640
855
|
const applVersionFile = new ApplicationVersionConstructor({
|
|
641
|
-
// The SDK compares 4-byte values where the format is set to 0 to determine whether a migration is needed
|
|
642
856
|
format: 0,
|
|
643
857
|
major: targetApplicationVersion.major,
|
|
644
858
|
minor: targetApplicationVersion.minor,
|
|
645
859
|
patch: targetApplicationVersion.patch,
|
|
646
|
-
fileVersion:
|
|
860
|
+
fileVersion: targetProtocolVersion.format(), // does not matter for this file
|
|
861
|
+
});
|
|
862
|
+
await serializeFile(applVersionFile);
|
|
863
|
+
const protocolVersionFile = new files_1.ProtocolVersionFile({
|
|
864
|
+
format: targetProtocolFormat,
|
|
865
|
+
major: targetProtocolVersion.major,
|
|
866
|
+
minor: targetProtocolVersion.minor,
|
|
867
|
+
patch: targetProtocolVersion.patch,
|
|
868
|
+
fileVersion: targetProtocolVersion.format(), // does not matter for this file
|
|
869
|
+
});
|
|
870
|
+
await serializeFile(protocolVersionFile);
|
|
871
|
+
{
|
|
872
|
+
const { key, data } = protocolVersionFile.serialize();
|
|
873
|
+
await nvm3.set(key, data);
|
|
874
|
+
}
|
|
875
|
+
// Now use the adapter where possible. Some properties have to be set together though,
|
|
876
|
+
// so we set the files directly
|
|
877
|
+
const adapter = new adapter_1.NVM3Adapter(nvm3);
|
|
878
|
+
// Start with the application data
|
|
879
|
+
const applTypeFile = new files_1.ApplicationTypeFile({
|
|
880
|
+
...(0, safe_2.pick)(target.controller, [
|
|
881
|
+
"isListening",
|
|
882
|
+
"optionalFunctionality",
|
|
883
|
+
"genericDeviceClass",
|
|
884
|
+
"specificDeviceClass",
|
|
885
|
+
]),
|
|
886
|
+
fileVersion: target.controller.applicationVersion,
|
|
887
|
+
});
|
|
888
|
+
adapter.setFile(applTypeFile);
|
|
889
|
+
const applCCsFile = new files_1.ApplicationCCsFile({
|
|
890
|
+
...(0, safe_2.pick)(target.controller.commandClasses, [
|
|
891
|
+
"includedInsecurely",
|
|
892
|
+
"includedSecurelyInsecureCCs",
|
|
893
|
+
"includedSecurelySecureCCs",
|
|
894
|
+
]),
|
|
895
|
+
fileVersion: target.controller.applicationVersion,
|
|
647
896
|
});
|
|
648
|
-
|
|
897
|
+
adapter.setFile(applCCsFile);
|
|
649
898
|
// When converting it can be that the rfConfig doesn't exist. Make sure
|
|
650
899
|
// that it is initialized with proper defaults.
|
|
651
900
|
target.controller.rfConfig ??= {
|
|
@@ -665,71 +914,76 @@ function jsonToNVMObjects_v7_11_0(json, targetSDKVersion) {
|
|
|
665
914
|
if (semver_1.default.gte(targetSDKVersion, "7.21.0")) {
|
|
666
915
|
target.controller.rfConfig.nodeIdType ??= safe_1.NodeIDType.Short;
|
|
667
916
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
917
|
+
const applRFConfigFile = new files_1.ApplicationRFConfigFile({
|
|
918
|
+
...(0, safe_2.pick)(target.controller.rfConfig, [
|
|
919
|
+
"rfRegion",
|
|
920
|
+
"txPower",
|
|
921
|
+
"measured0dBm",
|
|
922
|
+
]),
|
|
923
|
+
enablePTI: target.controller.rfConfig.enablePTI ?? undefined,
|
|
924
|
+
maxTXPower: target.controller.rfConfig.maxTXPower ?? undefined,
|
|
925
|
+
nodeIdType: target.controller.rfConfig.nodeIdType ?? undefined,
|
|
926
|
+
fileVersion: target.controller.applicationVersion,
|
|
676
927
|
});
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
928
|
+
adapter.setFile(applRFConfigFile);
|
|
929
|
+
if (target.controller.applicationData) {
|
|
930
|
+
await adapter.set({ domain: "controller", type: "applicationData" }, Buffer.from(target.controller.applicationData, "hex"));
|
|
931
|
+
}
|
|
932
|
+
// The application name only seems to be used on 800 series with the shared file system
|
|
933
|
+
if (target.controller.applicationName && target.meta?.sharedFileSystem) {
|
|
934
|
+
await adapter.set({ domain: "controller", type: "applicationName" }, target.controller.applicationName);
|
|
935
|
+
}
|
|
936
|
+
// Now the protocol data
|
|
937
|
+
// TODO: node IDs and LR node IDs should probably be handled by the NVM adapter when
|
|
938
|
+
// setting the node info. But then we need to make sure here that the files are guaranteed to exist
|
|
681
939
|
const nodeInfoExists = new Set();
|
|
682
940
|
const lrNodeInfoExists = new Set();
|
|
683
|
-
const
|
|
941
|
+
const virtualNodeIds = new Set();
|
|
942
|
+
const appRouteLock = new Set();
|
|
943
|
+
const routeSlaveSUC = new Set();
|
|
944
|
+
const sucPendingUpdate = new Set();
|
|
945
|
+
const pendingDiscovery = new Set();
|
|
946
|
+
// Ensure that the route cache exists nodemask is written, even when no routes exist
|
|
947
|
+
adapter.setFile(new files_1.ProtocolRouteCacheExistsNodeMaskFile({
|
|
948
|
+
nodeIds: [],
|
|
949
|
+
fileVersion: target.controller.protocolVersion,
|
|
950
|
+
}));
|
|
684
951
|
for (const [id, node] of Object.entries(target.nodes)) {
|
|
685
952
|
const nodeId = parseInt(id);
|
|
686
|
-
if (!nodeHasInfo(node))
|
|
953
|
+
if (!nodeHasInfo(node)) {
|
|
954
|
+
virtualNodeIds.add(nodeId);
|
|
687
955
|
continue;
|
|
688
|
-
nodeInfoExists.add(nodeId);
|
|
689
|
-
// Create/update node info file
|
|
690
|
-
const nodeInfoFileIndex = (0, files_1.nodeIdToNodeInfoFileIDV1)(nodeId);
|
|
691
|
-
if (!nodeInfoFiles.has(nodeInfoFileIndex)) {
|
|
692
|
-
nodeInfoFiles.set(nodeInfoFileIndex, new files_1.NodeInfoFileV1({
|
|
693
|
-
nodeInfos: [],
|
|
694
|
-
fileVersion: target.controller.protocolVersion,
|
|
695
|
-
}));
|
|
696
956
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
957
|
+
else {
|
|
958
|
+
nodeInfoExists.add(nodeId);
|
|
959
|
+
if (node.isVirtual)
|
|
960
|
+
virtualNodeIds.add(nodeId);
|
|
961
|
+
if (node.appRouteLock)
|
|
962
|
+
appRouteLock.add(nodeId);
|
|
963
|
+
if (node.routeSlaveSUC)
|
|
964
|
+
routeSlaveSUC.add(nodeId);
|
|
965
|
+
if (node.sucPendingUpdate)
|
|
966
|
+
sucPendingUpdate.add(nodeId);
|
|
967
|
+
if (node.pendingDiscovery)
|
|
968
|
+
pendingDiscovery.add(nodeId);
|
|
969
|
+
}
|
|
970
|
+
await adapter.set({ domain: "node", nodeId, type: "info" }, nvmJSONNodeToNodeInfo(nodeId, node));
|
|
700
971
|
if (node.lwr || node.nlwr) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
routeCacheFiles.set(routeCacheFileIndex, new files_1.RouteCacheFileV1({
|
|
705
|
-
routeCaches: [],
|
|
706
|
-
fileVersion: target.controller.protocolVersion,
|
|
707
|
-
}));
|
|
708
|
-
}
|
|
709
|
-
const routeCacheFile = routeCacheFiles.get(routeCacheFileIndex);
|
|
710
|
-
routeCacheFile.routeCaches.push({
|
|
711
|
-
nodeId,
|
|
712
|
-
lwr: node.lwr ?? (0, files_1.getEmptyRoute)(),
|
|
713
|
-
nlwr: node.nlwr ?? (0, files_1.getEmptyRoute)(),
|
|
972
|
+
await adapter.set({ domain: "node", nodeId, type: "routes" }, {
|
|
973
|
+
lwr: node.lwr ?? (0, routeCache_1.getEmptyRoute)(),
|
|
974
|
+
nlwr: node.nlwr ?? (0, routeCache_1.getEmptyRoute)(),
|
|
714
975
|
});
|
|
715
976
|
}
|
|
716
977
|
}
|
|
978
|
+
await adapter.set({ domain: "controller", type: "nodeIds" }, [...nodeInfoExists]);
|
|
717
979
|
if (target.lrNodes) {
|
|
718
980
|
for (const [id, node] of Object.entries(target.lrNodes)) {
|
|
719
981
|
const nodeId = parseInt(id);
|
|
720
982
|
lrNodeInfoExists.add(nodeId);
|
|
721
|
-
|
|
722
|
-
const nodeInfoFileIndex = (0, files_1.nodeIdToLRNodeInfoFileIDV5)(nodeId);
|
|
723
|
-
if (!lrNodeInfoFiles.has(nodeInfoFileIndex)) {
|
|
724
|
-
lrNodeInfoFiles.set(nodeInfoFileIndex, new files_1.LRNodeInfoFileV5({
|
|
725
|
-
nodeInfos: [],
|
|
726
|
-
fileVersion: target.controller.protocolVersion,
|
|
727
|
-
}));
|
|
728
|
-
}
|
|
729
|
-
const nodeInfoFile = lrNodeInfoFiles.get(nodeInfoFileIndex);
|
|
730
|
-
nodeInfoFile.nodeInfos.push(nvmJSONLRNodeToLRNodeInfo(nodeId, node));
|
|
983
|
+
await adapter.set({ domain: "lrnode", nodeId, type: "info" }, nvmJSONLRNodeToLRNodeInfo(nodeId, node));
|
|
731
984
|
}
|
|
732
985
|
}
|
|
986
|
+
await adapter.set({ domain: "controller", type: "lrNodeIds" }, [...lrNodeInfoExists]);
|
|
733
987
|
// For v3+ targets, the ControllerInfoFile must contain the LongRange properties
|
|
734
988
|
// or the controller will ignore the file and not have a home ID
|
|
735
989
|
if (targetProtocolFormat >= 3) {
|
|
@@ -739,90 +993,115 @@ function jsonToNVMObjects_v7_11_0(json, targetSDKVersion) {
|
|
|
739
993
|
target.controller.primaryLongRangeChannelId ??= 0;
|
|
740
994
|
target.controller.dcdcConfig ??= 255;
|
|
741
995
|
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}).serialize());
|
|
751
|
-
if (nodeInfoFiles.size > 0) {
|
|
752
|
-
addProtocolObjects(...[...nodeInfoFiles.values()].map((f) => f.serialize()));
|
|
753
|
-
}
|
|
754
|
-
if (routeCacheFiles.size > 0) {
|
|
755
|
-
addProtocolObjects(...[...routeCacheFiles.values()].map((f) => f.serialize()));
|
|
756
|
-
}
|
|
757
|
-
if (lrNodeInfoFiles.size > 0) {
|
|
758
|
-
addProtocolObjects(new files_1.ProtocolLRNodeListFile({
|
|
759
|
-
nodeIds: [...lrNodeInfoExists],
|
|
760
|
-
fileVersion: target.controller.protocolVersion,
|
|
761
|
-
}).serialize());
|
|
762
|
-
addProtocolObjects(...[...lrNodeInfoFiles.values()].map((f) => f.serialize()));
|
|
996
|
+
adapter.setFile(new files_1.ControllerInfoFile(nvmJSONControllerToFileOptions(target.controller)));
|
|
997
|
+
await adapter.set({ domain: "controller", type: "appRouteLock" }, [...appRouteLock]);
|
|
998
|
+
await adapter.set({ domain: "controller", type: "routeSlaveSUC" }, [...routeSlaveSUC]);
|
|
999
|
+
await adapter.set({ domain: "controller", type: "sucPendingUpdate" }, [...sucPendingUpdate]);
|
|
1000
|
+
await adapter.set({ domain: "controller", type: "virtualNodeIds" }, [...virtualNodeIds]);
|
|
1001
|
+
await adapter.set({ domain: "controller", type: "pendingDiscovery" }, [...pendingDiscovery]);
|
|
1002
|
+
if (target.controller.preferredRepeaters?.length) {
|
|
1003
|
+
await adapter.set({ domain: "controller", type: "preferredRepeaters" }, target.controller.preferredRepeaters);
|
|
763
1004
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
/** Reads an NVM buffer and returns its JSON representation */
|
|
770
|
-
function nvmToJSON(buffer, debugLogs = false) {
|
|
771
|
-
const nvm = (0, nvm_1.parseNVM)(buffer, debugLogs);
|
|
772
|
-
return parsedNVMToJSON(nvm);
|
|
773
|
-
}
|
|
774
|
-
function parsedNVMToJSON(nvm) {
|
|
775
|
-
const objects = new Map([
|
|
776
|
-
...nvm.applicationObjects,
|
|
777
|
-
...nvm.protocolObjects,
|
|
778
|
-
]);
|
|
779
|
-
// 800 series doesn't distinguish between the storage for application and protocol objects
|
|
780
|
-
const sharedFileSystem = nvm.applicationObjects.size > 0
|
|
781
|
-
&& nvm.protocolObjects.size === 0;
|
|
782
|
-
const ret = nvmObjectsToJSON(objects);
|
|
783
|
-
const firstPage = sharedFileSystem
|
|
784
|
-
? nvm.applicationPages[0]
|
|
785
|
-
: nvm.protocolPages[0];
|
|
786
|
-
ret.meta = (0, nvm_1.getNVMMeta)(firstPage, sharedFileSystem);
|
|
1005
|
+
await adapter.set({ domain: "controller", type: "sucUpdateEntries" }, target.controller.sucUpdateEntries);
|
|
1006
|
+
await adapter.commit();
|
|
1007
|
+
await io.close();
|
|
787
1008
|
return ret;
|
|
788
1009
|
}
|
|
789
|
-
/** Reads an NVM buffer of a 500-series stick and returns its JSON representation */
|
|
790
|
-
function nvm500ToJSON(buffer) {
|
|
791
|
-
const parser = (0, NVMParser_1.createParser)(buffer);
|
|
792
|
-
if (!parser) {
|
|
793
|
-
throw new safe_1.ZWaveError("Did not find a matching NVM 500 parser implementation! Make sure that the NVM data belongs to a controller with Z-Wave SDK 6.61 or higher.", safe_1.ZWaveErrorCodes.NVM_NotSupported);
|
|
794
|
-
}
|
|
795
|
-
return parser.toJSON();
|
|
796
|
-
}
|
|
797
|
-
/** Takes a JSON represented NVM and converts it to binary */
|
|
798
|
-
function jsonToNVM(json, targetSDKVersion) {
|
|
799
|
-
const parsedVersion = semver_1.default.parse(targetSDKVersion);
|
|
800
|
-
if (!parsedVersion) {
|
|
801
|
-
throw new safe_1.ZWaveError(`Invalid SDK version: ${targetSDKVersion}`, safe_1.ZWaveErrorCodes.Argument_Invalid);
|
|
802
|
-
}
|
|
803
|
-
let objects;
|
|
804
|
-
if (semver_1.default.gte(parsedVersion, "7.11.0")) {
|
|
805
|
-
objects = jsonToNVMObjects_v7_11_0(json, parsedVersion);
|
|
806
|
-
}
|
|
807
|
-
else if (semver_1.default.gte(parsedVersion, "7.0.0")) {
|
|
808
|
-
objects = jsonToNVMObjects_v7_0_0(json, parsedVersion);
|
|
809
|
-
}
|
|
810
|
-
else {
|
|
811
|
-
throw new safe_1.ZWaveError("jsonToNVM cannot convert to a pre-7.0 NVM version. Use jsonToNVM500 instead.", safe_1.ZWaveErrorCodes.Argument_Invalid);
|
|
812
|
-
}
|
|
813
|
-
return (0, nvm_1.encodeNVM)(objects.applicationObjects, objects.protocolObjects, json.meta);
|
|
814
|
-
}
|
|
815
1010
|
/** Takes a JSON represented 500 series NVM and converts it to binary */
|
|
816
|
-
function jsonToNVM500(json, protocolVersion) {
|
|
1011
|
+
async function jsonToNVM500(json, protocolVersion) {
|
|
817
1012
|
// Try to find a matching implementation
|
|
818
|
-
const impl =
|
|
1013
|
+
const impl = impls_1.nvm500Impls.find((p) => p.protocolVersions.includes(protocolVersion)
|
|
819
1014
|
&& p.name.toLowerCase().startsWith(json.meta.library));
|
|
820
1015
|
if (!impl) {
|
|
821
1016
|
throw new safe_1.ZWaveError(`Did not find a matching implementation for protocol version ${protocolVersion} and library ${json.meta.library}. To convert 500-series NVMs, both the source and the target controller must be using Z-Wave SDK 6.61 or higher.`, safe_1.ZWaveErrorCodes.NVM_NotSupported);
|
|
822
1017
|
}
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
1018
|
+
const { layout, nvmSize } = (0, shared_1.resolveLayout)(impl.layout);
|
|
1019
|
+
// Erase the NVM and set some basic information
|
|
1020
|
+
const ret = Buffer.allocUnsafe(nvmSize);
|
|
1021
|
+
const io = new NVMMemoryIO_1.NVMMemoryIO(ret);
|
|
1022
|
+
const nvm = new NVM500_1.NVM500(io);
|
|
1023
|
+
await nvm.erase({
|
|
1024
|
+
layout,
|
|
1025
|
+
nvmSize,
|
|
1026
|
+
library: impl.library,
|
|
1027
|
+
nvmDescriptor: {
|
|
1028
|
+
...(0, safe_2.pick)(json.meta, [
|
|
1029
|
+
"manufacturerID",
|
|
1030
|
+
"productType",
|
|
1031
|
+
"productID",
|
|
1032
|
+
"firmwareID",
|
|
1033
|
+
]),
|
|
1034
|
+
// Override the protocol version with the specified one
|
|
1035
|
+
protocolVersion,
|
|
1036
|
+
firmwareVersion: json.controller.applicationVersion,
|
|
1037
|
+
},
|
|
1038
|
+
});
|
|
1039
|
+
const adapter = new adapter_2.NVM500Adapter(nvm);
|
|
1040
|
+
// Set controller infos
|
|
1041
|
+
const c = json.controller;
|
|
1042
|
+
await adapter.set({ domain: "controller", type: "homeId" }, Buffer.from(c.ownHomeId.replace(/^0x/, ""), "hex"));
|
|
1043
|
+
await adapter.set({ domain: "controller", type: "learnedHomeId" }, c.learnedHomeId
|
|
1044
|
+
? Buffer.from(c.learnedHomeId.replace(/^0x/, ""), "hex")
|
|
1045
|
+
: undefined);
|
|
1046
|
+
await adapter.set({ domain: "controller", type: "nodeId" }, c.nodeId);
|
|
1047
|
+
await adapter.set({ domain: "controller", type: "lastNodeId" }, c.lastNodeId);
|
|
1048
|
+
await adapter.set({ domain: "controller", type: "maxNodeId" }, c.maxNodeId);
|
|
1049
|
+
await adapter.set({ domain: "controller", type: "reservedId" }, c.reservedId);
|
|
1050
|
+
await adapter.set({ domain: "controller", type: "staticControllerNodeId" }, c.staticControllerNodeId);
|
|
1051
|
+
await adapter.set({ domain: "controller", type: "controllerConfiguration" }, c.controllerConfiguration);
|
|
1052
|
+
await adapter.set({ domain: "controller", type: "sucUpdateEntries" }, c.sucUpdateEntries);
|
|
1053
|
+
await adapter.set({ domain: "controller", type: "sucLastIndex" }, c.sucLastIndex);
|
|
1054
|
+
await adapter.set({ domain: "controller", type: "systemState" }, c.systemState);
|
|
1055
|
+
await adapter.set({ domain: "controller", type: "watchdogStarted" }, c.watchdogStarted);
|
|
1056
|
+
await adapter.set({ domain: "controller", type: "powerLevelNormal" }, c.rfConfig.powerLevelNormal);
|
|
1057
|
+
await adapter.set({ domain: "controller", type: "powerLevelLow" }, c.rfConfig.powerLevelLow);
|
|
1058
|
+
await adapter.set({ domain: "controller", type: "powerMode" }, c.rfConfig.powerMode);
|
|
1059
|
+
await adapter.set({ domain: "controller", type: "powerModeExtintEnable" }, c.rfConfig.powerModeExtintEnable);
|
|
1060
|
+
await adapter.set({ domain: "controller", type: "powerModeWutTimeout" }, c.rfConfig.powerModeWutTimeout);
|
|
1061
|
+
await adapter.set({ domain: "controller", type: "preferredRepeaters" }, c.preferredRepeaters);
|
|
1062
|
+
await adapter.set({ domain: "controller", type: "commandClasses" }, c.commandClasses);
|
|
1063
|
+
if (c.applicationData) {
|
|
1064
|
+
await adapter.set({ domain: "controller", type: "applicationData" }, Buffer.from(c.applicationData, "hex"));
|
|
1065
|
+
}
|
|
1066
|
+
// Set node infos
|
|
1067
|
+
const appRouteLock = [];
|
|
1068
|
+
const routeSlaveSUC = [];
|
|
1069
|
+
const pendingDiscovery = [];
|
|
1070
|
+
const sucPendingUpdate = [];
|
|
1071
|
+
const virtualNodeIds = [];
|
|
1072
|
+
for (const [id, node] of Object.entries(json.nodes)) {
|
|
1073
|
+
const nodeId = parseInt(id);
|
|
1074
|
+
if (!nodeHasInfo(node)) {
|
|
1075
|
+
virtualNodeIds.push(nodeId);
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
if (node.appRouteLock)
|
|
1079
|
+
appRouteLock.push(nodeId);
|
|
1080
|
+
if (node.routeSlaveSUC)
|
|
1081
|
+
routeSlaveSUC.push(nodeId);
|
|
1082
|
+
if (node.pendingDiscovery)
|
|
1083
|
+
pendingDiscovery.push(nodeId);
|
|
1084
|
+
if (node.sucPendingUpdate)
|
|
1085
|
+
sucPendingUpdate.push(nodeId);
|
|
1086
|
+
await adapter.set({ domain: "node", nodeId, type: "info" }, {
|
|
1087
|
+
nodeId,
|
|
1088
|
+
...node,
|
|
1089
|
+
});
|
|
1090
|
+
if (node.lwr || node.nlwr) {
|
|
1091
|
+
await adapter.set({ domain: "node", nodeId, type: "routes" }, {
|
|
1092
|
+
lwr: node.lwr ?? undefined,
|
|
1093
|
+
nlwr: node.nlwr ?? undefined,
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
await adapter.set({ domain: "controller", type: "appRouteLock" }, [...appRouteLock]);
|
|
1098
|
+
await adapter.set({ domain: "controller", type: "routeSlaveSUC" }, [...routeSlaveSUC]);
|
|
1099
|
+
await adapter.set({ domain: "controller", type: "sucPendingUpdate" }, [...sucPendingUpdate]);
|
|
1100
|
+
await adapter.set({ domain: "controller", type: "virtualNodeIds" }, [...virtualNodeIds]);
|
|
1101
|
+
await adapter.set({ domain: "controller", type: "pendingDiscovery" }, [...pendingDiscovery]);
|
|
1102
|
+
await adapter.commit();
|
|
1103
|
+
await io.close();
|
|
1104
|
+
return ret;
|
|
826
1105
|
}
|
|
827
1106
|
function json500To700(json, truncateApplicationData) {
|
|
828
1107
|
const source = (0, safe_2.cloneDeep)(json);
|
|
@@ -990,30 +1269,24 @@ function json700To500(json) {
|
|
|
990
1269
|
return ret;
|
|
991
1270
|
}
|
|
992
1271
|
/** Converts the given source NVM into a format that is compatible with the given target NVM */
|
|
993
|
-
function migrateNVM(sourceNVM, targetNVM) {
|
|
1272
|
+
async function migrateNVM(sourceNVM, targetNVM) {
|
|
994
1273
|
let source;
|
|
995
1274
|
let target;
|
|
996
|
-
let sourceObjects;
|
|
997
1275
|
let sourceProtocolFileFormat;
|
|
998
1276
|
let targetProtocolFileFormat;
|
|
999
1277
|
try {
|
|
1000
|
-
const nvm = (0, nvm_1.parseNVM)(sourceNVM);
|
|
1001
1278
|
source = {
|
|
1002
1279
|
type: 700,
|
|
1003
|
-
json:
|
|
1280
|
+
json: await nvmToJSON(sourceNVM),
|
|
1004
1281
|
};
|
|
1005
1282
|
sourceProtocolFileFormat = source.json.format;
|
|
1006
|
-
sourceObjects = new Map([
|
|
1007
|
-
...nvm.applicationObjects,
|
|
1008
|
-
...nvm.protocolObjects,
|
|
1009
|
-
]);
|
|
1010
1283
|
}
|
|
1011
1284
|
catch (e) {
|
|
1012
1285
|
if ((0, safe_1.isZWaveError)(e) && e.code === safe_1.ZWaveErrorCodes.NVM_InvalidFormat) {
|
|
1013
1286
|
// This is not a 700 series NVM, maybe it is a 500 series one?
|
|
1014
1287
|
source = {
|
|
1015
1288
|
type: 500,
|
|
1016
|
-
json: nvm500ToJSON(sourceNVM),
|
|
1289
|
+
json: await nvm500ToJSON(sourceNVM),
|
|
1017
1290
|
};
|
|
1018
1291
|
}
|
|
1019
1292
|
else if ((0, safe_1.isZWaveError)(e)
|
|
@@ -1031,7 +1304,7 @@ function migrateNVM(sourceNVM, targetNVM) {
|
|
|
1031
1304
|
try {
|
|
1032
1305
|
target = {
|
|
1033
1306
|
type: 700,
|
|
1034
|
-
json: nvmToJSON(targetNVM),
|
|
1307
|
+
json: await nvmToJSON(targetNVM),
|
|
1035
1308
|
};
|
|
1036
1309
|
targetProtocolFileFormat = target.json.format;
|
|
1037
1310
|
}
|
|
@@ -1040,7 +1313,7 @@ function migrateNVM(sourceNVM, targetNVM) {
|
|
|
1040
1313
|
// This is not a 700 series NVM, maybe it is a 500 series one?
|
|
1041
1314
|
target = {
|
|
1042
1315
|
type: 500,
|
|
1043
|
-
json: nvm500ToJSON(targetNVM),
|
|
1316
|
+
json: await nvm500ToJSON(targetNVM),
|
|
1044
1317
|
};
|
|
1045
1318
|
}
|
|
1046
1319
|
else if ((0, safe_1.isZWaveError)(e)
|
|
@@ -1092,7 +1365,7 @@ function migrateNVM(sourceNVM, targetNVM) {
|
|
|
1092
1365
|
&& semver_1.default.lt(sourceApplicationVersion, "255.0.0")
|
|
1093
1366
|
&& semver_1.default.lt(targetApplicationVersion, "255.0.0")
|
|
1094
1367
|
// and avoid restoring a backup with a shifted 800 series application version file
|
|
1095
|
-
&& (!
|
|
1368
|
+
&& (!hasShiftedAppVersion800File(source.json))) {
|
|
1096
1369
|
return sourceNVM;
|
|
1097
1370
|
}
|
|
1098
1371
|
}
|
|
@@ -1166,39 +1439,24 @@ function migrateNVM(sourceNVM, targetNVM) {
|
|
|
1166
1439
|
/**
|
|
1167
1440
|
* Detects whether the app version file on a 800 series controller is shifted by 1 byte
|
|
1168
1441
|
*/
|
|
1169
|
-
function hasShiftedAppVersion800File(
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
return objects.get(id);
|
|
1173
|
-
}
|
|
1174
|
-
else {
|
|
1175
|
-
for (const [key, obj] of objects) {
|
|
1176
|
-
if (id(key))
|
|
1177
|
-
return obj;
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
};
|
|
1181
|
-
const getFile = (id, fileVersion) => {
|
|
1182
|
-
const obj = getObject(id);
|
|
1183
|
-
if (!obj)
|
|
1184
|
-
return undefined;
|
|
1185
|
-
return files_1.NVMFile.from(obj, fileVersion);
|
|
1186
|
-
};
|
|
1187
|
-
const protocolVersionFile = getFile(files_1.ProtocolVersionFileID, "7.0.0");
|
|
1188
|
-
// File not found, cannot fix anything
|
|
1189
|
-
if (!protocolVersionFile)
|
|
1442
|
+
function hasShiftedAppVersion800File(json) {
|
|
1443
|
+
// We can only detect this on 800 series controllers with the shared FS
|
|
1444
|
+
if (!json.meta.sharedFileSystem)
|
|
1190
1445
|
return false;
|
|
1191
|
-
const protocolVersion =
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1446
|
+
const protocolVersion = semver_1.default.parse(json.controller.protocolVersion);
|
|
1447
|
+
// Invalid protocol version, cannot fix anything
|
|
1448
|
+
if (!protocolVersion)
|
|
1449
|
+
return false;
|
|
1450
|
+
const applicationVersion = semver_1.default.parse(json.controller.applicationVersion);
|
|
1451
|
+
// Invalid application version, cannot fix anything
|
|
1452
|
+
if (!applicationVersion)
|
|
1195
1453
|
return false;
|
|
1196
1454
|
// We consider the version shifted if:
|
|
1197
1455
|
// - the app version format is the major protocol version
|
|
1198
1456
|
// - the app version major is the minor protocol version +/- 3
|
|
1199
|
-
if (
|
|
1457
|
+
if (json.applicationFileFormat !== protocolVersion.major)
|
|
1200
1458
|
return false;
|
|
1201
|
-
if (Math.abs(
|
|
1459
|
+
if (Math.abs(applicationVersion.major - protocolVersion.minor) > 3) {
|
|
1202
1460
|
return false;
|
|
1203
1461
|
}
|
|
1204
1462
|
return true;
|