From 9d6aaa2a0ec75304183198a84c3904925e5f749b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 27 Dec 2025 20:02:52 +0000 Subject: [PATCH 1/5] Initial plan From 7ea1efbabf25aba18e04a4479ab3e0fe05636582 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 27 Dec 2025 20:09:31 +0000 Subject: [PATCH 2/5] Add raise/lower movement time configuration and banked command support Co-authored-by: erikdred <88980320+erikdred@users.noreply.github.com> --- .../Displays/ScreenLiftController.cs | 105 ++++++++++++++++++ .../Displays/ScreenLiftRelaysConfig.cs | 6 + 2 files changed, 111 insertions(+) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index 9163c2a32..5d25a58ab 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,10 @@ public class ScreenLiftController : EssentialsDevice, IProjectorScreenLiftContro ISwitchedOutput LowerRelay; ISwitchedOutput LatchedRelay; + private bool _isMoving; + private RequestedState _requestedState; + private CTimer _movementTimer; + /// /// Gets or sets the InUpPosition /// @@ -163,6 +177,16 @@ public void Raise() { if (RaiseRelay == null && LatchedRelay == null) return; + 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) @@ -170,11 +194,25 @@ public void Raise() case eScreenLiftControlMode.momentary: { PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs); + + // Set moving flag and start timer if movement time is configured + if (RaiseRelayConfig.MovementTimeInMs > 0) + { + _isMoving = true; + _movementTimer = new CTimer(OnMovementComplete, RaiseRelayConfig.MovementTimeInMs); + } break; } case eScreenLiftControlMode.latched: { LatchedRelay.Off(); + + // Set moving flag and start timer if movement time is configured + if (LatchedRelayConfig.MovementTimeInMs > 0) + { + _isMoving = true; + _movementTimer = new CTimer(OnMovementComplete, LatchedRelayConfig.MovementTimeInMs); + } break; } } @@ -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,17 +243,74 @@ public void Lower() case eScreenLiftControlMode.momentary: { PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs); + + // Set moving flag and start timer if movement time is configured + if (LowerRelayConfig.MovementTimeInMs > 0) + { + _isMoving = true; + _movementTimer = new CTimer(OnMovementComplete, LowerRelayConfig.MovementTimeInMs); + } break; } case eScreenLiftControlMode.latched: { LatchedRelay.On(); + + // Set moving flag and start timer if movement time is configured + if (LatchedRelayConfig.MovementTimeInMs > 0) + { + _isMoving = true; + _movementTimer = new CTimer(OnMovementComplete, LatchedRelayConfig.MovementTimeInMs); + } break; } } InUpPosition = false; } + /// + /// Called when movement timer completes + /// + void OnMovementComplete(object o) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Movement complete"); + + _isMoving = false; + + // 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 + // If so, ignore it + if (commandToExecute == RequestedState.Raise && InUpPosition) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Already in up position, ignoring banked Raise command"); + return; + } + + if (commandToExecute == RequestedState.Lower && !InUpPosition) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Already in down position, ignoring banked Lower command"); + return; + } + + // Execute the banked command + if (commandToExecute == RequestedState.Raise) + { + Raise(); + } + else if (commandToExecute == RequestedState.Lower) + { + Lower(); + } + } + } + void PulseOutput(ISwitchedOutput output, int pulseTime) { output.On(); diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs index 4de9eb25f..a99f82d38 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 MovementTimeInMs - time in milliseconds for the movement to complete + /// + [JsonProperty("movementTimeInMs")] + public int MovementTimeInMs { get; set; } } } \ No newline at end of file From bd11c827daef5f6938c5cb89681de3649ebea126 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 27 Dec 2025 20:14:39 +0000 Subject: [PATCH 3/5] Split movement time into separate raise/lower times and remove timing from latched mode Co-authored-by: erikdred <88980320+erikdred@users.noreply.github.com> --- .../Displays/ScreenLiftController.cs | 40 ++++++++++--------- .../Displays/ScreenLiftRelaysConfig.cs | 12 ++++-- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index 5d25a58ab..4494fdbfa 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs @@ -196,23 +196,24 @@ public void Raise() PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs); // Set moving flag and start timer if movement time is configured - if (RaiseRelayConfig.MovementTimeInMs > 0) + if (RaiseRelayConfig.RaiseTimeInMs > 0) { _isMoving = true; - _movementTimer = new CTimer(OnMovementComplete, RaiseRelayConfig.MovementTimeInMs); + + // Dispose previous timer if exists + if (_movementTimer != null) + { + _movementTimer.Stop(); + _movementTimer.Dispose(); + } + + _movementTimer = new CTimer(OnMovementComplete, RaiseRelayConfig.RaiseTimeInMs); } break; } case eScreenLiftControlMode.latched: { LatchedRelay.Off(); - - // Set moving flag and start timer if movement time is configured - if (LatchedRelayConfig.MovementTimeInMs > 0) - { - _isMoving = true; - _movementTimer = new CTimer(OnMovementComplete, LatchedRelayConfig.MovementTimeInMs); - } break; } } @@ -245,23 +246,24 @@ public void Lower() PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs); // Set moving flag and start timer if movement time is configured - if (LowerRelayConfig.MovementTimeInMs > 0) + if (LowerRelayConfig.LowerTimeInMs > 0) { _isMoving = true; - _movementTimer = new CTimer(OnMovementComplete, LowerRelayConfig.MovementTimeInMs); + + // Dispose previous timer if exists + if (_movementTimer != null) + { + _movementTimer.Stop(); + _movementTimer.Dispose(); + } + + _movementTimer = new CTimer(OnMovementComplete, LowerRelayConfig.LowerTimeInMs); } break; } case eScreenLiftControlMode.latched: { LatchedRelay.On(); - - // Set moving flag and start timer if movement time is configured - if (LatchedRelayConfig.MovementTimeInMs > 0) - { - _isMoving = true; - _movementTimer = new CTimer(OnMovementComplete, LatchedRelayConfig.MovementTimeInMs); - } break; } } @@ -271,7 +273,7 @@ public void Lower() /// /// Called when movement timer completes /// - void OnMovementComplete(object o) + private void OnMovementComplete(object o) { Debug.LogMessage(LogEventLevel.Debug, this, $"Movement complete"); diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs index a99f82d38..f39134a41 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs @@ -20,9 +20,15 @@ public class ScreenLiftRelaysConfig public int PulseTimeInMs { get; set; } /// - /// Gets or sets the MovementTimeInMs - time in milliseconds for the movement to complete + /// Gets or sets the RaiseTimeInMs - time in milliseconds for the raise movement to complete /// - [JsonProperty("movementTimeInMs")] - public int MovementTimeInMs { get; set; } + [JsonProperty("raiseTimeInMs")] + public int RaiseTimeInMs { get; set; } + + /// + /// Gets or sets the LowerTimeInMs - time in milliseconds for the lower movement to complete + /// + [JsonProperty("lowerTimeInMs")] + public int LowerTimeInMs { get; set; } } } \ No newline at end of file From ae0b2fe0864692fd85a8c9fffce8f02fc4b3a105 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 27 Dec 2025 20:17:59 +0000 Subject: [PATCH 4/5] Refactor timer disposal and improve code readability Co-authored-by: erikdred <88980320+erikdred@users.noreply.github.com> --- .../Displays/ScreenLiftController.cs | 75 ++++++++++--------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index 4494fdbfa..459819aff 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs @@ -199,14 +199,7 @@ public void Raise() if (RaiseRelayConfig.RaiseTimeInMs > 0) { _isMoving = true; - - // Dispose previous timer if exists - if (_movementTimer != null) - { - _movementTimer.Stop(); - _movementTimer.Dispose(); - } - + DisposeMovementTimer(); _movementTimer = new CTimer(OnMovementComplete, RaiseRelayConfig.RaiseTimeInMs); } break; @@ -249,14 +242,7 @@ public void Lower() if (LowerRelayConfig.LowerTimeInMs > 0) { _isMoving = true; - - // Dispose previous timer if exists - if (_movementTimer != null) - { - _movementTimer.Stop(); - _movementTimer.Dispose(); - } - + DisposeMovementTimer(); _movementTimer = new CTimer(OnMovementComplete, LowerRelayConfig.LowerTimeInMs); } break; @@ -270,6 +256,19 @@ public void Lower() 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 /// @@ -287,28 +286,30 @@ private void OnMovementComplete(object o) var commandToExecute = _requestedState; _requestedState = RequestedState.None; - // Check if current state matches what the banked command would do - // If so, ignore it - if (commandToExecute == RequestedState.Raise && InUpPosition) - { - Debug.LogMessage(LogEventLevel.Debug, this, $"Already in up position, ignoring banked Raise command"); - return; - } - - if (commandToExecute == RequestedState.Lower && !InUpPosition) - { - Debug.LogMessage(LogEventLevel.Debug, this, $"Already in down position, ignoring banked Lower command"); - return; - } - - // Execute the banked command - if (commandToExecute == RequestedState.Raise) + // Check if current state matches what the banked command would do and execute if different + switch (commandToExecute) { - Raise(); - } - else if (commandToExecute == RequestedState.Lower) - { - Lower(); + case RequestedState.Raise: + if (InUpPosition) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Already in up position, ignoring banked Raise command"); + } + else + { + Raise(); + } + break; + + case RequestedState.Lower: + if (!InUpPosition) + { + Debug.LogMessage(LogEventLevel.Debug, this, $"Already in down position, ignoring banked Lower command"); + } + else + { + Lower(); + } + break; } } } From a7ff2e8903487c3aea66f136f2184693b11219b3 Mon Sep 17 00:00:00 2001 From: Erik Meyer Date: Sat, 27 Dec 2025 17:09:56 -0600 Subject: [PATCH 5/5] fix: move isInUpPosition to momvement complete method, remove conditionlal logic on raise/lower commands --- .../Displays/ScreenLiftController.cs | 56 +++++++++++-------- .../Displays/ScreenLiftRelaysConfig.cs | 12 +--- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index 459819aff..aad8f54a8 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs @@ -37,6 +37,7 @@ public class ScreenLiftController : EssentialsDevice, IProjectorScreenLiftContro private bool _isMoving; private RequestedState _requestedState; + private RequestedState _currentMovement; private CTimer _movementTimer; /// @@ -188,7 +189,7 @@ public void Raise() } Debug.LogMessage(LogEventLevel.Debug, this, $"Raising {Type}"); - + switch (Mode) { case eScreenLiftControlMode.momentary: @@ -196,21 +197,26 @@ public void Raise() PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs); // Set moving flag and start timer if movement time is configured - if (RaiseRelayConfig.RaiseTimeInMs > 0) + if (RaiseRelayConfig.MoveTimeInMs > 0) { _isMoving = true; + _currentMovement = RequestedState.Raise; DisposeMovementTimer(); - _movementTimer = new CTimer(OnMovementComplete, RaiseRelayConfig.RaiseTimeInMs); + _movementTimer = new CTimer(OnMovementComplete, RaiseRelayConfig.MoveTimeInMs); + } + else + { + InUpPosition = true; } break; } case eScreenLiftControlMode.latched: { LatchedRelay.Off(); + InUpPosition = true; break; } } - InUpPosition = true; } /// @@ -221,7 +227,7 @@ 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) { @@ -239,21 +245,26 @@ public void Lower() PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs); // Set moving flag and start timer if movement time is configured - if (LowerRelayConfig.LowerTimeInMs > 0) + if (LowerRelayConfig.MoveTimeInMs > 0) { _isMoving = true; + _currentMovement = RequestedState.Lower; DisposeMovementTimer(); - _movementTimer = new CTimer(OnMovementComplete, LowerRelayConfig.LowerTimeInMs); + _movementTimer = new CTimer(OnMovementComplete, LowerRelayConfig.MoveTimeInMs); + } + else + { + InUpPosition = false; } break; } case eScreenLiftControlMode.latched: { LatchedRelay.On(); + InUpPosition = false; break; } } - InUpPosition = false; } /// @@ -276,7 +287,18 @@ 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) @@ -290,25 +312,11 @@ private void OnMovementComplete(object o) switch (commandToExecute) { case RequestedState.Raise: - if (InUpPosition) - { - Debug.LogMessage(LogEventLevel.Debug, this, $"Already in up position, ignoring banked Raise command"); - } - else - { - Raise(); - } + Raise(); break; case RequestedState.Lower: - if (!InUpPosition) - { - Debug.LogMessage(LogEventLevel.Debug, this, $"Already in down position, ignoring banked Lower command"); - } - else - { - Lower(); - } + Lower(); break; } } diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs index f39134a41..8890ac95d 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs @@ -20,15 +20,9 @@ public class ScreenLiftRelaysConfig public int PulseTimeInMs { get; set; } /// - /// Gets or sets the RaiseTimeInMs - time in milliseconds for the raise movement to complete + /// Gets or sets the MoveTimeInMs - time in milliseconds for the movement to complete /// - [JsonProperty("raiseTimeInMs")] - public int RaiseTimeInMs { get; set; } - - /// - /// Gets or sets the LowerTimeInMs - time in milliseconds for the lower movement to complete - /// - [JsonProperty("lowerTimeInMs")] - public int LowerTimeInMs { get; set; } + [JsonProperty("moveTimeInMs")] + public int MoveTimeInMs { get; set; } } } \ No newline at end of file