255 lines
7.9 KiB
JavaScript
255 lines
7.9 KiB
JavaScript
#!/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
|
||
I’ll show the exact Node commands to fetch Isolationswiderstand (type 3) for slot 0 across DIA0–DIA2 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 device’s self‑signed certificate.
|
||
//----
|
||
|
||
npm run mocks:cable--silent , npm wartet bis das fertig ist
|
||
|
||
*/
|