@atelieruldetehnologii/node-red-custome-solutions 0.62.22
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/NOTICE +56 -0
- package/PROPRIETARY-LICENSE.txt +157 -0
- package/README.md +105 -0
- package/TERMS-AND-CONDITIONS.md +311 -0
- package/advantech-read/advantech-read.html +775 -0
- package/advantech-read/advantech-read.js +449 -0
- package/advantech-write/advantech-write.html +413 -0
- package/advantech-write/advantech-write.js +338 -0
- package/bess-control/bess-control.html +569 -0
- package/bess-control/bess-control.js +541 -0
- package/bess-control/lib/allocation.js +149 -0
- package/bess-control/lib/batteries.js +86 -0
- package/bess-control/lib/helpers.js +157 -0
- package/bess-control/lib/messages.js +131 -0
- package/bess-control/lib/runtime.js +156 -0
- package/carlo-gavazzi/carlo-gavazzi.html +4327 -0
- package/carlo-gavazzi/carlo-gavazzi.js +3081 -0
- package/control-export/control-export.html +3644 -0
- package/control-export/control-export.js +2192 -0
- package/control-reactive/control-reactive.html +3136 -0
- package/control-reactive/control-reactive.js +2124 -0
- package/fronius-emulator/README.md +258 -0
- package/fronius-emulator/fronius-emulator.html +170 -0
- package/fronius-emulator/fronius-emulator.js +520 -0
- package/fronius-emulator/lib/binary-codec.js +65 -0
- package/fronius-emulator/lib/fronius-register-map.js +185 -0
- package/fronius-emulator/lib/modbus-parser.js +61 -0
- package/fronius-emulator/lib/modbus-tcp-server.js +224 -0
- package/fronius-emulator/lib/validation.js +206 -0
- package/fronius-emulator/lib/virtual-meter.js +132 -0
- package/fronius-read/fronius-read.html +3944 -0
- package/fronius-read/fronius-read.js +1466 -0
- package/fronius-read/lib/inverter-profiles.js +711 -0
- package/fronius-read/lib/sunspec-core.js +303 -0
- package/fronius-read/lib/sunspec-model-parsers.js +845 -0
- package/fronius-write/fronius-write.html +1789 -0
- package/fronius-write/fronius-write.js +2531 -0
- package/influxdb/influxdb.html +1077 -0
- package/influxdb/influxdb.js +1487 -0
- package/janitza/janitza.html +2562 -0
- package/janitza/janitza.js +1500 -0
- package/janitza/lib/janitza-profiles.js +371 -0
- package/lib/a3-test-server.js +199 -0
- package/lib/adam-6000-profiles.js +173 -0
- package/lib/licensing/constants.js +103 -0
- package/lib/licensing/device-id.js +251 -0
- package/lib/licensing/errors.js +21 -0
- package/lib/licensing/license-client.js +377 -0
- package/lib/licensing/license-state.js +50 -0
- package/lib/licensing/node-guard.js +150 -0
- package/lib/licensing/package-integrity.js +167 -0
- package/lib/licensing/package-integrity.json +513 -0
- package/lib/licensing/public-key.pem +3 -0
- package/lib/licensing/public-key.pem.example +2 -0
- package/lib/licensing/public-keys.js +18 -0
- package/lib/licensing/storage.js +63 -0
- package/lib/licensing/token-verifier.js +84 -0
- package/lib/numbers.js +26 -0
- package/license/atelier-license.html +88 -0
- package/license/atelier-license.js +170 -0
- package/modbus-tcp-discover/modbus-tcp-discover.html +190 -0
- package/modbus-tcp-discover/modbus-tcp-discover.js +706 -0
- package/multi-battery/multi-battery.html +649 -0
- package/multi-battery/multi-battery.js +668 -0
- package/multi-grid/multi-grid.html +745 -0
- package/multi-grid/multi-grid.js +1392 -0
- package/multi-inverter/lib/engine-core.js +237 -0
- package/multi-inverter/multi-inverter.html +2674 -0
- package/multi-inverter/multi-inverter.js +1393 -0
- package/package.json +109 -0
- package/phoenix-contact/lib/eem-ma370-advanced.js +175 -0
- package/phoenix-contact/lib/eem-ma370.js +138 -0
- package/phoenix-contact/lib/integrations.js +149 -0
- package/phoenix-contact/lib/phoenix-contact-profile.js +35030 -0
- package/phoenix-contact/phoenix-contact.html +840 -0
- package/phoenix-contact/phoenix-contact.js +679 -0
- package/pv-generator/pv-generator.html +284 -0
- package/pv-generator/pv-generator.js +387 -0
- package/pylontech-read/pylontech-read.html +763 -0
- package/pylontech-read/pylontech-read.js +518 -0
- package/pylontech-write/pylontech-write.html +405 -0
- package/pylontech-write/pylontech-write.js +546 -0
- package/scada-aggregator/lib/aggregate.js +72 -0
- package/scada-aggregator/lib/groups.js +39 -0
- package/scada-aggregator/scada-aggregator.html +108 -0
- package/scada-aggregator/scada-aggregator.js +117 -0
- package/scada-server/lib/aggregator-map.js +58 -0
- package/scada-server/lib/encoding.js +235 -0
- package/scada-server/lib/modbus-server.js +492 -0
- package/scada-server/lib/object-path.js +18 -0
- package/scada-server/lib/register-map.js +288 -0
- package/scada-server/scada-server.html +1419 -0
- package/scada-server/scada-server.js +704 -0
- package/scripts/check-syntax.js +66 -0
- package/scripts/package-integrity.js +46 -0
- package/scripts/package-release.js +116 -0
- package/scripts/run-tests.js +2178 -0
- package/scripts/tgz-integrity.js +74 -0
- package/sma-read/lib/sunspec-core.js +83 -0
- package/sma-read/lib/sunspec-model-parsers.js +853 -0
- package/sma-read/sma-read.html +659 -0
- package/sma-read/sma-read.js +458 -0
- package/sma-write/sma-write.html +105 -0
- package/sma-write/sma-write.js +270 -0
- package/victron-read/lib/mqtt-state.js +176 -0
- package/victron-read/victron-read.html +1074 -0
- package/victron-read/victron-read.js +1222 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const zlib = require("zlib");
|
|
6
|
+
const { MANIFEST_PATH, canonicalJson, manifestPayload } = require("../lib/licensing/package-integrity");
|
|
7
|
+
const { decodePrivateKey } = require("./package-integrity");
|
|
8
|
+
|
|
9
|
+
function readText(buffer, offset, length) { return buffer.subarray(offset, offset + length).toString("utf8").replace(/\0.*$/, "").trim(); }
|
|
10
|
+
function readOctal(buffer, offset, length) { const value = readText(buffer, offset, length).replace(/\s/g, ""); return value ? Number.parseInt(value, 8) : 0; }
|
|
11
|
+
|
|
12
|
+
function readTarEntries(tgz) {
|
|
13
|
+
const tar = zlib.gunzipSync(tgz);
|
|
14
|
+
const entries = [];
|
|
15
|
+
for (let offset = 0; offset + 512 <= tar.length;) {
|
|
16
|
+
const header = tar.subarray(offset, offset + 512);
|
|
17
|
+
if (header.every(function (byte) { return byte === 0; })) break;
|
|
18
|
+
const name = readText(header, 0, 100);
|
|
19
|
+
const prefix = readText(header, 345, 155);
|
|
20
|
+
const fullName = prefix ? prefix + "/" + name : name;
|
|
21
|
+
const size = readOctal(header, 124, 12);
|
|
22
|
+
const type = readText(header, 156, 1) || "0";
|
|
23
|
+
const contentStart = offset + 512;
|
|
24
|
+
const contentEnd = contentStart + size;
|
|
25
|
+
if (contentEnd > tar.length) throw new Error("truncated tar entry: " + fullName);
|
|
26
|
+
if (!["x", "g", "L", "K"].includes(type)) entries.push({ name: fullName.replace(/^\.\//, ""), type, mode: readOctal(header, 100, 8), mtime: readOctal(header, 136, 12), data: Buffer.from(tar.subarray(contentStart, contentEnd)) });
|
|
27
|
+
offset = contentStart + Math.ceil(size / 512) * 512;
|
|
28
|
+
}
|
|
29
|
+
return entries;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function writeText(buffer, offset, length, value) { buffer.write(String(value).slice(0, length), offset, length, "utf8"); }
|
|
33
|
+
function writeOctal(buffer, offset, length, value) { writeText(buffer, offset, length, Math.max(0, value).toString(8).padStart(length - 1, "0") + "\0"); }
|
|
34
|
+
function tarHeader(entry) {
|
|
35
|
+
const header = Buffer.alloc(512);
|
|
36
|
+
const lastSlash = entry.name.lastIndexOf("/");
|
|
37
|
+
const usePrefix = Buffer.byteLength(entry.name) > 100 && lastSlash > 0;
|
|
38
|
+
const name = usePrefix ? entry.name.slice(lastSlash + 1) : entry.name;
|
|
39
|
+
const prefix = usePrefix ? entry.name.slice(0, lastSlash) : "";
|
|
40
|
+
if (Buffer.byteLength(name) > 100 || Buffer.byteLength(prefix) > 155) throw new Error("tar path too long: " + entry.name);
|
|
41
|
+
writeText(header, 0, 100, name); writeOctal(header, 100, 8, entry.mode || 0o644); writeOctal(header, 108, 8, 0); writeOctal(header, 116, 8, 0);
|
|
42
|
+
writeOctal(header, 124, 12, entry.data.length); writeOctal(header, 136, 12, entry.mtime || 0); header.fill(0x20, 148, 156);
|
|
43
|
+
writeText(header, 156, 1, entry.type || "0"); writeText(header, 257, 6, "ustar\0"); writeText(header, 263, 2, "00"); writeText(header, 265, 32, "root"); writeText(header, 297, 32, "root"); writeText(header, 345, 155, prefix);
|
|
44
|
+
const checksum = header.reduce(function (sum, byte) { return sum + byte; }, 0); writeText(header, 148, 8, checksum.toString(8).padStart(6, "0") + "\0 ");
|
|
45
|
+
return header;
|
|
46
|
+
}
|
|
47
|
+
function writeTar(entries) {
|
|
48
|
+
const parts = [];
|
|
49
|
+
entries.forEach(function (entry) { parts.push(tarHeader(entry), entry.data); const padding = (512 - (entry.data.length % 512)) % 512; if (padding) parts.push(Buffer.alloc(padding)); });
|
|
50
|
+
parts.push(Buffer.alloc(1024)); return Buffer.concat(parts);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function protectedEntry(entry) {
|
|
54
|
+
if (!entry.name.startsWith("package/") || entry.name === "package/" + MANIFEST_PATH) return false;
|
|
55
|
+
const relative = entry.name.slice("package/".length);
|
|
56
|
+
return relative === "package.json" || relative === "lib/licensing/public-key.pem" || /\.(?:js|html)$/.test(relative);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function signTgzIntegrity(archivePath, privateKeyValue, keyId) {
|
|
60
|
+
const entries = readTarEntries(fs.readFileSync(archivePath)).filter(function (entry) { return entry.name !== "package/" + MANIFEST_PATH; });
|
|
61
|
+
const packageEntry = entries.find(function (entry) { return entry.name === "package/package.json"; });
|
|
62
|
+
if (!packageEntry) throw new Error("archive has no package/package.json: " + archivePath);
|
|
63
|
+
const packageJson = JSON.parse(packageEntry.data.toString("utf8"));
|
|
64
|
+
const files = entries.filter(protectedEntry).map(function (entry) {
|
|
65
|
+
return { path: entry.name.slice("package/".length), sha256: crypto.createHash("sha256").update(entry.data).digest("hex"), size: entry.data.length };
|
|
66
|
+
}).sort(function (a, b) { return a.path.localeCompare(b.path); });
|
|
67
|
+
const manifest = { algorithm: "sha256", files, keyId: keyId || "v1", package: { name: String(packageJson.name || ""), version: String(packageJson.version || "") }, schemaVersion: 1, signatureAlgorithm: "Ed25519" };
|
|
68
|
+
const signature = crypto.sign(null, Buffer.from(canonicalJson(manifestPayload(manifest))), decodePrivateKey(privateKeyValue)).toString("base64url");
|
|
69
|
+
entries.push({ name: "package/" + MANIFEST_PATH, type: "0", mode: 0o644, mtime: 0, data: Buffer.from(JSON.stringify(Object.assign({}, manifest, { signature }), null, 2) + "\n") });
|
|
70
|
+
fs.writeFileSync(archivePath, zlib.gzipSync(writeTar(entries), { level: 9 }));
|
|
71
|
+
return manifest;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = { readTarEntries, signTgzIntegrity, writeTar };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const MAX_READ_REGISTERS = 120;
|
|
4
|
+
const MAX_MODELS = 256;
|
|
5
|
+
const BASE_CANDIDATES = [39999, 40000, 40001, 40002, 40199, 40200, 40201, 40202];
|
|
6
|
+
|
|
7
|
+
async function readHolding(client, addr, len) {
|
|
8
|
+
const start = Number(addr);
|
|
9
|
+
const count = Number(len);
|
|
10
|
+
if (!Number.isInteger(start) || start < 0 || start > 0xffff) {
|
|
11
|
+
throw new Error("Invalid Modbus start address: " + addr);
|
|
12
|
+
}
|
|
13
|
+
if (!Number.isInteger(count) || count < 1 || start + count > 0x10000) {
|
|
14
|
+
throw new Error("Invalid Modbus register count: " + len);
|
|
15
|
+
}
|
|
16
|
+
const data = [];
|
|
17
|
+
for (let offset = 0; offset < count;) {
|
|
18
|
+
const size = Math.min(MAX_READ_REGISTERS, count - offset);
|
|
19
|
+
const response = await client.readHoldingRegisters(start + offset, size);
|
|
20
|
+
if (!response || !Array.isArray(response.data) || response.data.length !== size) {
|
|
21
|
+
throw new Error("Incomplete Modbus response at register " + (start + offset));
|
|
22
|
+
}
|
|
23
|
+
data.push.apply(data, response.data);
|
|
24
|
+
offset += size;
|
|
25
|
+
}
|
|
26
|
+
return { data: data };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function findBase(client) {
|
|
30
|
+
for (const base of BASE_CANDIDATES) {
|
|
31
|
+
try {
|
|
32
|
+
const response = await readHolding(client, base, 2);
|
|
33
|
+
const text = response.data.map(function (word) {
|
|
34
|
+
return String.fromCharCode((word >> 8) & 0xff) + String.fromCharCode(word & 0xff);
|
|
35
|
+
}).join("");
|
|
36
|
+
if (text === "SunS") return base;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
// Continue with the next standard offset candidate.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
throw new Error("SunSpec not found");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function scanModelDescriptors(client, base) {
|
|
45
|
+
const descriptors = [];
|
|
46
|
+
let addr = base + 2;
|
|
47
|
+
while (true) {
|
|
48
|
+
if (descriptors.length >= MAX_MODELS || addr < 0 || addr > 0xfffd) {
|
|
49
|
+
throw new Error("Invalid or unterminated SunSpec model table");
|
|
50
|
+
}
|
|
51
|
+
const header = await readHolding(client, addr, 2);
|
|
52
|
+
const modelId = header.data[0];
|
|
53
|
+
const len = header.data[1];
|
|
54
|
+
if (modelId === 0xffff) break;
|
|
55
|
+
if (!Number.isInteger(len) || len < 1 || addr + 2 + len > 0x10000) {
|
|
56
|
+
throw new Error("Invalid SunSpec model length " + len + " for model " + modelId);
|
|
57
|
+
}
|
|
58
|
+
descriptors.push({ model_id: modelId, addr: addr, len: len });
|
|
59
|
+
addr += 2 + len;
|
|
60
|
+
}
|
|
61
|
+
return descriptors;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function readModelsByDescriptors(client, descriptors) {
|
|
65
|
+
const models = [];
|
|
66
|
+
for (const descriptor of descriptors) {
|
|
67
|
+
const response = await readHolding(client, descriptor.addr + 2, descriptor.len);
|
|
68
|
+
models.push({
|
|
69
|
+
model_id: descriptor.model_id,
|
|
70
|
+
addr: descriptor.addr,
|
|
71
|
+
len: descriptor.len,
|
|
72
|
+
raw: response.data
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return models;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
readHolding,
|
|
80
|
+
findBase,
|
|
81
|
+
scanModelDescriptors,
|
|
82
|
+
readModelsByDescriptors
|
|
83
|
+
};
|