Nouvelle pageBootNotification aux bornes FAULTED
/**
- Script TURBO – Envoi BootNotification RAPIDE aux bornes FAULTED
- Optimisations :
-
- Traitement en parallèle (par lots de 10)
-
- Suppression des délais artificiels
- Utilisation :
-
- Faire un "Refresh" (F5) de la page pour nettoyer l'ancien script
-
- Coller ce nouveau script
-
- Lancer : triggerBootNotificationToFaultedStations() */
let stopBootNotificationScriptFlag = false;
function stopBootNotificationScript() { stopBootNotificationScriptFlag = true; console.log("🛑 Arrêt du script demandé..."); }
function getStationId(station) { return ( station.id ?? station.chargingStationId ?? station.stationId ?? station.idChargingStation ?? null ); }
async function triggerBootNotificationToFaultedStations(customApiUrl = null) { stopBootNotificationScriptFlag = false; console.log("🚀 Envoi BootNotification TURBO aux bornes FAULTED");
try { // 🔑 Auth & Config const token = localStorage.getItem("token"); if (!token) throw new Error("Token non trouvé");
const selectedRole = JSON.parse(localStorage.getItem("selectedRole") || "{}");
if (!selectedRole.groupId) throw new Error("groupId manquant");
const groupId = selectedRole.groupId;
const origin = window.location.origin;
let API_URL = customApiUrl || (origin.includes("localhost") ? origin.replace(":4200", ":3000") : origin + "/api");
console.log(`🔗 API: ${API_URL} | Groupe: ${groupId}`);
// =========================
// 1. Récupération (Pagination)
// =========================
const pageSize = 100; // Max souvent autorisé
let page = 1;
let hasMorePages = true;
let allStations = [];
console.log("📡 Récupération des bornes FAULTED...");
while (hasMorePages && !stopBootNotificationScriptFlag) {
const url = `${API_URL}/charging-stations/group/${groupId}/list?offset=${(page - 1) * pageSize}&limit=${pageSize}&status=faulted`;
const res = await fetch(url, {
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" }
});
if (!res.ok) throw new Error(`Erreur HTTP listing: ${res.status}`);
const data = await res.json();
const records = data.records || data; // Gérer format {records: [], count: n} ou [records]
allStations = allStations.concat(records);
const totalRecords = parseInt(res.headers.get("X-Total-Count") || "0");
const totalPages = Math.ceil(totalRecords / pageSize);
console.log(`✅ Page ${page}/${totalPages || '?'} (+${records.length} bornes)`);
if (records.length === 0 || page >= totalPages) {
hasMorePages = false;
} else {
page++;
}
}
// =========================
// 2. Filtrage & Préparation
// =========================
// On garde uniquement celles avec un ID valide (le filtre status est fait par l'API)
const stationsToprocess = allStations
.map(s => ({ ...s, _stationId: getStationId(s) }))
.filter(s => s._stationId != null);
console.log(`📋 ${stationsToprocess.length} bornes FAULTED prêtes à être traitées.`);
if (stationsToprocess.length === 0) return console.warn("⚠️ Rien à traiter.");
if (!confirm(`🚀 GO pour envoyer BootNotification à ${stationsToprocess.length} bornes en MODE ACCÉLÉRÉ ?`)) {
return console.log("❌ Opération annulée");
}
// =========================
// 3. Traitement Parallèle (Concurrency Queue)
// =========================
const CONCURRENCY_LIMIT = 10; // Nombre de requêtes simultanées
let finishedCount = 0;
let successCount = 0;
let errorCount = 0;
// Fonction worker : consomme la liste tant qu'il y en a
const processQueue = async (workerId) => {
while (stationsToprocess.length > 0 && !stopBootNotificationScriptFlag) {
const station = stationsToprocess.shift(); // Prend le prochain élément
const name = station.name || station.chargeboxIdentity || station._stationId;
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10s timeout par requête
const res = await fetch(`${API_URL}/ocpp/trigger-message/${station._stationId}`, {
method: "POST",
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
body: JSON.stringify({ command: "BootNotification", connector: 0 }),
signal: controller.signal
}).finally(() => clearTimeout(timeoutId));
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const json = await res.json();
const status = json?.result?.status || json?.status || json?.[0]?.result?.status;
if (String(status).toLowerCase() === "accepted") {
successCount++;
console.log(`✅ [${++finishedCount}] ${name}`);
} else {
throw new Error(`Refusé (${status})`);
}
} catch (err) {
errorCount++;
console.warn(`❌ [${++finishedCount}] ${name} : ${err.message}`);
}
}
};
console.log(`🔥 Démarrage de ${CONCURRENCY_LIMIT} workers parallèles...`);
// Lancer les workers
const workers = [];
for (let i = 0; i < CONCURRENCY_LIMIT; i++) {
workers.push(processQueue(i));
}
await Promise.all(workers);
console.log("\n==============================");
console.log("🏁 TERMINÉ");
console.log("==============================");
console.log(`✅ Succès: ${successCount}`);
console.log(`❌ Échecs: ${errorCount}`);
console.log("==============================");
} catch (err) { console.error("❌ Erreur fatale:", err); } }
// Exposition globale window.triggerBootNotificationToFaultedStations = triggerBootNotificationToFaultedStations; window.stopBootNotificationScript = stopBootNotificationScript;
console.log("✅ Script FAULTED TURBO chargé"); console.log("➡️ triggerBootNotificationToFaultedStations()");
No comments to display
No comments to display