logique de traitement erron

This commit is contained in:
2026-05-01 17:38:40 +02:00
parent 874aca1afa
commit 5e6798b702
29 changed files with 9184 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
// =====================================================
// LEGACY / FORECAST MODES
// =====================================================
const batteryFullHarvestMode =
parsed.forecastModeEnabled &&
context.profile !== 'night_hc' &&
context.profile !== 'outside_window' &&
parsed.soc >= params.batteryFullSoc &&
parsed.todayRemainingKwh >= params.batteryFullForecastMinKwh &&
derived.projectedEndSocAfterCharge >= (derived.endDayGuardSoc - 2);
const forecastCommitMode =
parsed.forecastModeEnabled &&
context.profile !== 'night_hc' &&
context.profile !== 'outside_window' &&
parsed.soc >= params.forecastCommitSocFloor &&
parsed.todayRemainingKwh >= params.forecastCommitMinKwh &&
derived.projectedEndSocAfterCharge >= derived.endDayGuardSoc;
const batteryPriorityMode =
!batteryFullHarvestMode && !forecastCommitMode;
// =====================================================
// PROFILE-BASED THRESHOLDS
// =====================================================
const profileSocStartFloor =
context.profile === 'morning_solar' ? params.morningSocMin :
context.profile === 'midday_hc_or_solar' ? params.middaySocMin :
context.profile === 'evening_high_soc' ? params.eveningSocStartMin :
params.socStartMin;
const profileSocHoldFloor =
context.profile === 'morning_solar' ? Math.max(params.socStopMin, params.morningSocMin - 10) :
context.profile === 'midday_hc_or_solar' ? Math.max(params.socStopMin, params.middaySocMin - 15) :
context.profile === 'evening_high_soc' ? params.eveningSocStopMin :
params.socStopMin;
const profileSpecificDischargeFloorA =
context.profile === 'morning_solar' ? params.morningBatteryMaxDischargeA :
context.profile === 'midday_hc_or_solar' ? params.middayBatteryMaxDischargeA :
context.profile === 'evening_high_soc' ? params.eveningBatteryMaxDischargeA :
params.batteryDischargeSoftA;
const profileBatteryDischargeFloorA =
Math.max(profileSpecificDischargeFloorA, batteryDischargeSoftDynamicA);
// =====================================================
// GRID RELAX IN force_charge_now
// =====================================================
// Assouplissement uniquement pour la garde réseau,
// sans toucher aux sécurités dures globales.
const gridForceChargeRelaxSoftA =
strategy.forceChargeRequested && isGridSource
? (
parsed.soc >= 90 ? 28 :
parsed.soc >= 80 ? 16 :
parsed.soc >= 60 ? 8 :
parsed.soc >= 40 ? 4 :
0
)
: 0;
const gridForceChargeRelaxHardA =
strategy.forceChargeRequested && isGridSource
? (
parsed.soc >= 90 ? 39 :
parsed.soc >= 80 ? 29 :
parsed.soc >= 60 ? 18 :
parsed.soc >= 40 ? 8 :
0
)
: 0;
const gridBatterySoftDynamicABase =
Math.max(params.gridBatterySoftA, batteryDischargeSoftDynamicA);
const gridBatteryHardDynamicABase =
Math.max(params.gridBatteryHardA, batteryDischargeHardDynamicA);
let gridBatterySoftDynamicA =
gridBatterySoftDynamicABase - gridForceChargeRelaxSoftA;
let gridBatteryHardDynamicA =
gridBatteryHardDynamicABase - gridForceChargeRelaxHardA;
// Garantit que le hard reste plus permissif que le soft d'au moins 3 A
if (gridBatteryHardDynamicA > (gridBatterySoftDynamicA - 3)) {
gridBatteryHardDynamicA = gridBatterySoftDynamicA - 3;
}
// =====================================================
// BASE SAFETY
// =====================================================
const commonSafetyStartOk =
derived.canRunAtMinCurrent &&
!derived.anyVebusOverload &&
!derived.anyVebusLowBattery &&
!derived.vebusDcVoltageSoftLow &&
!derived.vebusAcOutSoftReached &&
parsed.evcsDeviceConnected &&
parsed.evcsVehicleConnected &&
!parsed.evcsModeIsAuto;
const commonSafetyHoldOk =
derived.canRunAtMinCurrent &&
!derived.anyVebusLowBattery &&
!derived.vebusDcVoltageHardLow &&
parsed.evcsDeviceConnected &&
parsed.evcsVehicleConnected &&
!parsed.evcsModeIsAuto;
// =====================================================
// START / HOLD CONDITIONS
// =====================================================
const solarStartOk =
(context.sourceMode === 'solar_only' || context.sourceMode === 'solar_potential') &&
commonSafetyStartOk &&
parsed.soc >= profileSocStartFloor &&
parsed.batteryCurrentA >= profileBatteryDischargeFloorA &&
(
context.sourceMode === 'solar_potential' ||
parsed.pvPowerW >= context.effectivePvStartMinW
);
const solarHoldOk =
(context.sourceMode === 'solar_only' || context.sourceMode === 'solar_potential') &&
commonSafetyHoldOk &&
parsed.soc >= profileSocHoldFloor &&
parsed.batteryCurrentA >= profileBatteryDischargeFloorA &&
(
parsed.pvPowerW >= params.pvHoldMinW ||
cloudToleranceOk
);
const gridStartOk =
isGridSource &&
commonSafetyStartOk &&
parsed.gridAvailable &&
parsed.batteryCurrentA >= gridBatterySoftDynamicA;
const gridHoldOk =
isGridSource &&
commonSafetyHoldOk &&
parsed.gridAvailable &&
parsed.batteryCurrentA >= gridBatteryHardDynamicA;
// =====================================================
// PROBE LOGIC — STRICTEMENT LIMITÉE AU MODE PROBE
// =====================================================
const probeModeActive = context.sourceMode === 'hybrid_probe';
const probeStartOk =
probeModeActive &&
commonSafetyStartOk &&
(context.morningProbeEligible || context.middayProbeEligible);
const probeHoldGuardOk =
probeModeActive &&
commonSafetyHoldOk &&
parsed.batteryCurrentA >= profileBatteryDischargeFloorA;
const probeWindowActive =
probeModeActive &&
sessionObservedActive &&
history.probeStartedMs !== null &&
lifecycle.minutesSinceProbeStart !== null &&
lifecycle.minutesSinceProbeStart < params.probeMinutes;
const probeElapsedReached =
probeModeActive &&
sessionObservedActive &&
history.probeStartedMs !== null &&
lifecycle.minutesSinceProbeStart !== null &&
lifecycle.minutesSinceProbeStart >= params.probeMinutes;
const probeSuccessNow =
probeModeActive &&
sessionObservedActive &&
history.probeStartedMs !== null &&
(
parsed.pvPowerW >= params.pvHoldMinW &&
parsed.batteryCurrentA >= Math.min(0, batteryDischargeSoftDynamicA)
);
const probeFailedNow =
probeModeActive &&
probeElapsedReached &&
!probeSuccessNow;