R2: git = source de vérité — src/nodes/ + build/extract intégrés au push
- src/nodes/*.js (6 nodes + template snapshot) = source de vérité unique. - n8n-push.mjs reconstruit le JSON depuis src/ avant syntaxe+golden+PUT (src gagne toujours; n8n-extract.mjs pour resynchroniser si édition UI). - n8n-build.mjs --check pour vérifier la synchro. - Copies historiques déplacées dans archive/ (mortes, dérivées de la prod). - .gitignore: backups locaux de rollback. - AGENTS.md: règle R2 pour toutes les futures sessions (dont Qwen local). - Validé: idempotence, mutation/restauration, pipeline push complet en réel.
This commit is contained in:
429
archive/decoupesurplus/V2/DECISION/decisionP3.js
Normal file
429
archive/decoupesurplus/V2/DECISION/decisionP3.js
Normal file
@@ -0,0 +1,429 @@
|
||||
else if (conditions.shouldStepDownVebusVoltage) {
|
||||
setOn({
|
||||
stateName: 'charging_step_down_dc_voltage',
|
||||
decisionName: 'step_down_fast',
|
||||
currentA: Math.max(
|
||||
params.currentMinA,
|
||||
Math.min(
|
||||
derived.currentReferenceA - Math.max(params.currentStepDownA + 1, 3),
|
||||
derived.physicalCapA
|
||||
)
|
||||
),
|
||||
reasonText: 'Baisse rapide: tension DC basse',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
|
||||
else if (
|
||||
activeSourceMode === 'battery_assist_night' &&
|
||||
conditions.batteryAssistNightShouldStepDown
|
||||
) {
|
||||
setOn({
|
||||
stateName: 'charging_step_down_battery_assist_night',
|
||||
decisionName: 'step_down',
|
||||
currentA: Math.max(
|
||||
params.currentMinA,
|
||||
Math.min(
|
||||
derived.currentReferenceA - params.currentStepDownA,
|
||||
derived.physicalCapA
|
||||
)
|
||||
),
|
||||
reasonText:
|
||||
nightEvcs?.batteryRecoveryUrgent
|
||||
? 'Réduction: approche départ, préparation takeover réseau'
|
||||
: 'Réduction: assistance batterie nuit devient trop coûteuse',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
|
||||
else if (
|
||||
(activeSourceMode === 'grid_hc_allowed' || activeSourceMode === 'grid_forced') &&
|
||||
conditions.gridShouldStepDownBattery
|
||||
) {
|
||||
setOn({
|
||||
stateName:
|
||||
activeSourceMode === 'grid_forced'
|
||||
? 'charging_step_down_grid_forced_guard'
|
||||
: 'charging_step_down_grid_guard',
|
||||
decisionName: 'step_down',
|
||||
currentA: Math.max(
|
||||
params.currentMinA,
|
||||
Math.min(
|
||||
derived.currentReferenceA - params.currentStepDownA,
|
||||
derived.physicalCapA
|
||||
)
|
||||
),
|
||||
reasonText:
|
||||
activeSourceMode === 'grid_forced'
|
||||
? 'Réduction réseau forcé: la batterie commence à participer'
|
||||
: 'Réduction réseau: la batterie commence à participer',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
|
||||
else if (
|
||||
(activeSourceMode === 'solar_only' || activeSourceMode === 'solar_potential') &&
|
||||
conditions.solarShouldStepDownCloudDebt
|
||||
) {
|
||||
setOn({
|
||||
stateName: 'charging_step_down_cloud_debt',
|
||||
decisionName: 'step_down',
|
||||
currentA: Math.max(
|
||||
params.currentMinA,
|
||||
Math.min(
|
||||
derived.currentReferenceA - Math.max(params.currentStepDownA, 2),
|
||||
derived.physicalCapA
|
||||
)
|
||||
),
|
||||
reasonText: 'Réduction: dette nuage trop élevée',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
|
||||
else if (
|
||||
(activeSourceMode === 'solar_only' || activeSourceMode === 'solar_potential') &&
|
||||
conditions.solarShouldStepDownBattery
|
||||
) {
|
||||
setOn({
|
||||
stateName: 'charging_step_down_battery',
|
||||
decisionName: 'step_down',
|
||||
currentA: Math.max(
|
||||
params.currentMinA,
|
||||
Math.min(
|
||||
derived.currentReferenceA - params.currentStepDownA,
|
||||
derived.physicalCapA
|
||||
)
|
||||
),
|
||||
reasonText: 'Réduction: batterie trop sollicitée',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
|
||||
else if (
|
||||
(activeSourceMode === 'grid_hc_allowed' || activeSourceMode === 'grid_forced') &&
|
||||
conditions.gridShouldStepUp
|
||||
) {
|
||||
setOn({
|
||||
stateName:
|
||||
activeSourceMode === 'grid_forced'
|
||||
? (
|
||||
nightEvcs?.batteryRecoveryUrgent
|
||||
? 'night_departure_deadline_grid_forced'
|
||||
: 'charging_step_up_grid_forced'
|
||||
)
|
||||
: 'charging_step_up_grid_hc',
|
||||
decisionName: 'step_up',
|
||||
currentA: clamp(
|
||||
derived.currentReferenceA + params.currentStepUpA,
|
||||
params.currentMinA,
|
||||
derived.physicalCapA
|
||||
),
|
||||
reasonText:
|
||||
activeSourceMode === 'grid_forced'
|
||||
? (
|
||||
nightEvcs?.batteryRecoveryUrgent
|
||||
? 'Hausse prudente: priorité départ, réseau forcé'
|
||||
: 'Hausse prudente du courant en charge réseau forcée'
|
||||
)
|
||||
: 'Hausse prudente du courant en HC réseau',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
|
||||
else if (
|
||||
activeSourceMode === 'battery_assist_night' &&
|
||||
conditions.batteryAssistNightShouldStepUp
|
||||
) {
|
||||
setOn({
|
||||
stateName: 'charging_step_up_battery_assist_night',
|
||||
decisionName: 'step_up',
|
||||
currentA: clamp(
|
||||
derived.currentReferenceA + params.currentStepUpA,
|
||||
params.currentMinA,
|
||||
derived.physicalCapA
|
||||
),
|
||||
reasonText: 'Hausse prudente du courant en assistance batterie nuit',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
|
||||
else if (
|
||||
(activeSourceMode === 'solar_only' || activeSourceMode === 'solar_potential') &&
|
||||
conditions.solarShouldStepUp
|
||||
) {
|
||||
setOn({
|
||||
stateName:
|
||||
conditions.probeSuccessNow
|
||||
? 'probe_success_step_up'
|
||||
: (modes.batteryPriorityMode
|
||||
? 'charging_step_up_battery'
|
||||
: 'charging_step_up_forecast'),
|
||||
decisionName: 'step_up',
|
||||
currentA: clamp(
|
||||
derived.currentReferenceA + params.currentStepUpA,
|
||||
params.currentMinA,
|
||||
derived.physicalCapA
|
||||
),
|
||||
reasonText: 'Hausse prudente du courant',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
|
||||
else {
|
||||
setOn({
|
||||
stateName:
|
||||
conditions.probeSuccessNow ? 'probe_success_hold' :
|
||||
activeSourceMode === 'battery_assist_night' ? 'charging_hold_battery_assist_night' :
|
||||
(activeSourceMode === 'grid_hc_allowed' || activeSourceMode === 'grid_forced') ? 'charging_hold_grid' :
|
||||
cloud.cloudDebtActive ? 'charging_hold_cloud_tolerance' :
|
||||
'charging_hold',
|
||||
decisionName: 'hold',
|
||||
currentA: Math.min(derived.currentReferenceA, derived.physicalCapA),
|
||||
reasonText:
|
||||
activeSourceMode === 'battery_assist_night'
|
||||
? 'Maintien du courant en assistance batterie nuit'
|
||||
: 'Maintien du courant',
|
||||
dynamic: true,
|
||||
mustStopFlag: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================
|
||||
// OUTPUT
|
||||
// =====================================================
|
||||
return [{
|
||||
json: {
|
||||
...prev,
|
||||
decision: {
|
||||
desiredCharging,
|
||||
desiredPermission,
|
||||
desiredLatch,
|
||||
desiredCurrentA,
|
||||
|
||||
state,
|
||||
currentDecision,
|
||||
dynamicOk,
|
||||
mustStop,
|
||||
reason,
|
||||
|
||||
nextBlockReason,
|
||||
nextBlockedUntilStamp,
|
||||
|
||||
setCloudDebtStartedAt,
|
||||
setProbeStartedAt,
|
||||
|
||||
setNightSessionStart,
|
||||
clearNightSessionStart,
|
||||
|
||||
notifyWanted,
|
||||
notifyTitle,
|
||||
notifyMessage,
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
Reference in New Issue
Block a user