236 lines
7.7 KiB
JavaScript
236 lines
7.7 KiB
JavaScript
// =====================================================
|
|
// START BRANCH
|
|
// =====================================================
|
|
else {
|
|
const startConditionsOk =
|
|
(context.sourceMode === 'grid_hc_allowed' || context.sourceMode === 'grid_forced')
|
|
? conditions.gridStartOk
|
|
: (context.sourceMode === 'solar_only' || context.sourceMode === 'solar_potential')
|
|
? conditions.solarStartOk
|
|
: context.sourceMode === 'hybrid_probe'
|
|
? conditions.probeStartOk
|
|
: context.sourceMode === 'battery_assist_night'
|
|
? conditions.batteryAssistNightStartOk
|
|
: false;
|
|
|
|
if (!derived.canRunAtMinCurrent) {
|
|
setOff({
|
|
stateName: 'blocked_by_capacity_min_current',
|
|
decisionName: 'hold',
|
|
reasonText: 'Capacité insuffisante pour courant mini',
|
|
dynamic: false,
|
|
mustStopFlag: false,
|
|
blockReason: 'system_capacity_stop',
|
|
blockedUntilStamp: formatParisStampFromMs(nowMs + 10 * 60000),
|
|
});
|
|
}
|
|
|
|
else if (context.sourceMode === 'blocked') {
|
|
setOff({
|
|
stateName:
|
|
context.profile === 'outside_window'
|
|
? 'blocked_outside_window'
|
|
: (context.profile === 'night_hc'
|
|
? 'night_no_grid_hc_lock'
|
|
: 'idle_wait_source'),
|
|
decisionName: 'hold',
|
|
reasonText:
|
|
context.profile === 'outside_window'
|
|
? 'Hors fenêtre préférée sans source suffisante'
|
|
: context.profile === 'night_hc'
|
|
? 'Nuit sans autorisation HC réseau'
|
|
: 'Source non autorisée ou insuffisante',
|
|
dynamic: false,
|
|
mustStopFlag: false,
|
|
blockReason:
|
|
context.profile === 'outside_window'
|
|
? 'outside_window'
|
|
: context.profile === 'night_hc'
|
|
? 'grid_hc_unavailable'
|
|
: 'source_unavailable',
|
|
blockedUntilStamp:
|
|
Number.isFinite(locks.nextAllowedWindowStartMs)
|
|
? formatParisStampFromMs(locks.nextAllowedWindowStartMs)
|
|
: formatParisStampFromMs(nowMs + 15 * 60000),
|
|
});
|
|
}
|
|
|
|
else if (
|
|
(context.sourceMode === 'grid_hc_allowed' || context.sourceMode === 'grid_forced') &&
|
|
!parsed.gridAvailable
|
|
) {
|
|
setOff({
|
|
stateName:
|
|
context.profile === 'night_hc'
|
|
? 'night_wait_grid_takeover'
|
|
: 'wait_grid_source',
|
|
decisionName: 'hold',
|
|
reasonText:
|
|
context.profile === 'night_hc'
|
|
? (
|
|
nightEvcs?.batteryRecoveryUrgent
|
|
? 'Réseau demandé: urgence recharge batterie avant départ'
|
|
: 'Prise de relais réseau demandée pour session nuit EVCS'
|
|
)
|
|
: 'Source réseau demandée mais pas encore disponible',
|
|
dynamic: false,
|
|
mustStopFlag: false,
|
|
blockReason:
|
|
context.profile === 'night_hc'
|
|
? 'grid_hc_unavailable'
|
|
: 'grid_unavailable',
|
|
blockedUntilStamp: formatParisStampFromMs(nowMs + 10 * 60000),
|
|
});
|
|
}
|
|
|
|
else if (locks.startBlockedByReason) {
|
|
setOff({
|
|
stateName: 'wait_reason_lock',
|
|
decisionName: 'hold',
|
|
reasonText: `Blocage anti-cliquetis: ${history.lastBlockReason}`,
|
|
dynamic: false,
|
|
mustStopFlag: false,
|
|
blockReason: history.lastBlockReason,
|
|
blockedUntilStamp: history.blockedUntilAt || now.stamp,
|
|
});
|
|
}
|
|
|
|
else if (!startConditionsOk) {
|
|
setOff({
|
|
stateName: 'idle_wait_conditions',
|
|
decisionName: 'hold',
|
|
reasonText:
|
|
context.sourceMode === 'battery_assist_night'
|
|
? 'Conditions de démarrage nuit batterie non réunies'
|
|
: 'Conditions de démarrage non réunies',
|
|
dynamic: false,
|
|
mustStopFlag: false,
|
|
blockReason: 'none',
|
|
blockedUntilStamp: now.stamp,
|
|
});
|
|
}
|
|
|
|
else if (!lifecycle.minStopElapsed) {
|
|
setOff({
|
|
stateName: 'wait_min_stop',
|
|
decisionName: 'hold',
|
|
reasonText: 'Temps mini OFF non écoulé',
|
|
dynamic: false,
|
|
mustStopFlag: false,
|
|
blockReason: 'none',
|
|
blockedUntilStamp: now.stamp,
|
|
});
|
|
}
|
|
|
|
else {
|
|
const startCurrentA =
|
|
context.sourceMode === 'hybrid_probe'
|
|
? clamp(params.probeCurrentA, params.currentMinA, derived.physicalCapA)
|
|
: params.currentMinA;
|
|
|
|
setOn({
|
|
stateName:
|
|
context.sourceMode === 'grid_forced' ? (
|
|
nightEvcs?.batteryRecoveryUrgent
|
|
? 'night_departure_deadline_grid_forced'
|
|
: 'start_grid_forced_min_current'
|
|
) :
|
|
context.sourceMode === 'grid_hc_allowed' ? 'start_grid_hc_min_current' :
|
|
context.sourceMode === 'battery_assist_night' ? 'start_battery_assist_night_min_current' :
|
|
context.sourceMode === 'hybrid_probe' ? 'probe_start_6a' :
|
|
context.sourceMode === 'solar_potential' ? 'start_forecast_solar_potential' :
|
|
modes.batteryFullHarvestMode ? 'start_min_current_battery_full_harvest' :
|
|
modes.forecastCommitMode ? 'start_min_current_forecast_commit' :
|
|
'start_min_current',
|
|
decisionName: 'start',
|
|
currentA: startCurrentA,
|
|
reasonText:
|
|
context.sourceMode === 'grid_forced'
|
|
? (
|
|
nightEvcs?.batteryRecoveryUrgent
|
|
? 'Démarrage réseau forcé: priorité départ / recharge batterie'
|
|
: 'Démarrage en charge réseau forcée'
|
|
)
|
|
: context.sourceMode === 'grid_hc_allowed'
|
|
? 'Démarrage en fenêtre HC réseau'
|
|
: context.sourceMode === 'battery_assist_night'
|
|
? 'Démarrage nuit en assistance batterie contrôlée'
|
|
: context.sourceMode === 'hybrid_probe'
|
|
? 'Démarrage en mode sonde'
|
|
: context.sourceMode === 'solar_potential'
|
|
? 'Démarrage par potentiel solaire confirmé'
|
|
: modes.batteryFullHarvestMode
|
|
? 'Démarrage harvest solaire'
|
|
: modes.forecastCommitMode
|
|
? 'Démarrage forecast commit'
|
|
: 'Démarrage prudent à courant mini',
|
|
dynamic: true,
|
|
mustStopFlag: false,
|
|
});
|
|
|
|
nextBlockReason = 'none';
|
|
nextBlockedUntilStamp = now.stamp;
|
|
setProbeStartedAt = context.sourceMode === 'hybrid_probe';
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// CONTEXT REASONS
|
|
// =====================================================
|
|
if (nightEvcs?.nightSessionActive) {
|
|
reason.push(
|
|
`Nuit EVCS: target=${round1(nightEvcs.batteryMorningTargetPct)}% | trigger réseau=${round1(nightEvcs.gridTakeoverTriggerPct)}%`
|
|
);
|
|
|
|
if (Number.isFinite(nightEvcs.nightSessionStartSocPct)) {
|
|
reason.push(
|
|
`SOC départ session nuit=${round1(nightEvcs.nightSessionStartSocPct)}% | décharge autorisée=${round1(nightEvcs.maxBatteryDischargePoints)} pts`
|
|
);
|
|
}
|
|
|
|
if (nightEvcs.batteryRecoveryUrgent) {
|
|
reason.push("Urgence départ: il faut anticiper la reprise réseau");
|
|
}
|
|
}
|
|
|
|
reason.push(`VehicleDemandFilter delivery=${vehicleDemandFilter.deliveryRatioEma}`);
|
|
reason.push(`VehicleDemandFilter noise=${vehicleDemandFilter.deliveryNoiseEma}`);
|
|
reason.push(`VehicleDemandFilter score=${vehicleDemandFilter.noDemandScoreEma}`);
|
|
reason.push(`VehicleDemandFilter noDemand=${vehicleDemandFilter.evcsVehicleNoDemandSemantic ? 'on' : 'off'}`);
|
|
|
|
// =====================================================
|
|
// OUTPUT
|
|
// =====================================================
|
|
return [{
|
|
json: {
|
|
...prev,
|
|
vehicleDemandFilter,
|
|
decision: {
|
|
desiredCharging,
|
|
desiredPermission,
|
|
desiredLatch,
|
|
desiredCurrentA,
|
|
|
|
state,
|
|
currentDecision,
|
|
dynamicOk,
|
|
mustStop,
|
|
reason,
|
|
|
|
nextBlockReason,
|
|
nextBlockedUntilStamp,
|
|
|
|
setCloudDebtStartedAt,
|
|
setProbeStartedAt,
|
|
|
|
setNightSessionStart,
|
|
clearNightSessionStart,
|
|
|
|
notifyWanted,
|
|
notifyTitle,
|
|
notifyMessage,
|
|
}
|
|
}
|
|
}];
|
|
|