189 lines
6.1 KiB
JavaScript
189 lines
6.1 KiB
JavaScript
// =====================================================
|
|
// 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;
|