Arbitre : voiture qui ne charge pas avec EDF ferme (tout etat), alerte recharge bridee
This commit is contained in:
@@ -27,28 +27,52 @@ const VOITURE_ABSENTE_OU_PLEINE = /not_connected|done|full|complete|charged/i;
|
||||
* sourceMode, etat, raison : controleur de la borne
|
||||
* vehicule : selecteur (VW, JEEP, ZERO)
|
||||
* modeNuit : 'sans_edf' | 'complete'
|
||||
* sessionEngagee, manqueKwh, soc, batterieA, dvccA : recharge de la batterie (cas 2)
|
||||
* @returns {null | { cas, question, choix: [{ cle, libelle, ordre: null | { ordre, valeur } }] }}
|
||||
* choix vide = ALERTE : rien a decider, seulement a signaler.
|
||||
*/
|
||||
export function detecterSituation(e) {
|
||||
// CAS 1 — voiture branchee, non pleine, bloquee, alors qu'EDF est deja ferme
|
||||
// en heures creuses. Cause de la nuit du 07-08/10 (VW bloquee 01:24-05:14).
|
||||
// CAS 1 — voiture branchee, non pleine, qui NE CHARGE PAS alors qu'EDF est deja
|
||||
// ferme en heures creuses. Nuit du 07-08/10 : VW « bloquee » (sans EDF) de 01:24
|
||||
// a 05:14. Elargi le 10/10 : HC de midi du 09/10, JEEP en « Reseau HC autorise »
|
||||
// mais « conditions de demarrage non reunies » — quel que soit l'etat du
|
||||
// controleur, une voiture branchee qui ne prend rien avec EDF ferme est une
|
||||
// incoherence.
|
||||
if (e.fenetre && e.contacteurOn && e.voitureBranchee && Number(e.borneW) < 100
|
||||
&& /bloqu/i.test(e.sourceMode || '') && !VOITURE_ABSENTE_OU_PLEINE.test(e.etat || '')) {
|
||||
&& !VOITURE_ABSENTE_OU_PLEINE.test(e.etat || '')) {
|
||||
const v = e.vehicule || 'la voiture';
|
||||
const nuit = e.fenetre === 'nuit';
|
||||
if (nuit && e.modeNuit === 'complete') return null; // deja autorisee : ce n'est pas un choix
|
||||
const bloqueeSansEdf = /bloqu/i.test(e.sourceMode || '');
|
||||
if (nuit && bloqueeSansEdf && e.modeNuit === 'complete') return null; // deja autorisee
|
||||
// La nuit en « sans EDF », le levier est le mode de nuit ; sinon force_grid_now,
|
||||
// qui expire seul a la fin des heures creuses.
|
||||
const levierMode = nuit && bloqueeSansEdf;
|
||||
return {
|
||||
cas: 'voiture_bloquee_edf_ferme',
|
||||
question: `${v} est branchee et ne charge pas, alors qu'EDF est ferme en heures creuses (jusqu'a ${e.finFenetre || 'la fin de la fenetre'}). `
|
||||
+ `Raison du controleur : « ${String(e.raison || 'inconnue').split('|')[0].trim()} ». Que fais-je ?`,
|
||||
choix: [
|
||||
nuit
|
||||
levierMode
|
||||
? { cle: '1', libelle: `Charger ${v} sur EDF jusqu'a ${e.finFenetre || '07:24'} (mode de nuit « complete »)`, ordre: { ordre: 'mode_nuit', valeur: 'complete' } }
|
||||
: { cle: '1', libelle: `Charger ${v} sur EDF jusqu'a ${e.finFenetre || '14:24'} (« force_grid_now », expire en fin d'heures creuses)`, ordre: { ordre: 'strategie', valeur: 'force_grid_now' } },
|
||||
{ cle: '2', libelle: 'Laisser en attente (rien ne change)', ordre: null },
|
||||
],
|
||||
};
|
||||
}
|
||||
// CAS 2 — ALERTE (pas de choix) : la batterie a un manque a reprendre pendant
|
||||
// une session HC, et elle recoit moins de la moitie du courant que l'ACM
|
||||
// autorise. HC de midi du 09/10 : 32 A pour 140 A (consigne qui descendait,
|
||||
// tension 50,1 V). Rien a decider pour le proprietaire : c'est un defaut a
|
||||
// corriger PENDANT l'heure creuse, pas le lendemain dans la revue.
|
||||
if (e.fenetre && e.contacteurOn && e.sessionEngagee && Number(e.manqueKwh) > 0.5
|
||||
&& Number(e.soc) < 95 && Number(e.dvccA) > 20 && Number(e.batterieA) < 0.5 * Number(e.dvccA)) {
|
||||
return {
|
||||
cas: 'recharge_bridee',
|
||||
question: `Recharge bridee en heures creuses de ${e.fenetre} : la batterie recoit ${Math.round(Number(e.batterieA))} A pour ${Math.round(Number(e.dvccA))} A autorises, `
|
||||
+ `alors qu'il reste ${Math.round(Number(e.manqueKwh) * 10) / 10} kWh a reprendre (SOC ${Math.round(Number(e.soc))} %). Signale-le a la session EVCS pour qu'elle corrige avant ${e.finFenetre || 'la fin de la fenetre'}.`,
|
||||
choix: [],
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -2129,6 +2129,11 @@ async function arbitrer(sql, client, st) {
|
||||
raison: txt(st.get('input_text.victron_evcs_surplus_reason')?.state),
|
||||
vehicule: txt(st.get('input_select.victron_evcs_vehicle')?.state),
|
||||
modeNuit: txt(st.get('input_select.victron_evcs_night_charge_mode')?.state),
|
||||
sessionEngagee: txt(st.get('input_boolean.victron_evcs_night_grid_session_committed')?.state) === 'on',
|
||||
manqueKwh: Number(st.get('input_number.evcs_balance_grid_energy_needed_kwh')?.state),
|
||||
soc: Number(st.get('sensor.victron_battery_soc')?.state),
|
||||
batterieA: Number(st.get('sensor.victron_battery_current')?.state),
|
||||
dvccA: Number(st.get('sensor.victron_max_charge_current_setting')?.state),
|
||||
});
|
||||
const { rows: [ouvert] } = await client.query(`SELECT * FROM arbitrage WHERE ferme IS NULL ORDER BY ouvert DESC LIMIT 1`);
|
||||
const publier = (etat, a) => publierCapteur('sensor.evcs_arbitrage', etat, { friendly_name: 'Arbitrage demande au proprietaire', ...a });
|
||||
@@ -2155,15 +2160,17 @@ async function arbitrer(sql, client, st) {
|
||||
await client.query(`INSERT INTO arbitrage (id, cas, question, choix, depuis) VALUES ($1,$2,$3,$4,$5) ON CONFLICT DO NOTHING`,
|
||||
[id, sit.cas, sit.question, JSON.stringify(sit.choix), new Date(arbitrageCandidat.depuis)]);
|
||||
await journaliser(sql, 'arbitrage', `Arbitrage demande : ${sit.cas}`, { id, question: sit.question });
|
||||
await publier('question', { id, cas: sit.cas, question: sit.question,
|
||||
// Sans choix = ALERTE (10/10) : rien a decider, seulement a signaler.
|
||||
await publier(sit.choix.length ? 'question' : 'alerte', { id, cas: sit.cas, question: sit.question,
|
||||
choix: sit.choix.map((c) => ({ cle: c.cle, libelle: c.libelle })),
|
||||
depuis: new Date(arbitrageCandidat.depuis).toISOString(),
|
||||
consigne: 'Repondre par le numero du choix. Seul l ordre attache au choix est applique.' });
|
||||
consigne: sit.choix.length ? 'Repondre par le numero du choix. Seul l ordre attache au choix est applique.'
|
||||
: 'Alerte : rien a repondre.' });
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Reponse du proprietaire, par le concierge.
|
||||
if (!ouvert.reponse_cle) {
|
||||
// Reponse du proprietaire, par le concierge (pas pour une alerte).
|
||||
if (!ouvert.reponse_cle && (ouvert.choix || []).length) {
|
||||
let rep = null;
|
||||
try { rep = JSON.parse(txt(st.get('input_text.evcs_arbitrage_reponse')?.state) || 'null'); } catch { rep = null; }
|
||||
if (rep && rep.id === ouvert.id) {
|
||||
|
||||
Reference in New Issue
Block a user