Un temoin sain, et l'historique de toute une chaine par un seul branchement

datalist reste local, mais data <adresse> history <n> est adressable
et rend l'enregistrement complet, quinze cellules comprises. Les trois
modules de la chaine ancienne sont donc extraits d'un seul
branchement, tous corriges du meme decalage lu au chronometre : 369
minutes. Les jeux sont enfin comparables entre eux, ce que les
decalages deduits - divergents de deux heures et demie - ne
permettaient pas.

Le module d'adresse 2 donne le temoin qui manquait : meme chaine,
memes courants, memes journees, et ses quinze cellules tiennent dans
onze millivolts d'amplitude les unes des autres, ecart median 6 mV.
Ce qui a tue les autres ne vient donc ni du regime de charge, ni du
pilotage, ni de l'installation.

Sur cette base commune la cellule 14 du module ...0322 passe a 273 mV
et rejoint les atteintes : dix cellules, pas neuf.

L'horloge se propage bien du maitre a sa chaine - j'avais conclu
l'inverse en verifiant une seconde apres l'ecriture, il en faut vingt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
Tallagrand Thierry
2026-09-05 16:20:58 +02:00
parent 8cf25114f8
commit 8d076603de
10 changed files with 5465 additions and 30 deletions

View File

@@ -238,6 +238,60 @@ async function main() {
return;
}
// --historique-distant <adresse> : l'historique d'un AUTRE module de la
// chaine. `datalist` est local, mais `data <adresse> history <n>` est
// adressable et rend l'enregistrement complet, quinze cellules comprises.
// Un seul branchement par chaine suffit donc pour tout son historique.
if (arg('historique-distant')) {
const ad = parseInt(String(arg('historique-distant')), 10);
if (!(ad >= 1 && ad <= 16)) { console.log('Adresse invalide.'); process.exit(1); }
// Le decalage se mesure AVANT, car les enregistrements stockes portent
// l'heure qu'avait le module quand il les a ecrits.
const rtc = await commande(l, 'time', 8000);
const mr = rtc.match(/RTC\s+(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/);
let decMs = 0;
if (mr) {
const [d, h] = mr[1].split(' ');
const [A, M, J] = d.split('-').map(Number); const [H, N, S] = h.split(':').map(Number);
decMs = new Date(A, M - 1, J, H, N, S).getTime() - Date.now();
console.log(`Horloge du module : ${mr[1]} — ${Math.round(decMs / 60000)} min d'avance, corriges a l'ecriture.`);
} else {
console.log('Horloge non lue : les horodatages seront ceux du module, non corriges.');
}
const info = await commande(l, `info ${ad}`, 8000);
const bc = (info.match(/Barcode\s*:\s*(\S+)/) || [])[1] || `adresse${ad}`;
const f = path.join(DOSSIER, `${tampon()}-histo-distant-${bc}.csv`);
fs.mkdirSync(DOSSIER, { recursive: true });
fs.writeFileSync(f, 'heure_reelle,module,etat,courant_mA,soc,' +
Array.from({ length: 15 }, (_, i) => `c${i + 1}_mV`).join(',') + ',ecart_mV\n');
console.log(`Module ${bc} (adresse ${ad}) -> ${f}`);
let ecrits = 0, vides = 0;
for (let n = 1; n <= 1800; n++) {
const t = await commande(l, `data ${ad} history ${n}`, 8000);
const mt = t.match(/Time\s*:\s*(\d\d-\d\d-\d\d \d\d:\d\d:\d\d)/);
const cel = cellules(t);
if (!mt || !cel || cel.length < 15) {
if (++vides > 20) break; // fin du tampon
continue;
}
vides = 0;
const [d, h] = mt[1].split(' ');
const [A, M, J] = d.split('-').map(Number); const [H, N, S] = h.split(':').map(Number);
const quand = new Date(new Date(2000 + A, M - 1, J, H, N, S).getTime() - decMs);
const v = cel.map((c) => c.mV);
const soc = (t.match(/Percent\s*:\s*(\d+)/) || [])[1] || '';
fs.appendFileSync(f, [quand.toISOString(), bc, cel[0].etat, cel[0].mA, soc,
...v, Math.max(...v) - Math.min(...v)].join(',') + '\n');
ecrits++;
if (n % 25 === 0) process.stdout.write(`\r ${n} interroges, ${ecrits} ecrits `);
}
console.log(`\n${ecrits} enregistrements ecrits dans ${f}`);
return;
}
if (arg('suivi')) {
const pas = Math.max(10, +(arg('suivi', '30')) || 30);
const nom = `${tampon()}-suivi.csv`;