Files
CPLv4.0/mocks/scripts/fetchCableData.mjs

255 lines
7.9 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
// Fetch and update cable monitoring mock data for 32 slots (0-31)
// Writes to mocks/device-cgi-simulator/chartsData/cable-monitoring-data/slot{N}/{isolationswiderstand|schleifenwiderstand}/DIA{0|1|2}.json
// Usage examples (PowerShell):
// node mocks/scripts/fetchCableData.mjs --base https://10.10.0.118 --from 2025-07-13 --to 2025-08-12 --insecure
// node mocks/scripts/fetchCableData.mjs --slots 0-3 --modes DIA0,DIA1 --types iso --insecure
import fs from "node:fs/promises";
import path from "node:path";
import https from "node:https";
// Simple CLI args parser supporting "--key=value" and "--key value"
const args = (() => {
const out = {};
const argv = process.argv.slice(2);
for (let i = 0; i < argv.length; i++) {
const tok = argv[i];
if (tok.startsWith("--")) {
const eq = tok.indexOf("=");
if (eq !== -1) {
const key = tok.slice(2, eq);
const val = tok.slice(eq + 1);
out[key] = val;
} else {
const key = tok.slice(2);
const next = argv[i + 1];
if (next && !next.startsWith("--")) {
out[key] = next;
i++;
} else {
out[key] = true;
}
}
}
}
return out;
})();
const BASE_URL =
args.base || process.env.CPL_DEVICE_BASE_URL || "https://10.10.0.118";
const MODES = String(args.modes || "DIA0,DIA1,DIA2")
.split(",")
.map((s) => s.trim())
.filter(Boolean);
const TYPES = String(args.types || "iso,rsl")
.split(",")
.map((s) => s.trim())
.filter(Boolean); // iso -> 3, rsl -> 4
const SLOTS = (() => {
if (args.slots) {
if (String(args.slots).includes("-")) {
const [a, b] = String(args.slots).split("-").map(Number);
return Array.from({ length: b - a + 1 }, (_, i) => a + i);
}
return String(args.slots)
.split(",")
.map((s) => Number(s.trim()));
}
return Array.from({ length: 32 }, (_, i) => i);
})();
const today = new Date();
const defaultFrom = new Date(today);
defaultFrom.setDate(today.getDate() - 30);
const fromISO =
args.from ||
process.env.CPL_FROM_DATE ||
defaultFrom.toISOString().slice(0, 10); // YYYY-MM-DD
const toISO =
args.to || process.env.CPL_TO_DATE || today.toISOString().slice(0, 10);
// Default output directory matches Next.js API handler slotDataAPIHandler.ts
// (mocks/device-cgi-simulator/chartsData/cable-monitoring-data)
const OUT_DIR =
args.out ||
path.join(
process.cwd(),
"mocks",
"device-cgi-simulator",
"chartsData",
"cable-monitoring-data"
);
const INSECURE = Boolean(args.insecure || process.env.CPL_INSECURE);
if (INSECURE) {
// Allow self-signed certs for local device
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
// Basic Auth credentials (same default as fetchSystemData.mjs)
const USERNAME = args.user || process.env.CPL_USER || "Littwin";
const PASSWORD = args.pass || process.env.CPL_PASS || "Littwin";
const AUTH_HEADER =
"Basic " + Buffer.from(`${USERNAME}:${PASSWORD}`).toString("base64");
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const toACPDate = (iso) => {
const [y, m, d] = iso.split("-");
return `${y};${m};${d}`;
};
const typeToFolderAndCode = (typeKey) => {
switch (typeKey) {
case "iso":
return { folder: "isolationswiderstand", code: 3 };
case "rsl":
case "schleife":
return { folder: "schleifenwiderstand", code: 4 };
default:
throw new Error(`Unknown type '${typeKey}'. Use iso or rsl.`);
}
};
const buildUrl = (mode, from, to, slot, typeCode) =>
`${BASE_URL}/CPL?seite.ACP&${mode}=${toACPDate(from)};${toACPDate(
to
)};${slot};${typeCode};`;
async function fetchJson(url) {
// Prefer node-fetch when INSECURE to pass https.Agent; otherwise use global fetch when available
let doFetch = globalThis.fetch;
if (INSECURE || typeof doFetch === "undefined") {
const { default: nf } = await import("node-fetch");
doFetch = nf;
}
const init = { headers: { Authorization: AUTH_HEADER } };
if (INSECURE) {
init.agent = new https.Agent({ rejectUnauthorized: false });
}
const res = await doFetch(url, init);
if (!res.ok) {
const text = await res.text().catch(() => "");
throw new Error(`HTTP ${res.status} ${res.statusText} for ${url}\n${text}`);
}
return res.json();
}
async function ensureDir(dir) {
await fs.mkdir(dir, { recursive: true });
}
async function writeJson(file, data) {
await ensureDir(path.dirname(file));
await fs.writeFile(file, JSON.stringify(data, null, 2), "utf8");
}
async function main() {
console.log(`➡️ Fetch cable data`);
console.log(` Base: ${BASE_URL}`);
console.log(` Range: ${fromISO}${toISO}`);
console.log(` Slots: ${SLOTS.join(",")}`);
console.log(` Modes: ${MODES.join(",")}`);
console.log(` Types: ${TYPES.join(",")}`);
console.log(` Out: ${OUT_DIR}`);
if (INSECURE) console.log(` TLS: insecure (self-signed allowed)`);
// Small concurrency to avoid hammering the device
const MAX_CONCURRENCY = Number(args.concurrency || 3);
let running = 0;
let idx = 0;
const tasks = [];
for (const slot of SLOTS) {
for (const typeKey of TYPES) {
const { folder, code } = typeToFolderAndCode(typeKey);
for (const mode of MODES) {
tasks.push({ slot, typeKey, folder, code, mode });
}
}
}
const runNext = async () => {
if (idx >= tasks.length) return;
const task = tasks[idx++];
running++;
try {
const url = buildUrl(task.mode, fromISO, toISO, task.slot, task.code);
console.log(`→ [slot ${task.slot}] ${task.folder} ${task.mode}`);
const data = await fetchJson(url);
const file = path.join(
OUT_DIR,
`slot${task.slot}`,
task.folder,
`${task.mode}.json`
);
await writeJson(file, data);
} catch (e) {
console.error(
`✖ Fehler bei slot ${task.slot} ${task.folder} ${task.mode}:`,
e.message || e
);
} finally {
running--;
// polite delay between requests
await sleep(Number(args.delay || 150));
if (idx < tasks.length) runNext();
}
};
// Start initial workers
const starters = Math.min(MAX_CONCURRENCY, tasks.length);
for (let i = 0; i < starters; i++) runNext();
// Wait for all to finish
while (running > 0 || idx < tasks.length) {
await sleep(100);
}
console.log("✅ Fertig.");
}
main().catch((e) => {
console.error("Unerwarteter Fehler:", e);
process.exit(1);
});
/*
kann ich auch mit node die isolationswiderstand DIA0 bis DIA2 für den Slot 0 aufrufen
fetchCableData.mjs
:175
Ill show the exact Node commands to fetch Isolationswiderstand (type 3) for slot 0 across DIA0DIA2 with the new script.
Checklist
Slot 0 only
Type iso (Isolationswiderstand)
All modes DIA0, DIA1, DIA2
Optional explicit date range
Basic Auth + self-signed TLS
Run (last 30 days, all DIA modes)
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --insecure
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --insecure
Run with explicit date range (e.g., 2025-07-13 → 2025-08-12)
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --from 2025-07-13 --to 2025-08-12 --insecure
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --from 2025-07-13 --to 2025-08-12 --insecure
Add credentials explicitly (if needed)
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --from 2025-07-13 --to 2025-08-12 --user Littwin --pass Littwin --insecure
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --from 2025-07-13 --to 2025-08-12 --user Littwin --pass Littwin --insecure
Notes
By default, the script fetches all modes DIA0,DIA1,DIA2; you can restrict with: --modes DIA0,DIA1,DIA2.
Output goes to:
mocks/device-cgi-simulator/cable-monitoring-data/slot0/isolationswiderstand/DIA{0|1|2}.json
The --insecure flag accepts the devices selfsigned certificate.
//----
npm run mocks:cable--silent , npm wartet bis das fertig ist
*/