Le releve continu, et le code-barres dans le CSV plutot que l'adresse
Le suivi n'ecrivait que l'adresse du module, traduite a l'import par une table figee sur le pack ancien. Le cable ayant change de pack, tout releve fait maintenant aurait ete attribue aux mauvais modules. Le code-barres est desormais resolu au demarrage et ecrit dans le CSV ; la table ne sert plus qu'aux anciens fichiers. Le releve tourne sur le poste qui porte le cable serie - le port USB est la, pas sur le Synology - et n'ecrit qu'un CSV dans le depot partage. C'est le service d'historisation, cote Synology, qui le verse en base : le poste n'a donc aucun mot de passe a connaitre. Archive pour le constructeur : un dossier par code-barres, plus un manifeste en francais, anglais et chinois qui dit ou regarder en premier et signale que les CSV sont deja corriges de la derive d'horloge des BMS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
@@ -515,6 +515,49 @@ async function ecrireSession(sql, client, st) {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Verse dans la base les relevés de cellule deposes par le poste qui porte le
|
||||
// cable serie. Celui-ci n'ecrit qu'un CSV dans le depot partage : il n'a donc
|
||||
// aucun mot de passe de base a connaitre, et le service d'ici, qui l'a deja,
|
||||
// fait l'ingestion. `ON CONFLICT DO NOTHING` rend l'operation idempotente,
|
||||
// donc relire le meme fichier a chaque cycle ne coute qu'une requete.
|
||||
const DOSSIER_CELLULES = 'docs/mesures/batteries';
|
||||
async function ingererCellules(client) {
|
||||
let fichiers;
|
||||
try { fichiers = fs.readdirSync(DOSSIER_CELLULES); } catch { return 0; }
|
||||
let lignes = 0;
|
||||
for (const n of fichiers) {
|
||||
if (!n.endsWith('-suivi.csv')) continue;
|
||||
const f = path.join(DOSSIER_CELLULES, n);
|
||||
// Seuls les fichiers vivants : un releve arrete depuis plus d'une heure a
|
||||
// deja ete verse, le relire serait du bruit.
|
||||
if (Date.now() - fs.statSync(f).mtimeMs > 3600000) continue;
|
||||
const l = fs.readFileSync(f, 'utf8').trim().split('\n');
|
||||
const cols = l[0].split(',');
|
||||
const iC = cols.indexOf('c1_mV');
|
||||
if (iC < 0) continue;
|
||||
const val = [];
|
||||
for (const ligne of l.slice(1)) {
|
||||
const c = ligne.split(',');
|
||||
if (c.length < iC + 15) continue;
|
||||
if (!/^[A-Z]\d{6}[A-Z]\d+$/.test(c[1])) continue; // sans code-barres, on ne devine pas
|
||||
for (let k = 0; k < 15; k++) {
|
||||
const mv = Number(c[iC + k]);
|
||||
if (!(mv > 1000)) continue;
|
||||
val.push([c[0], c[1], k + 1, mv, null, null, null, 'suivi']);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < val.length; i += 500) {
|
||||
const lot = val.slice(i, i + 500);
|
||||
const ph = lot.map((_, k) => `($${k * 8 + 1},$${k * 8 + 2},$${k * 8 + 3},$${k * 8 + 4},$${k * 8 + 5},$${k * 8 + 6},$${k * 8 + 7},$${k * 8 + 8})`).join(',');
|
||||
const r = await client.query(
|
||||
`INSERT INTO cellule (ts, module, cellule, mv, soc, courant_ma, etat, source)
|
||||
VALUES ${ph} ON CONFLICT (ts, module, cellule) DO NOTHING`, lot.flat());
|
||||
lignes += r.rowCount;
|
||||
}
|
||||
}
|
||||
return lignes;
|
||||
}
|
||||
|
||||
async function cycle(client) {
|
||||
// En blanc, on compte ce qu'on ECRIRAIT. Un essai a blanc qui renvoie
|
||||
// toujours zero ne verifie rien — c'est le piege classique du test qui ne
|
||||
@@ -535,13 +578,20 @@ async function cycle(client) {
|
||||
prevision: await ecrirePrevision(sql, st),
|
||||
session: await ecrireSession(sql, client, st),
|
||||
evenement: await detecterEvenements(sql, st),
|
||||
// Ingestion des relevés de cellule deposes par le poste au cable serie.
|
||||
// Hors essai a blanc : l'insertion est massive et idempotente, la simuler
|
||||
// n'apprendrait rien.
|
||||
cellules: DRY ? 0 : await ingererCellules(client).catch((e) => {
|
||||
console.error(`ingestion cellules en echec : ${e.message}`);
|
||||
return 0;
|
||||
}),
|
||||
};
|
||||
const total = r.mesures + r.bilan + r.decision + r.prevision + r.evenement + r.session;
|
||||
const total = r.mesures + r.bilan + r.decision + r.prevision + r.evenement + r.session + r.cellules;
|
||||
if (total > 0 || ONCE) {
|
||||
console.log(
|
||||
`${new Date().toLocaleString('fr-FR', { timeZone: 'Europe/Paris' })} ` +
|
||||
`${DRY ? '[BLANC] ' : ''}mesures=${r.mesures} bilan=${r.bilan} ` +
|
||||
`decision=${r.decision} prevision=${r.prevision} session=${r.session} evenement=${r.evenement}`
|
||||
`decision=${r.decision} prevision=${r.prevision} session=${r.session} evenement=${r.evenement} cellules=${r.cellules}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user