760 lines
29 KiB
C++
760 lines
29 KiB
C++
#include "Plunger.h"
|
|
#include <Arduino.h>
|
|
#include "PlungerSettings.h"
|
|
|
|
const bool debug_jam = true;
|
|
const bool debug_states = true;
|
|
|
|
const char *_plungerStateToString(PlungerState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case PlungerState::IDLE:
|
|
return "IDLE";
|
|
case PlungerState::HOMING_MANUAL:
|
|
return "HOMING_MANUAL";
|
|
case PlungerState::HOMING_AUTO:
|
|
return "HOMING_AUTO";
|
|
case PlungerState::PLUNGING_MANUAL:
|
|
return "PLUNGING_MANUAL";
|
|
case PlungerState::PLUNGING_AUTO:
|
|
return "PLUNGING_AUTO";
|
|
case PlungerState::STOPPING:
|
|
return "STOPPING";
|
|
case PlungerState::JAMMED:
|
|
return "JAMMED";
|
|
case PlungerState::RESETTING_JAM:
|
|
return "RESETTING_JAM";
|
|
case PlungerState::RECORD:
|
|
return "RECORD";
|
|
case PlungerState::REPLAY:
|
|
return "REPLAY";
|
|
case PlungerState::FILLING:
|
|
return "FILLING";
|
|
case PlungerState::POST_FLOW:
|
|
return "POST_FLOW";
|
|
default:
|
|
return "UNKNOWN_STATE";
|
|
}
|
|
}
|
|
|
|
// Re-add _fillStateToString
|
|
const char *_fillStateToString(FillState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case FillState::NONE:
|
|
return "NONE";
|
|
case FillState::PLUNGING:
|
|
return "PLUNGING";
|
|
case FillState::PLUNGED:
|
|
return "PLUNGED";
|
|
case FillState::HOMING:
|
|
return "HOMING";
|
|
case FillState::HOMED:
|
|
return "HOMED";
|
|
default:
|
|
return "UNKNOWN_FILL_STATE";
|
|
}
|
|
}
|
|
|
|
// Add _postFlowStateToString
|
|
const char *_postFlowStateToString(PostFlowState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case PostFlowState::NONE:
|
|
return "NONE";
|
|
case PostFlowState::POST_FLOW_STOPPING:
|
|
return "STOPPING";
|
|
case PostFlowState::POST_FLOW_STARTING:
|
|
return "STARTING";
|
|
case PostFlowState::POST_FLOW_COMPLETE:
|
|
return "COMPLETE";
|
|
default:
|
|
return "UNKNOWN_POST_FLOW_STATE";
|
|
}
|
|
}
|
|
|
|
Plunger::Plunger(Component *owner, SAKO_VFD *vfd, Joystick *joystick, POT *speedPot, POT *torquePot)
|
|
: Component(PLUNGER_COMPONENT_NAME, COMPONENT_KEY_PLUNGER, Component::COMPONENT_DEFAULT, owner),
|
|
_vfd(vfd),
|
|
_joystick(joystick),
|
|
_speedPot(speedPot),
|
|
_torquePot(torquePot),
|
|
_currentState(PlungerState::IDLE),
|
|
_currentFillState(FillState::NONE),
|
|
_lastJoystickDirection(Joystick::E_POSITION::CENTER),
|
|
_currentSpeedPotValue(0),
|
|
_currentTorquePotValue(0),
|
|
_calculatedPlungingSpeedHz(0),
|
|
_lastStateChangeTimeMs(0),
|
|
_jammedStartTimeMs(0),
|
|
_lastVfdReadTimeMs(0),
|
|
_joystickHoldStartTimeMs(0),
|
|
_modbusCommandRegisterValue(static_cast<short>(E_PlungerCommand::NO_COMMAND)),
|
|
_operationStartTimeMs(0),
|
|
_currentMaxOperationTimeMs(0),
|
|
_joystickReleasedSinceAutoStart(false),
|
|
_autoModeEnabled(true),
|
|
_lastDiagnosticLogTimeMs(0),
|
|
_lastImmediateStopCheckTimeMs(0),
|
|
_lastStateLogTimeMs(0),
|
|
_recordedPlungeDurationMs(0),
|
|
_recordModeStartTimeMs(0),
|
|
_fillOperationStartTimeMs(0),
|
|
_postFlowStartTimeMs(0),
|
|
_currentPostFlowState(PostFlowState::NONE)
|
|
{
|
|
setNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS);
|
|
}
|
|
|
|
short Plunger::init()
|
|
{
|
|
_vfdResetJam();
|
|
_vfdStop();
|
|
_transitionToState(PlungerState::IDLE);
|
|
_lastJoystickDirection = Joystick::E_POSITION::CENTER;
|
|
_lastStateChangeTimeMs = millis();
|
|
_jammedStartTimeMs = 0;
|
|
_lastVfdReadTimeMs = 0;
|
|
_joystickHoldStartTimeMs = 0;
|
|
_operationStartTimeMs = 0;
|
|
_currentMaxOperationTimeMs = 0;
|
|
_lastDiagnosticLogTimeMs = 0;
|
|
_lastImmediateStopCheckTimeMs = 0;
|
|
_lastStateLogTimeMs = 0;
|
|
_modbusCommandRegisterValue = static_cast<short>(E_PlungerCommand::NO_COMMAND);
|
|
_joystickReleasedSinceAutoStart = false;
|
|
_autoModeEnabled = true;
|
|
|
|
bool loadSettings = true;
|
|
|
|
if (loadSettings)
|
|
{
|
|
// _settings is already initialized with compile-time defaults by its constructor.
|
|
// Now, attempt to load from file, overriding defaults if successful.
|
|
Log.infoln("[%s] init() called. Attempting to load settings...", name.c_str());
|
|
if (_settings.load())
|
|
{ // Uses default path "/plunger.json"
|
|
Log.infoln("[%s] Settings loaded successfully from file during init.", name.c_str());
|
|
}
|
|
else
|
|
{
|
|
Log.warningln("[%s] Could not load settings from file during init, using compile-time defaults. Attempting to save defaults to create file.", name.c_str());
|
|
if (_settings.save())
|
|
{ // Attempt to save the current (compile-time default) settings
|
|
Log.infoln("[%s] Default settings saved to file during init.", name.c_str());
|
|
}
|
|
else
|
|
{
|
|
Log.errorln("[%s] Failed to save default settings to file during init.", name.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now that settings are finalized (loaded or compile-time defaults), proceed with dependent initializations.
|
|
_updatePotValues(); // Recalculates _calculatedPlungingSpeedHz based on potentially loaded _settings.speedFastHz
|
|
_recordedPlungeDurationMs = _settings.replayDurationMs;
|
|
|
|
_recordModeStartTimeMs = 0;
|
|
_joystickRecordHoldTimer.detach();
|
|
_replayPlungeTimer.detach();
|
|
|
|
_currentFillState = FillState::NONE;
|
|
_fillOperationStartTimeMs = 0;
|
|
_fillSubStateTimer.detach();
|
|
_joystickFillHoldTimer.detach();
|
|
|
|
_postFlowStartTimeMs = 0;
|
|
_currentPostFlowState = PostFlowState::NONE;
|
|
_postFlowSubStateTimer.detach();
|
|
|
|
Log.infoln("[%s] Final Plunger settings after init process:", name.c_str());
|
|
_settings.print(); // Log the finalized settings
|
|
|
|
return E_OK;
|
|
}
|
|
|
|
short Plunger::setup()
|
|
{
|
|
Component::setup();
|
|
return this->init();
|
|
}
|
|
|
|
void Plunger::_updatePotValues()
|
|
{
|
|
_currentSpeedPotValue = _speedPot->getValue();
|
|
_currentTorquePotValue = _torquePot->getValue();
|
|
_calculatedPlungingSpeedHz = (_currentSpeedPotValue / 100.0f) * (_settings.speedFastHz * 100.0f);
|
|
}
|
|
|
|
void Plunger::_vfdStartForward(uint16_t frequencyCentiHz)
|
|
{
|
|
_vfd->setFrequency(frequencyCentiHz / 100); // SAKO_VFD::setFrequency expects Hz
|
|
_vfd->run();
|
|
}
|
|
|
|
void Plunger::_vfdStartReverse(uint16_t frequencyCentiHz)
|
|
{
|
|
_vfd->setFrequency(frequencyCentiHz / 100); // SAKO_VFD::setFrequency expects Hz
|
|
_vfd->reverse();
|
|
}
|
|
|
|
void Plunger::_vfdStop()
|
|
{
|
|
_vfd->stop();
|
|
}
|
|
|
|
void Plunger::_vfdResetJam()
|
|
{
|
|
Log.verboseln("[%s] VFD Resetting Fault/Jam", name.c_str());
|
|
_vfd->resetFault();
|
|
}
|
|
|
|
void Plunger::_checkVfdForJam()
|
|
{
|
|
unsigned long currentTimeMs = millis();
|
|
if (debug_jam && currentTimeMs - _lastDiagnosticLogTimeMs > 5000)
|
|
{
|
|
uint16_t diagCurrentMa = 0;
|
|
bool diagReadSuccess = _vfd->getOutputCurrent(diagCurrentMa);
|
|
Log.infoln("[%s] --- DIAGNOSTIC LOG (debug_jam active) ---", name.c_str());
|
|
Log.infoln("State: %s, FillState: %s, PostFlowState: %s",
|
|
_plungerStateToString(_currentState),
|
|
(_currentState == PlungerState::FILLING ? _fillStateToString(_currentFillState) : "N/A"),
|
|
(_currentState == PlungerState::POST_FLOW ? _postFlowStateToString(_currentPostFlowState) : "N/A"));
|
|
Log.infoln("VFD Running (reported): %d, VFD Fault (reported): %d", _vfd->isRunning(), _vfd->hasFault());
|
|
Log.infoln("VFD Current Read Success: %d, Current: %u mA", diagReadSuccess, diagCurrentMa);
|
|
Log.infoln("JammedStartTime: %lu ms (ago: %lu ms if active)", _jammedStartTimeMs, (_jammedStartTimeMs > 0 ? currentTimeMs - _jammedStartTimeMs : 0));
|
|
Log.infoln("JoystickHoldStartTime: %lu ms", _joystickHoldStartTimeMs);
|
|
Log.infoln("OperationStartTime: %lu ms, CurrentMaxOpTime: %lu ms", _operationStartTimeMs, _currentMaxOperationTimeMs);
|
|
Log.infoln("FillOperationStartTime: %lu ms", _fillOperationStartTimeMs);
|
|
_lastDiagnosticLogTimeMs = currentTimeMs;
|
|
}
|
|
|
|
uint16_t vfdOutputCurrentMa = 0;
|
|
bool readSuccess = _vfd->getOutputCurrent(vfdOutputCurrentMa);
|
|
if (!readSuccess)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool motorExpectedActive = false;
|
|
if (_currentState == PlungerState::HOMING_MANUAL || _currentState == PlungerState::HOMING_AUTO ||
|
|
_currentState == PlungerState::PLUNGING_MANUAL || _currentState == PlungerState::PLUNGING_AUTO ||
|
|
_currentState == PlungerState::RECORD ||
|
|
(_currentState == PlungerState::POST_FLOW && _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) ||
|
|
(_currentState == PlungerState::FILLING &&
|
|
(_currentFillState == FillState::PLUNGING || _currentFillState == FillState::HOMING)))
|
|
{
|
|
motorExpectedActive = true;
|
|
}
|
|
|
|
if (_vfd->hasFault())
|
|
{
|
|
Log.errorln("[%s] JAMMED (VFD FAULT)! VFD reports fault code %d. State: %s, FillState: %s",
|
|
name.c_str(), _vfd->getFaultCode(),
|
|
_plungerStateToString(_currentState),
|
|
_currentState == PlungerState::FILLING ? _fillStateToString(_currentFillState) : "N/A");
|
|
_transitionToState(PlungerState::JAMMED);
|
|
return;
|
|
}
|
|
|
|
if (!motorExpectedActive)
|
|
{
|
|
if (_jammedStartTimeMs != 0)
|
|
{
|
|
Log.verboseln("[%s] JAM CHECK: Motor not expected active. Jam timer RESET. State: %s, FillState: %s",
|
|
name.c_str(), _plungerStateToString(_currentState),
|
|
_currentState == PlungerState::FILLING ? _fillStateToString(_currentFillState) : "N/A");
|
|
_jammedStartTimeMs = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
float torqueMultiplier = 1.0f;
|
|
uint16_t adjustedJamThresholdMa = _settings.currentJamThresholdMa;
|
|
|
|
bool isPlungingState = (_currentState == PlungerState::PLUNGING_MANUAL ||
|
|
_currentState == PlungerState::PLUNGING_AUTO ||
|
|
_currentState == PlungerState::RECORD ||
|
|
(_currentState == PlungerState::FILLING && _currentFillState == FillState::PLUNGING));
|
|
|
|
if (_currentState == PlungerState::POST_FLOW && _currentPostFlowState == PostFlowState::POST_FLOW_STARTING)
|
|
{
|
|
adjustedJamThresholdMa = _settings.currentPostFlowMa;
|
|
}
|
|
else if (isPlungingState)
|
|
{
|
|
torqueMultiplier = (100.0f - _currentTorquePotValue) / 100.0f;
|
|
adjustedJamThresholdMa = static_cast<uint16_t>(_settings.currentJamThresholdMa * torqueMultiplier);
|
|
}
|
|
|
|
if (vfdOutputCurrentMa >= adjustedJamThresholdMa)
|
|
{
|
|
if (_jammedStartTimeMs == 0)
|
|
{
|
|
_jammedStartTimeMs = millis();
|
|
}
|
|
|
|
unsigned long jamDurationTargetMs = 0;
|
|
if (_currentState == PlungerState::FILLING)
|
|
{
|
|
if (_currentFillState == FillState::PLUNGING)
|
|
jamDurationTargetMs = _settings.jammedDurationMs;
|
|
else if (_currentFillState == FillState::HOMING)
|
|
jamDurationTargetMs = _settings.jammedDurationHomingMs;
|
|
}
|
|
else if (_currentState == PlungerState::POST_FLOW && _currentPostFlowState == PostFlowState::POST_FLOW_STARTING)
|
|
{
|
|
jamDurationTargetMs = _settings.jammedDurationMs;
|
|
}
|
|
else if (_currentState == PlungerState::HOMING_MANUAL || _currentState == PlungerState::HOMING_AUTO)
|
|
{
|
|
jamDurationTargetMs = _settings.jammedDurationHomingMs;
|
|
}
|
|
else if (_currentState == PlungerState::PLUNGING_MANUAL || _currentState == PlungerState::PLUNGING_AUTO || _currentState == PlungerState::RECORD)
|
|
{
|
|
jamDurationTargetMs = _settings.jammedDurationMs;
|
|
}
|
|
|
|
if (_jammedStartTimeMs > 0 && (millis() - _jammedStartTimeMs > _settings.maxUniversalJamTimeMs))
|
|
{
|
|
Log.errorln("[%s] UNIVERSAL JAM TIMEOUT! Current %u mA for >%lums. State: %s, FillState: %s. JAMMED.",
|
|
name.c_str(), vfdOutputCurrentMa, millis() - _jammedStartTimeMs,
|
|
_plungerStateToString(_currentState),
|
|
_currentState == PlungerState::FILLING ? _fillStateToString(_currentFillState) : "N/A");
|
|
_transitionToState(PlungerState::JAMMED);
|
|
return;
|
|
}
|
|
|
|
if (jamDurationTargetMs > 0 && _jammedStartTimeMs > 0 && (millis() - _jammedStartTimeMs > jamDurationTargetMs))
|
|
{
|
|
if (_currentState == PlungerState::PLUNGING_AUTO && _settings.enablePostFlow)
|
|
{
|
|
Log.infoln("[%s] Jam in PLUNGING_AUTO & postFlow enabled. -> POST_FLOW", name.c_str());
|
|
_transitionToState(PlungerState::POST_FLOW);
|
|
}
|
|
else if (_currentState == PlungerState::FILLING)
|
|
{
|
|
_vfdStop();
|
|
if (_currentFillState == FillState::PLUNGING)
|
|
{
|
|
Log.infoln("[%s] Fill: Jam during PLUNGING. -> PLUNGED. Wait %lu ms.", name.c_str(), _settings.fillPlungedWaitDurationMs);
|
|
_currentFillState = FillState::PLUNGED;
|
|
_fillSubStateTimer.once_ms(_settings.fillPlungedWaitDurationMs, &Plunger::_fillSubStateTimerRelay, this);
|
|
_jammedStartTimeMs = 0;
|
|
}
|
|
else if (_currentFillState == FillState::HOMING)
|
|
{
|
|
Log.infoln("[%s] Fill: Jam during HOMING. -> HOMED. Wait %lu ms.", name.c_str(), _settings.fillHomedWaitDurationMs);
|
|
_currentFillState = FillState::HOMED;
|
|
_fillSubStateTimer.once_ms(_settings.fillHomedWaitDurationMs, &Plunger::_fillSubStateTimerRelay, this);
|
|
_jammedStartTimeMs = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_transitionToState(PlungerState::JAMMED);
|
|
}
|
|
}
|
|
else if (_jammedStartTimeMs > 0)
|
|
{
|
|
}
|
|
}
|
|
else // Current is NOT above threshold
|
|
{
|
|
if (_jammedStartTimeMs != 0) // If it *was* timing a jam
|
|
{
|
|
_jammedStartTimeMs = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
short Plunger::loop()
|
|
{
|
|
Component::loop();
|
|
_updatePotValues();
|
|
_checkVfdForJam();
|
|
|
|
if (debug_states)
|
|
{
|
|
unsigned long currentTimeMs = millis();
|
|
if (currentTimeMs - _lastStateLogTimeMs >= 10000)
|
|
{
|
|
Log.infoln("[%s] --- STATE LOG DUMP (debug_states active) ---", name.c_str());
|
|
Log.infoln(" CurrentTime: %lu ms", currentTimeMs);
|
|
Log.infoln(" State: %s (%d)", _plungerStateToString(_currentState), static_cast<int>(_currentState));
|
|
if (_currentState == PlungerState::FILLING)
|
|
{
|
|
Log.infoln(" FillState: %s (%d)", _fillStateToString(_currentFillState), static_cast<int>(_currentFillState));
|
|
}
|
|
if (_currentState == PlungerState::POST_FLOW)
|
|
{
|
|
Log.infoln(" PostFlowState: %s (%d)", _postFlowStateToString(_currentPostFlowState), static_cast<int>(_currentPostFlowState));
|
|
}
|
|
Log.infoln(" Timers (ms):");
|
|
Log.infoln(" OperationStart: %d (Max: %d)", _operationStartTimeMs, _currentMaxOperationTimeMs);
|
|
Log.infoln(" JammedStart: %lu", _jammedStartTimeMs);
|
|
Log.infoln(" JoystickHoldStart: %lu", _joystickHoldStartTimeMs);
|
|
Log.infoln(" FillOperationStart: %lu", _fillOperationStartTimeMs);
|
|
Log.infoln(" PostFlowStart: %lu", _postFlowStartTimeMs);
|
|
Log.infoln(" RecordModeStart: %lu", _recordModeStartTimeMs);
|
|
Log.infoln(" LastStateChange: %lu", _lastStateChangeTimeMs);
|
|
_lastStateLogTimeMs = currentTimeMs;
|
|
Log.infoln("[%s] --- END STATE LOG DUMP ---", name.c_str());
|
|
}
|
|
}
|
|
|
|
if (_currentState == PlungerState::PLUNGING_MANUAL || _currentState == PlungerState::PLUNGING_AUTO)
|
|
{
|
|
// _calculatedPlungingSpeedHz is in 0.01Hz units, SAKO_VFD::setFrequency expects Hz
|
|
// _vfd->setFrequency(static_cast<uint16_t>(_calculatedPlungingSpeedHz / 100.0f));
|
|
}
|
|
// _vfd->setFrequency(static_cast<uint16_t>(_currentSpeedPotValue / 100.0f));
|
|
Joystick::E_POSITION currentJoystickDir = static_cast<Joystick::E_POSITION>(_joystick->getValue());
|
|
// Generic Max Operation Time Check (Safety Net)
|
|
if (_operationStartTimeMs > 0 && _currentMaxOperationTimeMs > 0)
|
|
{
|
|
bool isMonitoredState = false;
|
|
if (_currentState == PlungerState::HOMING_MANUAL || _currentState == PlungerState::HOMING_AUTO ||
|
|
_currentState == PlungerState::PLUNGING_MANUAL || _currentState == PlungerState::PLUNGING_AUTO ||
|
|
_currentState == PlungerState::RECORD || _currentState == PlungerState::REPLAY)
|
|
{
|
|
isMonitoredState = true;
|
|
}
|
|
else if (_currentState == PlungerState::FILLING &&
|
|
(_currentFillState == FillState::PLUNGING || _currentFillState == FillState::HOMING))
|
|
{
|
|
isMonitoredState = true;
|
|
}
|
|
else if (_currentState == PlungerState::POST_FLOW && _currentPostFlowState == PostFlowState::POST_FLOW_STARTING)
|
|
{
|
|
isMonitoredState = true;
|
|
}
|
|
|
|
if (isMonitoredState && (millis() - _operationStartTimeMs > _currentMaxOperationTimeMs))
|
|
{
|
|
Log.warningln("[%s] GENERIC MAX OPERATION TIME (%lu ms) EXCEEDED! State: %s, FillState: %s, PostFlowState: %s. Transitioning to JAMMED.",
|
|
name.c_str(), _currentMaxOperationTimeMs,
|
|
_plungerStateToString(_currentState),
|
|
_currentState == PlungerState::FILLING ? _fillStateToString(_currentFillState) : "N/A",
|
|
_currentState == PlungerState::POST_FLOW ? _postFlowStateToString(_currentPostFlowState) : "N/A");
|
|
_transitionToState(PlungerState::JAMMED);
|
|
}
|
|
}
|
|
|
|
switch (_currentState)
|
|
{
|
|
case PlungerState::IDLE:
|
|
_handleIdleState();
|
|
break;
|
|
case PlungerState::HOMING_MANUAL:
|
|
_handleHomingManualState();
|
|
break;
|
|
case PlungerState::HOMING_AUTO:
|
|
_handleHomingAutoState();
|
|
break;
|
|
case PlungerState::PLUNGING_MANUAL:
|
|
_handlePlungingManualState();
|
|
break;
|
|
case PlungerState::PLUNGING_AUTO:
|
|
_handlePlungingAutoState();
|
|
break;
|
|
case PlungerState::STOPPING:
|
|
_handleStoppingState();
|
|
break;
|
|
case PlungerState::JAMMED:
|
|
_handleJammedState();
|
|
break;
|
|
case PlungerState::RESETTING_JAM:
|
|
_handleResettingJamState();
|
|
break;
|
|
case PlungerState::RECORD:
|
|
_handleRecordState();
|
|
break;
|
|
case PlungerState::REPLAY:
|
|
_handleReplayState();
|
|
break;
|
|
case PlungerState::FILLING: // Re-added case
|
|
_handleFillingState();
|
|
break;
|
|
case PlungerState::POST_FLOW:
|
|
_handlePostFlowState();
|
|
break;
|
|
default:
|
|
Log.warningln("[%s] Unknown state: %d. Transitioning to IDLE.", name.c_str(), static_cast<uint8_t>(_currentState));
|
|
_transitionToState(PlungerState::IDLE);
|
|
break;
|
|
}
|
|
_lastJoystickDirection = currentJoystickDir;
|
|
return E_OK;
|
|
}
|
|
|
|
short Plunger::info()
|
|
{
|
|
Log.verboseln("--- Plunger Info (ID: %d, Name: %s) ---", id, name.c_str());
|
|
|
|
Log.verboseln("State: %d, LastJoy: %d, CurrentJoy: %d",
|
|
static_cast<uint8_t>(_currentState),
|
|
static_cast<int>(_lastJoystickDirection),
|
|
static_cast<int>(_joystick->getValue()));
|
|
|
|
Log.verboseln("SpeedPOT: %d, TorquePOT: %d",
|
|
_currentSpeedPotValue, _currentTorquePotValue);
|
|
uint16_t freq = 0;
|
|
uint16_t current = 0;
|
|
bool freqValid = _vfd->getFrequency(freq);
|
|
bool currentOk = _vfd->getOutputCurrent(current);
|
|
|
|
Log.verboseln("VFD: Running=%s, Fault=%s, FreqSet=%d Hz, OutputCurrent=%d",
|
|
_vfd->isRunning() ? "YES" : "NO",
|
|
_vfd->hasFault() ? "YES" : "NO",
|
|
freqValid ? (static_cast<int>(freq)) : -1,
|
|
currentOk ? static_cast<int>(current) : -1);
|
|
return E_OK;
|
|
}
|
|
|
|
short Plunger::debug()
|
|
{
|
|
return info();
|
|
}
|
|
|
|
short Plunger::serial_register(Bridge *b)
|
|
{
|
|
if (!b)
|
|
return E_INVALID_PARAMETER;
|
|
b->registerMemberFunction(id, this, C_STR("info"), (ComponentFnPtr)&Plunger::info);
|
|
b->registerMemberFunction(id, this, C_STR("plunge"), (ComponentFnPtr)&Plunger::cmd_plunge);
|
|
b->registerMemberFunction(id, this, C_STR("home"), (ComponentFnPtr)&Plunger::cmd_home);
|
|
b->registerMemberFunction(id, this, C_STR("stop"), (ComponentFnPtr)&Plunger::cmd_stop);
|
|
b->registerMemberFunction(id, this, C_STR("fill"), (ComponentFnPtr)&Plunger::cmd_fill);
|
|
b->registerMemberFunction(id, this, C_STR("enableAuto"), (ComponentFnPtr)&Plunger::cmd_enableAutoMode);
|
|
b->registerMemberFunction(id, this, C_STR("disableAuto"), (ComponentFnPtr)&Plunger::cmd_disableAutoMode);
|
|
b->registerMemberFunction(id, this, C_STR("saveSettings"), (ComponentFnPtr)&Plunger::cmd_save_settings);
|
|
b->registerMemberFunction(id, this, C_STR("loadDefaultSettings"), (ComponentFnPtr)&Plunger::cmd_load_default_settings);
|
|
b->registerMemberFunction(id, this, C_STR("replay"), (ComponentFnPtr)&Plunger::cmd_replay);
|
|
return E_OK;
|
|
}
|
|
|
|
short Plunger::cmd_plunge()
|
|
{
|
|
if (!_autoModeEnabled)
|
|
{
|
|
Log.warningln("[%s] cmd_plunge ignored. Auto mode is disabled.", name.c_str());
|
|
return 1;
|
|
}
|
|
if (_currentState == PlungerState::IDLE)
|
|
{
|
|
Log.infoln("[%s] Initiating PLUNGING_AUTO from command.", name.c_str());
|
|
_vfdStartForward(static_cast<uint16_t>(_calculatedPlungingSpeedHz));
|
|
_transitionToState(PlungerState::PLUNGING_AUTO);
|
|
return E_OK;
|
|
}
|
|
else
|
|
{
|
|
Log.warningln("[%s] cmd_plunge ignored. Current state is %d (not IDLE).", name.c_str(), static_cast<int>(_currentState));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
short Plunger::cmd_home()
|
|
{
|
|
if (!_autoModeEnabled)
|
|
{
|
|
Log.warningln("[%s] cmd_home ignored. Auto mode is disabled.", name.c_str());
|
|
return 1;
|
|
}
|
|
if (_currentState == PlungerState::IDLE)
|
|
{
|
|
Log.infoln("[%s] Initiating HOMING_AUTO from command.", name.c_str());
|
|
_vfdStartReverse(static_cast<uint16_t>(_settings.speedSlowHz * 100.0f));
|
|
_transitionToState(PlungerState::HOMING_AUTO);
|
|
return E_OK;
|
|
}
|
|
else
|
|
{
|
|
Log.warningln("[%s] cmd_home ignored. Current state is %d (not IDLE).", name.c_str(), static_cast<int>(_currentState));
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
short Plunger::cmd_stop()
|
|
{
|
|
_transitionToState(PlungerState::STOPPING);
|
|
_vfdStop();
|
|
_vfdResetJam();
|
|
return E_OK;
|
|
}
|
|
|
|
// Definition for cmd_fill
|
|
short Plunger::cmd_fill()
|
|
{
|
|
if (_currentState != PlungerState::IDLE)
|
|
{
|
|
Log.warningln("[%s] cmd_fill ignored. Not IDLE. Current State: %s",
|
|
name.c_str(), _plungerStateToString(_currentState));
|
|
return 1;
|
|
}
|
|
if (!_autoModeEnabled)
|
|
{
|
|
Log.warningln("[%s] cmd_fill ignored. Auto mode is disabled.", name.c_str());
|
|
return 1;
|
|
}
|
|
Log.infoln("[%s] cmd_fill: Initiating FILLING sequence.", name.c_str());
|
|
_currentFillState = FillState::PLUNGING;
|
|
_joystickReleasedSinceAutoStart = false;
|
|
_vfdStartForward(static_cast<uint16_t>(_settings.speedFillPlungeHz * 100.0f));
|
|
_operationStartTimeMs = millis();
|
|
_currentMaxOperationTimeMs = _settings.defaultMaxOperationDurationMs;
|
|
_transitionToState(PlungerState::FILLING);
|
|
return E_OK;
|
|
}
|
|
|
|
// New command implementation to save settings
|
|
short Plunger::cmd_save_settings()
|
|
{
|
|
Log.infoln("[%s] cmd_save_settings: Attempting to save current settings to file...", name.c_str());
|
|
if (_settings.save())
|
|
{
|
|
Log.infoln("[%s] Settings successfully saved via command.", name.c_str());
|
|
return E_OK;
|
|
}
|
|
else
|
|
{
|
|
Log.errorln("[%s] Failed to save settings via command.", name.c_str());
|
|
return 1; // Or a more specific error code
|
|
}
|
|
}
|
|
|
|
// Definition for reset
|
|
short Plunger::reset()
|
|
{
|
|
Log.infoln("[%s] reset() called. Stopping VFD, clearing faults, and re-initializing.", name.c_str());
|
|
_vfdStop();
|
|
_vfdResetJam();
|
|
return this->init();
|
|
}
|
|
|
|
// Definition for setAutoModeEnabled
|
|
void Plunger::setAutoModeEnabled(bool enabled)
|
|
{
|
|
_autoModeEnabled = enabled;
|
|
Log.infoln("[%s] Auto mode %s.", name.c_str(), enabled ? "ENABLED" : "DISABLED");
|
|
}
|
|
|
|
// Definition for isAutoModeEnabled
|
|
bool Plunger::isAutoModeEnabled() const
|
|
{
|
|
return _autoModeEnabled;
|
|
}
|
|
|
|
// Definition for cmd_enableAutoMode
|
|
short Plunger::cmd_enableAutoMode()
|
|
{
|
|
setAutoModeEnabled(true);
|
|
return E_OK;
|
|
}
|
|
|
|
// Definition for cmd_disableAutoMode
|
|
short Plunger::cmd_disableAutoMode()
|
|
{
|
|
setAutoModeEnabled(false);
|
|
return E_OK;
|
|
}
|
|
|
|
// Method to serialize current settings to a JsonDocument
|
|
void Plunger::getSettingsJson(JsonDocument& doc) const {
|
|
_settings.toJson(doc); // Utilize the existing method in PlungerSettings
|
|
}
|
|
|
|
// Method to update settings from a JsonObject and then save them
|
|
bool Plunger::updateSettingsFromJson(const JsonObject& json) {
|
|
if (!_settings.fromJson(json)) { // Utilize the existing method in PlungerSettings
|
|
Log.errorln("[%s] Failed to update settings from JSON in updateSettingsFromJson.", name.c_str());
|
|
return false;
|
|
}
|
|
Log.infoln("[%s] Settings updated from JSON, attempting to save...", name.c_str());
|
|
if (!_settings.save()) { // Utilize the existing save method in PlungerSettings
|
|
Log.errorln("[%s] Failed to save updated settings in updateSettingsFromJson.", name.c_str());
|
|
// Decide if this is a hard failure for the method.
|
|
// For now, if fromJson succeeded but save failed, we might still return true
|
|
// as settings are updated in memory, but log the error. Or return false.
|
|
// Let's return false if save fails, to indicate the full operation wasn't successful.
|
|
return false;
|
|
}
|
|
Log.infoln("[%s] Settings successfully updated from JSON and saved.", name.c_str());
|
|
// After successful update and save, re-initialize parts of Plunger that depend on settings
|
|
// For example, if _recordedPlungeDurationMs or _calculatedPlungingSpeedHz might change.
|
|
_recordedPlungeDurationMs = _settings.replayDurationMs;
|
|
_updatePotValues(); // This recalculates _calculatedPlungingSpeedHz
|
|
// Consider if a more full re-init or specific re-calculations are needed here.
|
|
// For now, updating these two common ones.
|
|
_settings.print();
|
|
return true;
|
|
}
|
|
|
|
short Plunger::cmd_load_default_settings()
|
|
{
|
|
Log.infoln("[%s] cmd_load_default_settings: Attempting to load default settings...", name.c_str());
|
|
if (loadDefaultSettings()) { // Uses default paths defined in Plunger.h declaration
|
|
Log.infoln("[%s] Default settings loaded and applied successfully via command.", name.c_str());
|
|
return E_OK;
|
|
} else {
|
|
Log.errorln("[%s] Failed to load or apply default settings via command.", name.c_str());
|
|
return 1; // Or a more specific error code
|
|
}
|
|
}
|
|
|
|
bool Plunger::loadDefaultSettings(const char* defaultPath, const char* operationalPath) {
|
|
Log.infoln("[%s] Attempting to load settings from default path: %s", name.c_str(), defaultPath);
|
|
PlungerSettings tempSettings = _settings; // Create a copy to attempt loading into
|
|
|
|
if (!tempSettings.load(defaultPath)) {
|
|
Log.errorln("[%s] Failed to load settings from default file: %s", name.c_str(), defaultPath);
|
|
return false;
|
|
}
|
|
Log.infoln("[%s] Successfully loaded settings from %s. Now applying and saving to %s.", name.c_str(), defaultPath, operationalPath);
|
|
|
|
_settings = tempSettings; // Apply loaded settings to the main _settings object
|
|
|
|
if (!_settings.save(operationalPath)) {
|
|
Log.errorln("[%s] Failed to save the loaded default settings to operational path: %s", name.c_str(), operationalPath);
|
|
// Depending on requirements, this might still be considered a partial success if memory update is enough.
|
|
// For now, let's say if save fails, the operation wasn't fully successful.
|
|
return false;
|
|
}
|
|
|
|
// Re-apply any settings-dependent internal states
|
|
_recordedPlungeDurationMs = _settings.replayDurationMs;
|
|
_updatePotValues(); // This recalculates _calculatedPlungingSpeedHz
|
|
_settings.print(); // Log the newly applied settings
|
|
|
|
Log.infoln("[%s] Default settings loaded from %s, applied, and saved to %s.", name.c_str(), defaultPath, operationalPath);
|
|
return true;
|
|
}
|
|
|
|
short Plunger::cmd_replay()
|
|
{
|
|
if (_currentState != PlungerState::IDLE)
|
|
{
|
|
Log.warningln("[%s] cmd_replay ignored. Not IDLE. Current State: %s", name.c_str(), _plungerStateToString(_currentState));
|
|
return 1;
|
|
}
|
|
if (_recordedPlungeDurationMs <= 50) { // Same check as in _handleReplayState
|
|
Log.warningln("[%s] cmd_replay ignored. Invalid or zero replay duration (%lu ms).", name.c_str(), _recordedPlungeDurationMs);
|
|
return 1;
|
|
}
|
|
if (!_autoModeEnabled) // Consider if replay should be subject to autoModeEnabled
|
|
{
|
|
Log.warningln("[%s] cmd_replay ignored. Auto mode is disabled.", name.c_str());
|
|
return 1;
|
|
} // Depending on requirements, you might allow replay even if auto mode is off.
|
|
|
|
Log.infoln("[%s] Initiating REPLAY from command.", name.c_str());
|
|
_transitionToState(PlungerState::REPLAY);
|
|
// _handleReplayState will start the VFD and set timers.
|
|
return E_OK;
|
|
}
|