diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index 9163c2a32..aad8f54a8 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs @@ -10,6 +10,16 @@ namespace PepperDash.Essentials.Devices.Common.Shades { + /// + /// Enumeration for requested state + /// + enum RequestedState + { + None, + Raise, + Lower + } + /// /// Controls a single shade using three relays /// @@ -25,6 +35,11 @@ public class ScreenLiftController : EssentialsDevice, IProjectorScreenLiftContro ISwitchedOutput LowerRelay; ISwitchedOutput LatchedRelay; + private bool _isMoving; + private RequestedState _requestedState; + private RequestedState _currentMovement; + private CTimer _movementTimer; + /// /// Gets or sets the InUpPosition /// @@ -163,22 +178,45 @@ public void Raise() { if (RaiseRelay == null && LatchedRelay == null) return; - Debug.LogMessage(LogEventLevel.Debug, this, $"Raising {Type}"); + Debug.LogMessage(LogEventLevel.Debug, this, $"Raise called for {Type}"); + + // If device is moving, bank the command + if (_isMoving) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Device is moving, banking Raise command"); + _requestedState = RequestedState.Raise; + return; + } + Debug.LogMessage(LogEventLevel.Debug, this, $"Raising {Type}"); + switch (Mode) { case eScreenLiftControlMode.momentary: { PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs); + + // Set moving flag and start timer if movement time is configured + if (RaiseRelayConfig.MoveTimeInMs > 0) + { + _isMoving = true; + _currentMovement = RequestedState.Raise; + DisposeMovementTimer(); + _movementTimer = new CTimer(OnMovementComplete, RaiseRelayConfig.MoveTimeInMs); + } + else + { + InUpPosition = true; + } break; } case eScreenLiftControlMode.latched: { LatchedRelay.Off(); + InUpPosition = true; break; } } - InUpPosition = true; } /// @@ -188,6 +226,16 @@ public void Lower() { if (LowerRelay == null && LatchedRelay == null) return; + Debug.LogMessage(LogEventLevel.Debug, this, $"Lower called for {Type}"); + + // If device is moving, bank the command + if (_isMoving) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Device is moving, banking Lower command"); + _requestedState = RequestedState.Lower; + return; + } + Debug.LogMessage(LogEventLevel.Debug, this, $"Lowering {Type}"); switch (Mode) @@ -195,15 +243,83 @@ public void Lower() case eScreenLiftControlMode.momentary: { PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs); + + // Set moving flag and start timer if movement time is configured + if (LowerRelayConfig.MoveTimeInMs > 0) + { + _isMoving = true; + _currentMovement = RequestedState.Lower; + DisposeMovementTimer(); + _movementTimer = new CTimer(OnMovementComplete, LowerRelayConfig.MoveTimeInMs); + } + else + { + InUpPosition = false; + } break; } case eScreenLiftControlMode.latched: { LatchedRelay.On(); + InUpPosition = false; break; } } - InUpPosition = false; + } + + /// + /// Disposes the current movement timer if it exists + /// + private void DisposeMovementTimer() + { + if (_movementTimer != null) + { + _movementTimer.Stop(); + _movementTimer.Dispose(); + _movementTimer = null; + } + } + + /// + /// Called when movement timer completes + /// + private void OnMovementComplete(object o) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Movement complete"); + + // Update position based on completed movement + if (_currentMovement == RequestedState.Raise) + { + InUpPosition = true; + } + else if (_currentMovement == RequestedState.Lower) + { + InUpPosition = false; + } + + _isMoving = false; + _currentMovement = RequestedState.None; + + // Execute banked command if one exists + if (_requestedState != RequestedState.None) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Executing banked command: {_requestedState}"); + + var commandToExecute = _requestedState; + _requestedState = RequestedState.None; + + // Check if current state matches what the banked command would do and execute if different + switch (commandToExecute) + { + case RequestedState.Raise: + Raise(); + break; + + case RequestedState.Lower: + Lower(); + break; + } + } } void PulseOutput(ISwitchedOutput output, int pulseTime) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs index 4de9eb25f..8890ac95d 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs @@ -18,5 +18,11 @@ public class ScreenLiftRelaysConfig /// [JsonProperty("pulseTimeInMs")] public int PulseTimeInMs { get; set; } + + /// + /// Gets or sets the MoveTimeInMs - time in milliseconds for the movement to complete + /// + [JsonProperty("moveTimeInMs")] + public int MoveTimeInMs { get; set; } } } \ No newline at end of file