Le reseau ne prend plus la place du soleil quand la voiture charge
BOOST 28 A en plein soleil, 11/09 17:02 : consigne reseau calculee a
8242 W (maison 1802 + 28 A x 230), PV effondre a 121 W, reseau 7697 W,
batterie 0 A. L'ESS n'a qu'un moyen de prelever 8,2 kW quand le soleil
en donne 4 : brider les MPPT. La production etait refusee par notre
propre consigne.
Le commentaire qui justifiait une consigne genereuse ("elle ne coute
rien") datait de la nuit du 01/09, ou la PV valait zero. En plein jour
il est faux.
On ne peut pas soustraire la PV mesuree : elle vaut 121 W A CAUSE de
cette consigne. Le proprietaire l'a montre en la baissant a la main a
2280 W -- PV 4758 W en 50 secondes, batterie +9 A. On descend donc par
paliers et on laisse la physique repondre, sur deux signaux incensurables
et deja lus : les chargeurs declarent eux-memes s'ils se BRIDENT, et le
courant batterie dit si on est descendu trop bas.
`off` ne compte pas comme bride : la nuit les six le sont, et les
confondre ferait descendre la consigne au crepuscule -- un oscillateur
de plus. C'est ce que verifie le scenario de nuit.
Plancher : la consigne ne descend jamais sous la maison hors voiture,
garantie du 01/09 et du 04/09. On ne libere que la part voiture.
Golden 84 -> 89. Mutation en quatre directions (descente neutralisee /
`off` recompte comme bride / garde batterie retiree / plancher retire) :
chacune fait tomber un jeu DIFFERENT, aucune garde n'est couverte par
le test d'une autre.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
This commit is contained in:
@@ -1202,7 +1202,8 @@ paliers 35/55/85 et les charges programmées de l'ESS.
|
|||||||
### Acteur non lu n°2 — l'export d'excédent PV
|
### Acteur non lu n°2 — l'export d'excédent PV
|
||||||
`switch.gx_device_dc_coupled_pv_feed_in_excess` = off ·
|
`switch.gx_device_dc_coupled_pv_feed_in_excess` = off ·
|
||||||
`switch.gx_device_ac_coupled_pv_feed_in_excess` = off · `ess_max_feed_in_power`
|
`switch.gx_device_ac_coupled_pv_feed_in_excess` = off · `ess_max_feed_in_power`
|
||||||
= −1. Cohérent avec « sans injection », à confirmer comme voulu.
|
= −1. **Confirme par le proprietaire le 08/09/2026 : « je n'injecte pas c'est imperatif pas negociable ».** Ce n'est donc pas une piste, et l'ecretage de la production a batterie pleine est le corollaire assume de ce choix. La
|
||||||
|
reponse au bridage est du STOCKAGE supplementaire, pas du pilotage.
|
||||||
|
|
||||||
### Ce qui n'est PAS démontré : le bridage du MPPT par la présence d'EDF
|
### Ce qui n'est PAS démontré : le bridage du MPPT par la présence d'EDF
|
||||||
Tentative de preuve sur la seule fenêtre EDF-ON diurne conservée en base
|
Tentative de preuve sur la seule fenêtre EDF-ON diurne conservée en base
|
||||||
|
|||||||
@@ -359,13 +359,89 @@ const gridSessionActive =
|
|||||||
night.nightGridSessionCommitted === true
|
night.nightGridSessionCommitted === true
|
||||||
);
|
);
|
||||||
|
|
||||||
const gridSetpointNeedW = gridSessionActive
|
const gridSetpointCeilingW = clamp(
|
||||||
? clamp(
|
|
||||||
Math.round(derived.houseNonEvcsW + derived.physicalCapA * derived.acVoltageRef),
|
Math.round(derived.houseNonEvcsW + derived.physicalCapA * derived.acVoltageRef),
|
||||||
params.gridSetpointIdleW,
|
params.gridSetpointIdleW,
|
||||||
GRID_SETPOINT_MAX_W
|
GRID_SETPOINT_MAX_W
|
||||||
)
|
);
|
||||||
|
|
||||||
|
const gridSetpointCurrentW = Number.isFinite(parsed.gridSetpointW)
|
||||||
|
? parsed.gridSetpointW
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// CREDIT SOLAIRE SUR LA CONSIGNE (11/09/2026)
|
||||||
|
// =====================================================
|
||||||
|
// Defaut mesure ce jour-la : BOOST 28 A en plein soleil, consigne calculee a
|
||||||
|
// 8242 W (maison 1802 + 28 A x 230). L'ESS n'a qu'un moyen de prelever 8,2 kW
|
||||||
|
// quand le soleil en donne 4 : brider les MPPT. Releve 17:02 -- PV 121 W,
|
||||||
|
// reseau 7697 W, batterie 0 A, SOC 96 %. La production etait refusee, et par
|
||||||
|
// NOTRE consigne. Le commentaire ci-dessus ("une consigne trop HAUTE ne coute
|
||||||
|
// rien") a ete ecrit la nuit du 01/09, ou la PV valait zero : il n'y avait
|
||||||
|
// alors rien a evincer. En plein jour il est faux.
|
||||||
|
//
|
||||||
|
// ⚠️ ON NE PEUT PAS SOUSTRAIRE LA PV MESUREE. Elle vaut 121 W *a cause* de
|
||||||
|
// cette consigne : mesure censuree, la soustraire ne bouge rien et le systeme
|
||||||
|
// reste sur son mauvais equilibre. Preuve le meme jour a 17:22 -- consigne
|
||||||
|
// descendue A LA MAIN a 2280 W : PV 4758 W en 50 secondes, batterie +9 A. La
|
||||||
|
// ressource etait la, seule la consigne l'evincait.
|
||||||
|
//
|
||||||
|
// On DESCEND donc, et on laisse la physique repondre. Deux signaux, tous deux
|
||||||
|
// deja lus et tous deux INCENSURABLES :
|
||||||
|
// - les chargeurs declarent eux-memes s'ils se BRIDENT (mpptLimitedCount).
|
||||||
|
// `off` ne compte pas : la nuit ils sont tous `off` et il n'y a rien a
|
||||||
|
// liberer -- c'est ce qui garantit que le comportement de nuit (§31, §57)
|
||||||
|
// est strictement inchange ;
|
||||||
|
// - le courant batterie dit si on est descendu trop bas, via la politique
|
||||||
|
// par bande de SOC deja calibree (batterySoftBreachNow, §35).
|
||||||
|
// La valeur courante vit dans le GX : l'etat est deja persiste, aucun helper
|
||||||
|
// nouveau n'est necessaire.
|
||||||
|
//
|
||||||
|
// PLANCHER : la consigne ne descend JAMAIS sous la maison hors voiture. C'est
|
||||||
|
// la garantie du 01/09 et du 04/09 -- le reseau, quand le contacteur est ferme
|
||||||
|
// a notre demande, couvre la maison. On ne libere que la part VOITURE, qui est
|
||||||
|
// exactement celle qui evince le solaire. Le solaire pourrait souvent couvrir
|
||||||
|
// la maison en plus, mais l'affirmer demanderait ses propres scenarios.
|
||||||
|
const gridSetpointHouseFloorW = clamp(
|
||||||
|
Math.round(derived.houseNonEvcsW),
|
||||||
|
params.gridSetpointIdleW,
|
||||||
|
GRID_SETPOINT_MAX_W
|
||||||
|
);
|
||||||
|
|
||||||
|
const solarResourceRefused =
|
||||||
|
parsed.mpptReadableCount > 0 && parsed.mpptLimitedCount > 0;
|
||||||
|
|
||||||
|
// Pendant la fenetre d'etablissement (§29) les mesures PV et batterie ne
|
||||||
|
// decrivent aucun regime permanent : on ne descend pas sur elles.
|
||||||
|
const gridSetpointDescendOk =
|
||||||
|
gridSessionActive &&
|
||||||
|
solarResourceRefused &&
|
||||||
|
!batteryPolicy.batterySoftBreachNow &&
|
||||||
|
!derived.gridSettling &&
|
||||||
|
gridSetpointCurrentW !== null;
|
||||||
|
|
||||||
|
let gridSetpointNeedW = gridSessionActive
|
||||||
|
? gridSetpointCeilingW
|
||||||
: params.gridSetpointIdleW;
|
: params.gridSetpointIdleW;
|
||||||
|
let gridSetpointDescending = false;
|
||||||
|
|
||||||
|
if (gridSetpointDescendOk) {
|
||||||
|
// Un chargeur bride PROUVE qu'il reste de la ressource : on peut descendre
|
||||||
|
// franchement. Une descente trop forte est rattrapee au cycle suivant (30 s
|
||||||
|
// ou la batterie porte l'ecart, soit quelques dizaines de Wh), alors qu'une
|
||||||
|
// descente trop timide laisse des kW de solaire refuses pendant dix minutes.
|
||||||
|
const minStepW = Math.max(
|
||||||
|
GRID_SETPOINT_DEADBAND_W,
|
||||||
|
Math.round(params.currentStepUpA * derived.acVoltageRef)
|
||||||
|
);
|
||||||
|
const baseW = Math.min(gridSetpointCurrentW, gridSetpointCeilingW);
|
||||||
|
const gapW = baseW - gridSetpointHouseFloorW;
|
||||||
|
if (gapW > 0) {
|
||||||
|
const stepW = Math.max(minStepW, Math.round(gapW / 2));
|
||||||
|
gridSetpointNeedW = Math.max(gridSetpointHouseFloorW, baseW - stepW);
|
||||||
|
gridSetpointDescending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// La bande est ASYMETRIQUE, et c'est le point. Une consigne trop BASSE fait
|
// La bande est ASYMETRIQUE, et c'est le point. Une consigne trop BASSE fait
|
||||||
// porter la difference par la batterie : c'est le defaut de la nuit du 01/09,
|
// porter la difference par la batterie : c'est le defaut de la nuit du 01/09,
|
||||||
@@ -380,7 +456,7 @@ const gridSetpointNeedW = gridSessionActive
|
|||||||
// consigne insuffisante au cycle suivant, et on ne redescend que si elle est
|
// consigne insuffisante au cycle suivant, et on ne redescend que si elle est
|
||||||
// devenue franchement inutile. Sans cela la boucle 30 s reecrivait a chaque
|
// devenue franchement inutile. Sans cela la boucle 30 s reecrivait a chaque
|
||||||
// cycle en poursuivant le bruit.
|
// cycle en poursuivant le bruit.
|
||||||
const gridSetpointSlackW = gridSessionActive
|
const gridSetpointSlackW = gridSessionActive && !gridSetpointDescending
|
||||||
? Math.max(GRID_SETPOINT_DEADBAND_W, Math.round(params.currentStepUpA * derived.acVoltageRef))
|
? Math.max(GRID_SETPOINT_DEADBAND_W, Math.round(params.currentStepUpA * derived.acVoltageRef))
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
@@ -390,9 +466,6 @@ const gridSetpointTargetW = clamp(
|
|||||||
GRID_SETPOINT_MAX_W
|
GRID_SETPOINT_MAX_W
|
||||||
);
|
);
|
||||||
|
|
||||||
const gridSetpointCurrentW = Number.isFinite(parsed.gridSetpointW)
|
|
||||||
? parsed.gridSetpointW
|
|
||||||
: null;
|
|
||||||
const gridSetpointNeedsWrite =
|
const gridSetpointNeedsWrite =
|
||||||
gridSetpointCurrentW === null ||
|
gridSetpointCurrentW === null ||
|
||||||
gridSetpointCurrentW < gridSetpointNeedW ||
|
gridSetpointCurrentW < gridSetpointNeedW ||
|
||||||
@@ -406,7 +479,11 @@ if (derived.gridSettling) {
|
|||||||
reason.push(`ETABLISSEMENT reseau ${Math.round(parsed.gridTransitionAgeSec)}s/${params.gridSettleSeconds}s (mesures PV/batterie non fiables)`);
|
reason.push(`ETABLISSEMENT reseau ${Math.round(parsed.gridTransitionAgeSec)}s/${params.gridSettleSeconds}s (mesures PV/batterie non fiables)`);
|
||||||
}
|
}
|
||||||
if (gridSessionActive) {
|
if (gridSessionActive) {
|
||||||
reason.push(`Consigne reseau=${gridSetpointTargetW}W`);
|
reason.push(
|
||||||
|
gridSetpointDescending
|
||||||
|
? `Consigne reseau=${gridSetpointTargetW}W (CREDIT SOLAIRE, ${parsed.mpptLimitedCount}/${parsed.mpptReadableCount} brides)`
|
||||||
|
: `Consigne reseau=${gridSetpointTargetW}W`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Visible dans le logbook uniquement pendant un depassement souple : c'est le
|
// Visible dans le logbook uniquement pendant un depassement souple : c'est le
|
||||||
// seul moment ou l'information sert, et la raison est tronquee a 255 caracteres.
|
// seul moment ou l'information sert, et la raison est tronquee a 255 caracteres.
|
||||||
|
|||||||
@@ -264,10 +264,20 @@ const parsed = {
|
|||||||
.map(s => s.trim().toLowerCase())
|
.map(s => s.trim().toLowerCase())
|
||||||
.filter(s => s !== '' && s !== 'unavailable' && s !== 'unknown');
|
.filter(s => s !== '' && s !== 'unavailable' && s !== 'unknown');
|
||||||
const atMaxPower = modes.filter(s => s === 'mppt_active').length;
|
const atMaxPower = modes.filter(s => s === 'mppt_active').length;
|
||||||
|
// Un chargeur qui SE RETIENT (`voltage_current_limited`) prouve qu'il reste
|
||||||
|
// de la ressource refusee. Un chargeur `off` n'a rien a donner : la nuit,
|
||||||
|
// tous le sont. `mpptHoldingBackCount` confond les deux, ce qui est sans
|
||||||
|
// consequence pour la garde de provocation solaire (§37, demarrage de jour
|
||||||
|
// seulement) mais ferait descendre la consigne reseau au crepuscule si on
|
||||||
|
// s'en servait ici — un oscillateur de plus. On compte donc separement ce
|
||||||
|
// qui se declare BRIDE, et tout libelle inconnu retombe du cote prudent
|
||||||
|
// (pas de ressource refusee, donc comportement anterieur).
|
||||||
|
const limited = modes.filter(s => s.includes('limited')).length;
|
||||||
return {
|
return {
|
||||||
mpptReadableCount: modes.length,
|
mpptReadableCount: modes.length,
|
||||||
mpptAtMaxPowerCount: atMaxPower,
|
mpptAtMaxPowerCount: atMaxPower,
|
||||||
mpptHoldingBackCount: modes.length - atMaxPower,
|
mpptHoldingBackCount: modes.length - atMaxPower,
|
||||||
|
mpptLimitedCount: limited,
|
||||||
};
|
};
|
||||||
})(),
|
})(),
|
||||||
pvPowerAvg10mW: Math.max(0, num(input.pv_power_10m_avg_w, num(input.pv_power_w, 0))),
|
pvPowerAvg10mW: Math.max(0, num(input.pv_power_10m_avg_w, num(input.pv_power_w, 0))),
|
||||||
|
|||||||
@@ -2185,4 +2185,121 @@ export const scenarios = [
|
|||||||
gridSetpointW: 700,
|
gridSetpointW: 700,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// ================= CREDIT SOLAIRE SUR LA CONSIGNE (11/09/2026) =================
|
||||||
|
// Releve reel : BOOST 28 A en plein soleil, consigne 8260 W, PV effondre a
|
||||||
|
// 121 W, reseau 7697 W, batterie 0 A. La consigne evincait le solaire.
|
||||||
|
{
|
||||||
|
id: 'consigne-credit-solaire-descend',
|
||||||
|
label: "Releve 11/09 17:02 — BOOST 28 A, 6 trackers brides, batterie neutre : la consigne DESCEND pour rendre la main au solaire",
|
||||||
|
time: '2026-08-08T17:02:00+02:00',
|
||||||
|
overrides: {
|
||||||
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
|
evcs_charging_switch: 'on', control_latch: 'on', charge_permission_now: 'on',
|
||||||
|
last_start_at: '2026-08-08 16:30:00',
|
||||||
|
victron_evcs_strategy: 'force_grid_now',
|
||||||
|
grid_state: 'on', victron_acin1_available: '1',
|
||||||
|
grid_current_max_a: '28', current_max_auto_a: '22',
|
||||||
|
soc_percent: '96',
|
||||||
|
battery_current_a: '0',
|
||||||
|
pv_power_w: '121', pv_power_10m_avg_w: '150', pv_trend_w: '0',
|
||||||
|
house_ac_power_w: '7695', vebus_ac_out_l1_power_w: '7695',
|
||||||
|
evcs_ac_power_w: '5893', evcs_current_a: '28',
|
||||||
|
grid_setpoint_w: '8260',
|
||||||
|
mppt_operation_modes: 'voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
sourceMode: 'grid_forced',
|
||||||
|
gridSetpointW: 5018,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'consigne-credit-trackers-a-fond-pas-de-descente',
|
||||||
|
label: "CONTREFACTUEL — meme instant, mais les 6 trackers en mppt_active : plus rien a liberer, la consigne reste au plafond",
|
||||||
|
time: '2026-08-08T17:02:00+02:00',
|
||||||
|
overrides: {
|
||||||
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
|
evcs_charging_switch: 'on', control_latch: 'on', charge_permission_now: 'on',
|
||||||
|
last_start_at: '2026-08-08 16:30:00',
|
||||||
|
victron_evcs_strategy: 'force_grid_now',
|
||||||
|
grid_state: 'on', victron_acin1_available: '1',
|
||||||
|
grid_current_max_a: '28', current_max_auto_a: '22',
|
||||||
|
soc_percent: '96',
|
||||||
|
battery_current_a: '0',
|
||||||
|
pv_power_w: '121', pv_power_10m_avg_w: '150', pv_trend_w: '0',
|
||||||
|
house_ac_power_w: '7695', vebus_ac_out_l1_power_w: '7695',
|
||||||
|
evcs_ac_power_w: '5893', evcs_current_a: '28',
|
||||||
|
grid_setpoint_w: '8260',
|
||||||
|
mppt_operation_modes: 'mppt_active,mppt_active,mppt_active,mppt_active,mppt_active,mppt_active',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
sourceMode: 'grid_forced',
|
||||||
|
gridSetpointW: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'consigne-credit-batterie-porte-remonte',
|
||||||
|
label: "CONTREFACTUEL — trackers brides MAIS batterie en depassement souple (-60 A) : securite d'abord, la consigne remonte au plafond",
|
||||||
|
time: '2026-08-08T17:02:00+02:00',
|
||||||
|
overrides: {
|
||||||
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
|
evcs_charging_switch: 'on', control_latch: 'on', charge_permission_now: 'on',
|
||||||
|
last_start_at: '2026-08-08 16:30:00',
|
||||||
|
victron_evcs_strategy: 'force_grid_now',
|
||||||
|
grid_state: 'on', victron_acin1_available: '1',
|
||||||
|
grid_current_max_a: '28', current_max_auto_a: '22',
|
||||||
|
soc_percent: '96',
|
||||||
|
battery_current_a: '-60',
|
||||||
|
pv_power_w: '121', pv_power_10m_avg_w: '150', pv_trend_w: '0',
|
||||||
|
house_ac_power_w: '7695', vebus_ac_out_l1_power_w: '7695',
|
||||||
|
evcs_ac_power_w: '5893', evcs_current_a: '28',
|
||||||
|
grid_setpoint_w: '2000',
|
||||||
|
mppt_operation_modes: 'voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
sourceMode: 'grid_forced',
|
||||||
|
gridSetpointW: 8465,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'consigne-credit-nuit-trackers-eteints',
|
||||||
|
label: "ANTI-OSCILLATEUR — nuit HC, session reseau, les 6 trackers `off` : rien a liberer, comportement de nuit STRICTEMENT inchange (§31, §57)",
|
||||||
|
time: NIGHT,
|
||||||
|
overrides: {
|
||||||
|
...VEHICLE_NIGHT,
|
||||||
|
soc_percent: '50',
|
||||||
|
allow_grid_hc_night: 'on',
|
||||||
|
grid_state: 'on',
|
||||||
|
victron_acin1_available: '1',
|
||||||
|
grid_setpoint_w: '5000',
|
||||||
|
mppt_operation_modes: 'off,off,off,off,off,off',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
sourceMode: 'grid_hc_allowed',
|
||||||
|
gridSetpointW: 5525,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'consigne-credit-plancher-maison',
|
||||||
|
label: "La descente s'arrete a la maison hors voiture : le reseau continue de la couvrir (garantie du 01/09 et du 04/09)",
|
||||||
|
time: '2026-08-08T17:02:00+02:00',
|
||||||
|
overrides: {
|
||||||
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
|
evcs_charging_switch: 'on', control_latch: 'on', charge_permission_now: 'on',
|
||||||
|
last_start_at: '2026-08-08 16:30:00',
|
||||||
|
victron_evcs_strategy: 'force_grid_now',
|
||||||
|
grid_state: 'on', victron_acin1_available: '1',
|
||||||
|
grid_current_max_a: '28', current_max_auto_a: '22',
|
||||||
|
soc_percent: '96',
|
||||||
|
battery_current_a: '0',
|
||||||
|
pv_power_w: '4500', pv_power_10m_avg_w: '4500', pv_trend_w: '0',
|
||||||
|
house_ac_power_w: '7695', vebus_ac_out_l1_power_w: '7695',
|
||||||
|
evcs_ac_power_w: '5893', evcs_current_a: '28',
|
||||||
|
grid_setpoint_w: '2000',
|
||||||
|
mppt_operation_modes: 'voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
sourceMode: 'grid_forced',
|
||||||
|
gridSetpointW: 1802,
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user