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:
@@ -359,13 +359,89 @@ const gridSessionActive =
|
||||
night.nightGridSessionCommitted === true
|
||||
);
|
||||
|
||||
const gridSetpointNeedW = gridSessionActive
|
||||
? clamp(
|
||||
Math.round(derived.houseNonEvcsW + derived.physicalCapA * derived.acVoltageRef),
|
||||
params.gridSetpointIdleW,
|
||||
GRID_SETPOINT_MAX_W
|
||||
)
|
||||
const gridSetpointCeilingW = clamp(
|
||||
Math.round(derived.houseNonEvcsW + derived.physicalCapA * derived.acVoltageRef),
|
||||
params.gridSetpointIdleW,
|
||||
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;
|
||||
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
|
||||
// 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
|
||||
// devenue franchement inutile. Sans cela la boucle 30 s reecrivait a chaque
|
||||
// cycle en poursuivant le bruit.
|
||||
const gridSetpointSlackW = gridSessionActive
|
||||
const gridSetpointSlackW = gridSessionActive && !gridSetpointDescending
|
||||
? Math.max(GRID_SETPOINT_DEADBAND_W, Math.round(params.currentStepUpA * derived.acVoltageRef))
|
||||
: 0;
|
||||
|
||||
@@ -390,9 +466,6 @@ const gridSetpointTargetW = clamp(
|
||||
GRID_SETPOINT_MAX_W
|
||||
);
|
||||
|
||||
const gridSetpointCurrentW = Number.isFinite(parsed.gridSetpointW)
|
||||
? parsed.gridSetpointW
|
||||
: null;
|
||||
const gridSetpointNeedsWrite =
|
||||
gridSetpointCurrentW === null ||
|
||||
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)`);
|
||||
}
|
||||
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
|
||||
// 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())
|
||||
.filter(s => s !== '' && s !== 'unavailable' && s !== 'unknown');
|
||||
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 {
|
||||
mpptReadableCount: modes.length,
|
||||
mpptAtMaxPowerCount: atMaxPower,
|
||||
mpptHoldingBackCount: modes.length - atMaxPower,
|
||||
mpptLimitedCount: limited,
|
||||
};
|
||||
})(),
|
||||
pvPowerAvg10mW: Math.max(0, num(input.pv_power_10m_avg_w, num(input.pv_power_w, 0))),
|
||||
|
||||
Reference in New Issue
Block a user