@@ -12,6 +12,7 @@ enum class PumpTarget {
1212};
1313enum class PhaseType { PHASE_TYPE_PREINFUSION , PHASE_TYPE_BREW };
1414enum class TransitionType { INSTANT , LINEAR , EASE_IN , EASE_OUT , EASE_IN_OUT };
15+ enum class TransitionTarget { TIME , VOLUMETRIC , PUMPED };
1516
1617// Why a phase ended; persisted as uint8_t in the .slog phase transitions, so values must stay stable.
1718// NONE (0) doubles as "still running" and as the legacy/unknown value in old shot files.
@@ -47,6 +48,7 @@ struct PumpAdvanced {
4748
4849struct Transition {
4950 TransitionType type;
51+ TransitionTarget target;
5052 float duration;
5153 bool adaptive;
5254};
@@ -81,6 +83,24 @@ struct Phase {
8183 return Target{};
8284 }
8385
86+ bool hasPumpedTarget () const {
87+ for (const auto &target : targets) {
88+ if (target.type == TargetType::TARGET_TYPE_PUMPED && target.value > 0 .0f ) {
89+ return true ;
90+ }
91+ }
92+ return false ;
93+ }
94+
95+ Target getPumpedTarget () const {
96+ for (auto &target : targets) {
97+ if (target.type == TargetType::TARGET_TYPE_PUMPED ) {
98+ return target;
99+ }
100+ }
101+ return Target{};
102+ }
103+
84104 void adjustDuration (float amount) { duration = std::max (0 .5f , duration + amount); }
85105
86106 void adjustVolumetricTarget (float factor) {
@@ -98,6 +118,9 @@ struct Phase {
98118 for (const auto &target : targets) {
99119 switch (target.type ) {
100120 case TargetType::TARGET_TYPE_VOLUMETRIC :
121+ if (target.value <= 0 .0f ) {
122+ break ;
123+ }
101124 volumetricTested = enableVolumetric;
102125 if (enableVolumetric && target.isReached (volume)) {
103126 return PhaseExitReason::TARGET_VOLUMETRIC ;
@@ -296,11 +319,20 @@ inline bool parseProfile(const JsonObject &obj, Profile &profile) {
296319 } else {
297320 phase.transition .type = TransitionType::INSTANT ;
298321 }
322+ String target = transition[" target" ].as <String>();
323+ if (target == " volumetric" ) {
324+ phase.transition .target = TransitionTarget::VOLUMETRIC ;
325+ } else if (target == " pumped" ) {
326+ phase.transition .target = TransitionTarget::PUMPED ;
327+ } else {
328+ phase.transition .target = TransitionTarget::TIME ;
329+ }
299330 phase.transition .duration = transition[" duration" ].as <float >();
300331 phase.transition .adaptive = transition[" adaptive" ].as <bool >();
301332 } else {
302333 phase.transition = Transition{
303334 .type = TransitionType::INSTANT ,
335+ .target = TransitionTarget::TIME ,
304336 .duration = 0 ,
305337 .adaptive = false ,
306338 };
@@ -381,6 +413,13 @@ inline void writeProfile(JsonObject &obj, const Profile &profile) {
381413 transition[" type" ] = " instant" ;
382414 break ;
383415 }
416+ if (phase.transition .target == TransitionTarget::VOLUMETRIC ) {
417+ transition[" target" ] = " volumetric" ;
418+ } else if (phase.transition .target == TransitionTarget::PUMPED ) {
419+ transition[" target" ] = " pumped" ;
420+ } else {
421+ transition[" target" ] = " time" ;
422+ }
384423 transition[" duration" ] = phase.transition .duration ;
385424 transition[" adaptive" ] = phase.transition .adaptive ;
386425
0 commit comments