// Energie delivree par POINT de SOC, mesuree point par point. // Methode : pour chaque palier ou le SOC reste a la valeur v puis DESCEND a // v-1, on integre la puissance batterie sur ce palier. Uniquement si la // batterie decharge tout du long et si le reseau n'apporte rien (sinon la // mesure porte sur autre chose que la batterie). import fs from 'node:fs'; const ROOT='/mnt/projects/EVCS/EVCS'; function token(){for(const l of fs.readFileSync(ROOT+'/.env','utf8').split('\n')){const m=l.match(/^\s*HA_TOKEN\s*=\s*(.+?)\s*$/);if(m)return m[1].replace(/^["']|["']$/g,'');}throw 0;} const HA='http://10.10.10.17:8123';const H={Authorization:'Bearer '+token()}; async function hist(ent,t0,t1){ const u=`${HA}/api/history/period/${t0.toISOString()}?end_time=${t1.toISOString()}&filter_entity_id=${ent}&minimal_response&significant_changes_only=0`; const d=await (await fetch(u,{headers:H})).json(); return (d[0]||[]).map(s=>({t:new Date(s.last_changed||s.last_updated).getTime(),v:Number(s.state)})).filter(p=>Number.isFinite(p.v)); } const DAYS=Number(process.argv[2]||8); const end=new Date(process.argv[3]||Date.now()); const bins={}; // soc -> {kwh, count, secs} let paliers=0, rejetes=0; for(let d=0; d{let v=null;for(const p of arr){if(p.t<=t)v=p.v;else break;}return v;}; // paliers de SOC for(let i=0;i 4*3600000) { rejetes++; continue; } // integration de la puissance batterie sur [a,b], et controle reseau const pts=bp.filter(p=>p.t>=a&&p.t<=b); const first=at(bp,a); if(first===null) { rejetes++; continue; } const seq=[{t:a,v:first},...pts,{t:b,v:pts.length?pts[pts.length-1].v:first}]; let kwh=0, positif=false; for(let k=0;k50) positif=true; // la batterie s'est mise a charger kwh += -seq[k].v*dt/1000; } if(positif||kwh<=0){ rejetes++; continue; } // reseau : on rejette si import moyen significatif const gpts=grid.filter(p=>p.t>=a&&p.t<=b); const g0=at(grid,a); const gseq=[{t:a,v:g0===null?0:g0},...gpts]; let gkwh=0; for(let k=0;k0)gkwh+=gseq[k].v*dt/1000;} if(gkwh>0.02){ rejetes++; continue; } const key=Math.round(v); bins[key]=bins[key]||{kwh:0,n:0}; bins[key].kwh+=kwh; bins[key].n++; paliers++; } } console.log(`paliers retenus: ${paliers} | rejetes: ${rejetes}`); const keys=Object.keys(bins).map(Number).sort((a,b)=>a-b); console.log('\nSOC n kWh/point'); for(const k of keys) console.log(String(k).padStart(3), String(bins[k].n).padStart(3), (bins[k].kwh/bins[k].n).toFixed(3).padStart(7)); // regroupement par tranches de 10 console.log('\ntranche paliers kWh/point capacite implicite'); for(let lo=15; lo<100; lo+=10){ const ks=keys.filter(k=>k>=lo&&ks+bins[k].n,0), e=ks.reduce((s,k)=>s+bins[k].kwh,0); if(!n) continue; console.log(`${lo}-${lo+9}`.padEnd(9), String(n).padStart(7), (e/n).toFixed(3).padStart(11), (100*e/n).toFixed(1).padStart(18),'kWh'); }