Le courant par module entre dans les CSV de releve
La colonne courant_mA etait vide depuis la mise en service : le mode --modules interroge chaque adresse avec soh <n>, qui donne les quinze tensions mais AUCUN courant. La source juste est pwr, qui rend courant, tension et SOC pour TOUS les modules en un seul appel — une commande serie par cycle au lieu d'une par module. ⚠️ LE TABLEAU pwr N'A PAS LES MEMES COLONNES SELON LA FAMILLE DE MODULES. Mesure du 16/09 : les US5000 (firmware B69.26) intercalent Tlow.Id, Thigh.Id, Vlow.Id et Vhigh.Id que les US2000C (B69.13) n'ont pas. Un parseur a index figes lit donc n'importe quoi des qu'on change de pack — c'est la meme famille de piege que le trou de 44 h. Les colonnes sont resolues PAR LEUR NOM dans l'en-tete. Les trois utiles (Volt, Curr, Coulomb) precedent Time, dont la valeur contient une espace, donc le decoupage positionnel reste valable. Echec de pwr non bloquant : on ecrit la ligne sans courant plutot que de perdre les tensions, qui sont l'essentiel du releve. Verifie sur cinq modules, trois cycles : courant et SOC par module dans le journal et dans le CSV. Pack 2 a 13:18 — 9,5 + 9,4 + 9,0 + 9,2 + 9,1 = 46,2 A, SOC 82/79/83/81/87 %. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
This commit is contained in:
@@ -332,6 +332,43 @@ async function main() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// COURANT PAR MODULE — un seul `pwr` pour toute la chaine
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// `soh <n>` donne les quinze tensions mais AUCUN courant : c'est pourquoi la
|
||||||
|
// colonne courant_mA du CSV est restee vide depuis la mise en service.
|
||||||
|
// `pwr` donne courant, tension et SOC pour TOUS les modules en un appel —
|
||||||
|
// une commande serie par cycle au lieu d'une par module.
|
||||||
|
//
|
||||||
|
// ⚠️ LE TABLEAU N'A PAS LES MEMES COLONNES SELON LA FAMILLE DE MODULES.
|
||||||
|
// Mesure du 16/09 : les US5000 (firmware B69.26) intercalent Tlow.Id,
|
||||||
|
// Thigh.Id, Vlow.Id et Vhigh.Id que les US2000C (B69.13) n'ont pas. Un
|
||||||
|
// parseur a index figes lit donc n'importe quoi des qu'on change de pack.
|
||||||
|
// On resout les colonnes PAR LEUR NOM, dans l'en-tete.
|
||||||
|
//
|
||||||
|
// Les colonnes utiles (Volt, Curr, Coulomb) precedent toutes `Time`, dont la
|
||||||
|
// valeur contient une espace — le decoupage positionnel reste donc valable.
|
||||||
|
function courantsParModule(txt) {
|
||||||
|
const lignes = txt.split('\n').map((l) => l.replace(/\r/g, '').trimEnd());
|
||||||
|
const iEntete = lignes.findIndex((l) => /^\s*Power\s+Volt\s+Curr\b/.test(l));
|
||||||
|
if (iEntete === -1) return new Map();
|
||||||
|
const cols = lignes[iEntete].trim().split(/\s+/);
|
||||||
|
const iCurr = cols.indexOf('Curr');
|
||||||
|
const iVolt = cols.indexOf('Volt');
|
||||||
|
const iSoc = cols.indexOf('Coulomb');
|
||||||
|
if (iCurr === -1) return new Map();
|
||||||
|
const m = new Map();
|
||||||
|
for (const l of lignes.slice(iEntete + 1)) {
|
||||||
|
const c = l.trim().split(/\s+/);
|
||||||
|
const ad = parseInt(c[0], 10);
|
||||||
|
if (!Number.isFinite(ad) || c[iCurr] === undefined || c[iCurr] === '-') continue;
|
||||||
|
const mA = parseInt(c[iCurr], 10);
|
||||||
|
if (!Number.isFinite(mA)) continue;
|
||||||
|
m.set(ad, { mA, mV: parseInt(c[iVolt], 10) || null, soc: iSoc > -1 ? c[iSoc] : null });
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg('suivi')) {
|
if (arg('suivi')) {
|
||||||
const pas = Math.max(10, +(arg('suivi', '30')) || 30);
|
const pas = Math.max(10, +(arg('suivi', '30')) || 30);
|
||||||
const nom = `${horodateFichier()}-suivi.csv`;
|
const nom = `${horodateFichier()}-suivi.csv`;
|
||||||
@@ -370,6 +407,12 @@ async function main() {
|
|||||||
console.log('Ctrl-C pour arreter.\n');
|
console.log('Ctrl-C pour arreter.\n');
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (adresses.length) {
|
if (adresses.length) {
|
||||||
|
// Un `pwr` pour toute la chaine, avant la boucle par module. Si la
|
||||||
|
// lecture echoue on continue sans courant plutot que de perdre les
|
||||||
|
// tensions, qui sont l'essentiel du releve.
|
||||||
|
let puis = new Map();
|
||||||
|
try { puis = courantsParModule(await commande(l, 'pwr', 10000)); }
|
||||||
|
catch { /* on garde les tensions */ }
|
||||||
for (const ad of adresses) {
|
for (const ad of adresses) {
|
||||||
const t = await commande(l, `soh ${ad}`, 10000);
|
const t = await commande(l, `soh ${ad}`, 10000);
|
||||||
// `soh` : "<n0based> <mV> <SOHCount> <statut>"
|
// `soh` : "<n0based> <mV> <SOHCount> <statut>"
|
||||||
@@ -381,9 +424,12 @@ async function main() {
|
|||||||
if (c.length < 10) { console.log(`${horodate()} module ${ad} : illisible`); continue; }
|
if (c.length < 10) { console.log(`${horodate()} module ${ad} : illisible`); continue; }
|
||||||
const v = c.map((x) => x.mV);
|
const v = c.map((x) => x.mV);
|
||||||
const hi = Math.max(...v), lo = Math.min(...v);
|
const hi = Math.max(...v), lo = Math.min(...v);
|
||||||
fs.appendFileSync(f, [new Date().toISOString(), codes.get(ad), '', ...v, hi - lo].join(',') + '\n');
|
const p = puis.get(ad);
|
||||||
|
fs.appendFileSync(f, [new Date().toISOString(), codes.get(ad),
|
||||||
|
p ? p.mA : '', ...v, hi - lo].join(',') + '\n');
|
||||||
console.log(`${horodate()} ${codes.get(ad).slice(-4)} haute ${hi} mV (cellule ${c.find((x) => x.mV === hi).n})` +
|
console.log(`${horodate()} ${codes.get(ad).slice(-4)} haute ${hi} mV (cellule ${c.find((x) => x.mV === hi).n})` +
|
||||||
` basse ${lo} mV ecart ${String(hi - lo).padStart(3)} mV` +
|
` basse ${lo} mV ecart ${String(hi - lo).padStart(3)} mV` +
|
||||||
|
(p ? ` ${(p.mA / 1000).toFixed(1)} A ${p.soc || ''}` : '') +
|
||||||
(hi >= 3600 ? ' NIVEAU 4' : hi >= 3550 ? ' NIVEAU 3, le courant se reduit' : ''));
|
(hi >= 3600 ? ' NIVEAU 4' : hi >= 3550 ? ' NIVEAU 3, le courant se reduit' : ''));
|
||||||
}
|
}
|
||||||
await new Promise((r) => setTimeout(r, pas * 1000));
|
await new Promise((r) => setTimeout(r, pas * 1000));
|
||||||
|
|||||||
Reference in New Issue
Block a user