#!/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 */