Compare commits

..

6 Commits

Author SHA1 Message Date
Andrew Welker
4437074f07 fix: implement copilot suggestions 2026-02-09 08:45:28 -06:00
Andrew Welker
1fb5d3e5ee fix: make registering for push schedule updates optional
The default config for a Fusion room will now NOT subscribe for Fusion schedule push updates unless explicitly
requested.
2026-02-09 08:09:18 -06:00
equinoy
c0971a4f8e Merge remote-tracking branch 'origin/screen-lift-controller-mute-logic' into feature/circuittype-property-versiport 2026-01-22 15:36:27 -06:00
equinoy
8bc6d4392b feat: add circuitType property to IOPortConfig and implement state inversion in digital input devices 2026-01-22 15:04:25 -06:00
Nick Genovese
f49901d3fa fix: Improve status messages in StatusMonitorCollection
Enhanced error and warning message generation to use monitor names when available, include counts, proper pluralization, and append "Offline" when issues are present. Avoided multiple enumerations by converting to lists. "Room Ok." is shown when no issues are detected.
2026-01-01 18:01:37 -06:00
Nick Genovese
7910b7931e feat: Add mute logic to ScreenLiftController
- adds a config value that mutes the display when the screen is in the up position
- screens will now mute/unmute based on their position if the config is set
2026-01-01 09:02:04 -06:00
18 changed files with 286 additions and 262 deletions

View File

@@ -15,23 +15,23 @@ namespace PepperDash.Core
/// Unique Key
/// </summary>
public string Key { get; protected set; }
/// <summary>
/// Gets or sets the Name
/// </summary>
/// <summary>
/// Gets or sets the Name
/// </summary>
public string Name { get; protected set; }
/// <summary>
/// Gets or sets a value indicating whether the device is enabled
///
/// </summary>
public bool Enabled { get; protected set; }
// /// <summary>
// /// A place to store reference to the original config object, if any. These values should
// /// NOT be used as properties on the device as they are all publicly-settable values.
// /// </summary>
/// <summary>
/// A place to store reference to the original config object, if any. These values should
/// NOT be used as properties on the device as they are all publicly-settable values.
/// </summary>
//public DeviceConfig Config { get; private set; }
// /// <summary>
// /// Helper method to check if Config exists
// /// </summary>
/// <summary>
/// Helper method to check if Config exists
/// </summary>
//public bool HasConfig { get { return Config != null; } }
List<Action> _PreActivationActions;

View File

@@ -41,9 +41,6 @@ namespace PepperDash.Core
CrestronConsole.PrintLine(message);
}
/// <summary>
/// Constructor for DebugConsoleSink
/// </summary>
public DebugConsoleSink(ITextFormatter formatProvider )
{
_textFormatter = formatProvider ?? new JsonFormatter();
@@ -51,9 +48,6 @@ namespace PepperDash.Core
}
/// <summary>
/// Provides extension methods for DebugConsoleSink
/// </summary>
public static class DebugConsoleSinkExtensions
{
/// <summary>

View File

@@ -27,9 +27,6 @@ namespace PepperDash.Core.Logging
CrestronLogger.WriteToLog(message, (uint)logEvent.Level);
}
/// <summary>
/// Constructor for DebugCrestronLoggerSink
/// </summary>
public DebugCrestronLoggerSink()
{
CrestronLogger.Initialize(1, LoggerModeEnum.RM);

View File

@@ -63,10 +63,6 @@ namespace PepperDash.Core.Logging
handler(message);
}
/// <summary>
/// Constructor for DebugErrorLogSink
/// </summary>
/// <param name="formatter">text formatter for log output</param>
public DebugErrorLogSink(ITextFormatter formatter = null)
{
_formatter = formatter;

View File

@@ -4,9 +4,6 @@ using Log = PepperDash.Core.Debug;
namespace PepperDash.Core.Logging
{
/// <summary>
/// Provides extension methods for logging on IKeyed objects
/// </summary>
public static class DebugExtensions
{
/// <summary>

View File

@@ -32,9 +32,6 @@ namespace PepperDash.Core
private const string _certificateName = "selfCres";
private const string _certificatePassword = "cres12345";
/// <summary>
/// Gets the Port
/// </summary>
public int Port
{ get
{
@@ -44,9 +41,6 @@ namespace PepperDash.Core
}
}
/// <summary>
/// Gets the Url
/// </summary>
public string Url
{
get
@@ -64,11 +58,6 @@ namespace PepperDash.Core
private readonly ITextFormatter _textFormatter;
/// <summary>
/// Constructor for DebugWebsocketSink
/// </summary>
/// <param name="formatProvider">text formatter for log output</param>
public DebugWebsocketSink(ITextFormatter formatProvider)
{
@@ -228,9 +217,6 @@ namespace PepperDash.Core
}
}
/// <summary>
/// Provides extension methods for DebugWebsocketSink
/// </summary>
public static class DebugWebsocketSinkExtensions
{
/// <summary>
@@ -251,9 +237,6 @@ namespace PepperDash.Core
{
private DateTime _connectionTime;
/// <summary>
/// Gets the ConnectedDuration
/// </summary>
public TimeSpan ConnectedDuration
{
get
@@ -269,17 +252,11 @@ namespace PepperDash.Core
}
}
/// <summary>
/// Constructor for DebugClient
/// </summary>
public DebugClient()
{
Debug.Console(0, "DebugClient Created");
}
/// <summary>
/// OnOpen method
/// </summary>
protected override void OnOpen()
{
base.OnOpen();
@@ -290,9 +267,6 @@ namespace PepperDash.Core
_connectionTime = DateTime.Now;
}
/// <summary>
/// OnMessage method
/// </summary>
protected override void OnMessage(MessageEventArgs e)
{
base.OnMessage(e);
@@ -300,9 +274,6 @@ namespace PepperDash.Core
Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data);
}
/// <summary>
/// OnClose method
/// </summary>
protected override void OnClose(CloseEventArgs e)
{
base.OnClose(e);
@@ -311,9 +282,6 @@ namespace PepperDash.Core
}
/// <summary>
/// OnError method
/// </summary>
protected override void OnError(WebSocketSharp.ErrorEventArgs e)
{
base.OnError(e);

View File

@@ -5,16 +5,9 @@ using System.Threading.Tasks;
namespace PepperDash.Core.Web.RequestHandlers
{
/// <summary>
/// CWS Base Async Handler, implements IHttpCwsHandler
/// </summary>
public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler
{
private readonly Dictionary<string, Func<HttpCwsContext, Task>> _handlers;
/// <summary>
/// Indicates whether CORS is enabled
/// </summary>
protected readonly bool EnableCors;
/// <summary>

View File

@@ -10,10 +10,6 @@ namespace PepperDash.Core.Web.RequestHandlers
public abstract class WebApiBaseRequestHandler : IHttpCwsHandler
{
private readonly Dictionary<string, Action<HttpCwsContext>> _handlers;
/// <summary>
/// Indicates whether CORS is enabled
/// </summary>
protected readonly bool EnableCors;
/// <summary>

View File

@@ -45,9 +45,9 @@ namespace PepperDash.Core.Web
/// </summary>
public bool IsRegistered { get; private set; }
// /// <summary>
// /// Http request handler
// /// </summary>
/// <summary>
/// Http request handler
/// </summary>
//public IHttpCwsHandler HttpRequestHandler
//{
// get { return _server.HttpRequestHandler; }
@@ -58,9 +58,9 @@ namespace PepperDash.Core.Web
// }
//}
// /// <summary>
// /// Received request event handler
// /// </summary>
/// <summary>
/// Received request event handler
/// </summary>
//public event EventHandler<HttpCwsRequestEventArgs> ReceivedRequestEvent
//{
// add { _server.ReceivedRequestEvent += new HttpCwsRequestEventHandler(value); }

View File

@@ -21,6 +21,7 @@ namespace PepperDash.Essentials.Core.CrestronIO
public class GenericDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IHasFeedback
{
private DigitalInput inputPort;
private readonly bool invertState;
/// <summary>
/// Gets or sets the InputStateFeedback
@@ -41,7 +42,9 @@ namespace PepperDash.Essentials.Core.CrestronIO
IOPortConfig config)
: base(key, name)
{
InputStateFeedback = new BoolFeedback("inputState", () => inputPort.State);
invertState = string.Equals(config.CircuitType, "NC", StringComparison.OrdinalIgnoreCase);
InputStateFeedback = new BoolFeedback("inputState", () => invertState ? !inputPort.State : inputPort.State);
AddPostActivationAction(() =>
{

View File

@@ -18,6 +18,7 @@ namespace PepperDash.Essentials.Core.CrestronIO
public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IPartitionStateProvider, IHasFeedback
{
private Versiport inputPort;
private readonly bool invertState;
/// <summary>
/// Gets or sets the InputStateFeedback
@@ -47,7 +48,10 @@ namespace PepperDash.Essentials.Core.CrestronIO
public GenericVersiportDigitalInputDevice(string key, string name, Func<IOPortConfig, Versiport> postActivationFunc, IOPortConfig config) :
base(key, name)
{
InputStateFeedback = new BoolFeedback("inputState", () => inputPort.DigitalIn);
var circuitType = string.IsNullOrEmpty(config.CircuitType) ? "NO" : config.CircuitType;
invertState = circuitType.Equals("NC", StringComparison.OrdinalIgnoreCase);
InputStateFeedback = new BoolFeedback("inputState", () => invertState ? !inputPort.DigitalIn : inputPort.DigitalIn);
PartitionPresentFeedback = new BoolFeedback("partitionPresent", () => !inputPort.DigitalIn);
AddPostActivationAction(() =>

View File

@@ -37,5 +37,12 @@ namespace PepperDash.Essentials.Core.CrestronIO
/// </summary>
[JsonProperty("minimumChange")]
public int MinimumChange { get; set; }
/// <summary>
/// Gets or sets the circuit type: "NO" (Normally Open) or "NC" (Normally Closed)
/// If set to "NC", the input state will be inverted. Defaults to "NO" if not specified.
/// </summary>
[JsonProperty("circuitType")]
public string CircuitType { get; set; } = "NO";
}
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
@@ -698,18 +699,26 @@ namespace PepperDash.Essentials.Core.Fusion
/// <param name="args"></param>
protected void FusionRoom_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args)
{
if (args.DeviceOnLine)
if (!args.DeviceOnLine)
{
CrestronInvoke.BeginInvoke((o) =>
{
CrestronEnvironment.Sleep(200);
return;
}
// Send Push Notification Action request:
if (!_config.EnableSchedulePushNotifications)
{
return;
}
const string requestId = "InitialPushRequest";
Task.Run(() =>
{
// CrestronEnvironment.Sleep(200);
// Send Push Notification Action request:
const string requestId = "InitialPushRequest";
var actionRequest =
var actionRequest =
string.Format("<RequestAction>\n<RequestID>{0}</RequestID>\n", requestId) +
"<ActionID>RegisterPushModel</ActionID>\n" +
"<Parameters>\n" +
@@ -734,27 +743,26 @@ namespace PepperDash.Essentials.Core.Fusion
"</Parameters>\n" +
"</RequestAction>\n";
Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ActionRequest: \n{0}", actionRequest);
Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ActionRequest: \n{0}", actionRequest);
FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = actionRequest;
FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = actionRequest;
GetCustomProperties();
GetCustomProperties();
// Request current Fusion Server Time
RequestLocalDateTime(null);
// Request current Fusion Server Time
RequestLocalDateTime(null);
// Setup timer to request time daily
if (_dailyTimeRequestTimer != null && !_dailyTimeRequestTimer.Disposed)
{
_dailyTimeRequestTimer.Stop();
_dailyTimeRequestTimer.Dispose();
}
// Setup timer to request time daily
if (_dailyTimeRequestTimer != null && !_dailyTimeRequestTimer.Disposed)
{
_dailyTimeRequestTimer.Stop();
_dailyTimeRequestTimer.Dispose();
}
_dailyTimeRequestTimer = new CTimer(RequestLocalDateTime, null, 86400000, 86400000);
_dailyTimeRequestTimer = new CTimer(RequestLocalDateTime, null, 86400000, 86400000);
_dailyTimeRequestTimer.Reset(86400000, 86400000);
});
}
_dailyTimeRequestTimer.Reset(86400000, 86400000);
});
}
/// <summary>
@@ -785,7 +793,7 @@ namespace PepperDash.Essentials.Core.Fusion
var requestTest =
string.Format(
"<RequestSchedule><RequestID>FullSchedleRequest</RequestID><RoomID>{0}</RoomID><Start>{1}</Start><HourSpan>24</HourSpan></RequestSchedule>",
"<RequestSchedule><RequestID>FullScheduleRequest</RequestID><RoomID>{0}</RoomID><Start>{1}</Start><HourSpan>24</HourSpan></RequestSchedule>",
RoomGuid, currentTime);
Debug.LogMessage(LogEventLevel.Verbose, this, "Sending Fusion ScheduleQuery: \n{0}", requestTest);
@@ -960,7 +968,7 @@ namespace PepperDash.Essentials.Core.Fusion
select parameter.Attributes
into attributes
where attributes["ID"].Value == "Registered"
select Int32.Parse(attributes["Value"].Value))
select int.Parse(attributes["Value"].Value))
{
switch (isRegistered)
{
@@ -1112,7 +1120,7 @@ namespace PepperDash.Essentials.Core.Fusion
protected void FusionRoomSchedule_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender,
SigEventArgs args)
{
Debug.LogMessage(LogEventLevel.Verbose, this, "Scehdule Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event,
Debug.LogMessage(LogEventLevel.Verbose, this, "Schedule Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event,
args.Sig.Name, args.Sig.StringValue);

View File

@@ -75,4 +75,11 @@ public class IEssentialsRoomFusionControllerPropertiesConfig
/// </summary>
[JsonProperty("helpRequestTimeoutMs")]
public int HelpRequestTimeoutMs { get; set; } = 30000;
/// <summary>
/// Gets or sets whether to enable schedule push notifications
/// </summary>
/// <remarks>Defaults to false to skip getting schedule unless required</remarks>
[JsonProperty("enableSchedulePushNotifications")]
public bool EnableSchedulePushNotifications { get; set; } = false;
}

View File

@@ -14,7 +14,7 @@ using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
/// <summary>
///
///
/// </summary>
public class StatusMonitorCollection : IStatusMonitor
{
@@ -59,51 +59,61 @@ namespace PepperDash.Essentials.Core
void ProcessStatuses()
{
var InError = Monitors.Where(m => m.Status == MonitorStatus.InError);
var InWarning = Monitors.Where(m => m.Status == MonitorStatus.InWarning);
var IsOk = Monitors.Where(m => m.Status == MonitorStatus.IsOk);
var InError = Monitors.Where(m => m.Status == MonitorStatus.InError).ToList();
var InWarning = Monitors.Where(m => m.Status == MonitorStatus.InWarning).ToList();
var IsOk = Monitors.Where(m => m.Status == MonitorStatus.IsOk).ToList();
MonitorStatus initialStatus;
string prefix = "0:";
if (InError.Count() > 0)
if (InError.Any())
{
initialStatus = MonitorStatus.InError;
prefix = "3:";
}
else if (InWarning.Count() > 0)
else if (InWarning.Any())
{
initialStatus = MonitorStatus.InWarning;
prefix = "2:";
}
else if (IsOk.Count() > 0)
else if (IsOk.Any())
initialStatus = MonitorStatus.IsOk;
else
initialStatus = MonitorStatus.StatusUnknown;
// Build the error message string
if (InError.Count() > 0 || InWarning.Count() > 0)
{
StringBuilder sb = new StringBuilder(prefix);
if (InError.Count() > 0)
{
// Do string splits and joins
sb.Append(string.Format("{0} Errors:", InError.Count()));
foreach (var mon in InError)
sb.Append(string.Format("{0}, ", mon.Parent.Key));
}
if (InWarning.Count() > 0)
{
sb.Append(string.Format("{0} Warnings:", InWarning.Count()));
foreach (var mon in InWarning)
sb.Append(string.Format("{0}, ", mon.Parent.Key));
}
Message = sb.ToString();
}
else
{
Message = "Room Ok.";
}
if (InError.Any() || InWarning.Any())
{
var errorNames = InError
.Select(mon => mon.Parent is IKeyName keyName ? keyName.Name : mon.Parent.Key)
.ToList();
var warningNames = InWarning
.Select(mon => mon.Parent is IKeyName keyName ? keyName.Name : mon.Parent.Key)
.ToList();
var sb = new StringBuilder(prefix);
if (errorNames.Count > 0)
{
sb.Append($"{errorNames.Count} Error{(errorNames.Count > 1 ? "s" : "")}: ");
sb.Append(string.Join(", ", errorNames));
}
if (warningNames.Count > 0)
{
if (errorNames.Count > 0)
sb.Append("; ");
sb.Append($"{warningNames.Count} Warning{(warningNames.Count > 1 ? "s" : "")}: ");
sb.Append(string.Join(", ", warningNames));
}
sb.Append(" Offline");
Message = sb.ToString();
}
else
{
Message = "Room Ok.";
}
// Want to fire even if status doesn't change because the message may.
Status = initialStatus;

View File

@@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Devices.Common.Shades
{
None,
Raise,
Lower
Lower,
}
/// <summary>
@@ -50,7 +50,8 @@ namespace PepperDash.Essentials.Devices.Common.Shades
get { return _isInUpPosition; }
set
{
if (value == _isInUpPosition) return;
if (value == _isInUpPosition)
return;
_isInUpPosition = value;
IsInUpPosition.FireUpdate();
PositionChanged?.Invoke(this, new EventArgs());
@@ -87,7 +88,11 @@ namespace PepperDash.Essentials.Devices.Common.Shades
/// <summary>
/// Constructor for ScreenLiftController
/// </summary>
public ScreenLiftController(string key, string name, ScreenLiftControllerConfigProperties config)
public ScreenLiftController(
string key,
string name,
ScreenLiftControllerConfigProperties config
)
: base(key, name)
{
Config = config;
@@ -105,27 +110,60 @@ namespace PepperDash.Essentials.Devices.Common.Shades
switch (Mode)
{
case eScreenLiftControlMode.momentary:
{
RaiseRelayConfig = Config.Relays["raise"];
LowerRelayConfig = Config.Relays["lower"];
break;
}
{
RaiseRelayConfig = Config.Relays["raise"];
LowerRelayConfig = Config.Relays["lower"];
break;
}
case eScreenLiftControlMode.latched:
{
LatchedRelayConfig = Config.Relays["latched"];
break;
}
{
LatchedRelayConfig = Config.Relays["latched"];
break;
}
}
IsInUpPosition.OutputChange += (sender, args) =>
{
this.LogDebug(
"ScreenLiftController '{name}' IsInUpPosition changed to {position}",
Name,
IsInUpPosition.BoolValue ? "Up" : "Down"
);
if (!Config.MuteOnScreenUp)
{
return;
}
if (args.BoolValue)
{
return;
}
if (DisplayDevice is IBasicVideoMuteWithFeedback videoMute)
{
this.LogInformation("Unmuting video because screen is down");
videoMute.VideoMuteOff();
}
};
IsInUpPosition.FireUpdate();
}
private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
if (!DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.lift)
if (
!DisplayDevice.IsCoolingDownFeedback.BoolValue
&& Type == eScreenLiftControlType.lift
)
{
Raise();
return;
}
if (DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.screen)
if (
DisplayDevice.IsCoolingDownFeedback.BoolValue
&& Type == eScreenLiftControlType.screen
)
{
Raise();
return;
@@ -150,18 +188,18 @@ namespace PepperDash.Essentials.Devices.Common.Shades
switch (Mode)
{
case eScreenLiftControlMode.momentary:
{
this.LogDebug("Getting relays for {mode}", Mode);
RaiseRelay = GetSwitchedOutputFromDevice(RaiseRelayConfig.DeviceKey);
LowerRelay = GetSwitchedOutputFromDevice(LowerRelayConfig.DeviceKey);
break;
}
{
this.LogDebug("Getting relays for {mode}", Mode);
RaiseRelay = GetSwitchedOutputFromDevice(RaiseRelayConfig.DeviceKey);
LowerRelay = GetSwitchedOutputFromDevice(LowerRelayConfig.DeviceKey);
break;
}
case eScreenLiftControlMode.latched:
{
this.LogDebug("Getting relays for {mode}", Mode);
LatchedRelay = GetSwitchedOutputFromDevice(LatchedRelayConfig.DeviceKey);
break;
}
{
this.LogDebug("Getting relays for {mode}", Mode);
LatchedRelay = GetSwitchedOutputFromDevice(LatchedRelayConfig.DeviceKey);
break;
}
}
this.LogDebug("Getting display with key {displayKey}", DisplayDeviceKey);
@@ -172,7 +210,8 @@ namespace PepperDash.Essentials.Devices.Common.Shades
this.LogDebug("Subscribing to {displayKey} feedbacks", DisplayDeviceKey);
DisplayDevice.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange;
DisplayDevice.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
DisplayDevice.IsCoolingDownFeedback.OutputChange +=
IsCoolingDownFeedback_OutputChange;
}
return base.CustomActivate();
@@ -183,10 +222,17 @@ namespace PepperDash.Essentials.Devices.Common.Shades
/// </summary>
public void Raise()
{
if (RaiseRelay == null && LatchedRelay == null) return;
if (RaiseRelay == null && LatchedRelay == null)
return;
this.LogDebug("Raise called for {type}", Type);
if (Config.MuteOnScreenUp && DisplayDevice is IBasicVideoMuteWithFeedback videoMute)
{
this.LogInformation("Muting video because screen is going up");
videoMute.VideoMuteOn();
}
// If device is moving, bank the command
if (_isMoving)
{
@@ -200,33 +246,33 @@ namespace PepperDash.Essentials.Devices.Common.Shades
switch (Mode)
{
case eScreenLiftControlMode.momentary:
{
PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs);
{
PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs);
// Set moving flag and start timer if movement time is configured
if (RaiseRelayConfig.MoveTimeInMs > 0)
{
_isMoving = true;
_currentMovement = RequestedState.Raise;
if (_movementTimer.Enabled)
{
_movementTimer.Stop();
}
_movementTimer.Interval = RaiseRelayConfig.MoveTimeInMs;
_movementTimer.Start();
}
else
{
InUpPosition = true;
}
break;
}
case eScreenLiftControlMode.latched:
// Set moving flag and start timer if movement time is configured
if (RaiseRelayConfig.MoveTimeInMs > 0)
{
LatchedRelay.Off();
InUpPosition = true;
break;
_isMoving = true;
_currentMovement = RequestedState.Raise;
if (_movementTimer.Enabled)
{
_movementTimer.Stop();
}
_movementTimer.Interval = RaiseRelayConfig.MoveTimeInMs;
_movementTimer.Start();
}
else
{
InUpPosition = true;
}
break;
}
case eScreenLiftControlMode.latched:
{
LatchedRelay.Off();
InUpPosition = true;
break;
}
}
}
@@ -235,7 +281,8 @@ namespace PepperDash.Essentials.Devices.Common.Shades
/// </summary>
public void Lower()
{
if (LowerRelay == null && LatchedRelay == null) return;
if (LowerRelay == null && LatchedRelay == null)
return;
this.LogDebug("Lower called for {type}", Type);
@@ -252,33 +299,33 @@ namespace PepperDash.Essentials.Devices.Common.Shades
switch (Mode)
{
case eScreenLiftControlMode.momentary:
{
PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs);
{
PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs);
// Set moving flag and start timer if movement time is configured
if (LowerRelayConfig.MoveTimeInMs > 0)
{
_isMoving = true;
_currentMovement = RequestedState.Lower;
if (_movementTimer.Enabled)
{
_movementTimer.Stop();
}
_movementTimer.Interval = LowerRelayConfig.MoveTimeInMs;
_movementTimer.Start();
}
else
{
InUpPosition = false;
}
break;
}
case eScreenLiftControlMode.latched:
// Set moving flag and start timer if movement time is configured
if (LowerRelayConfig.MoveTimeInMs > 0)
{
LatchedRelay.On();
InUpPosition = false;
break;
_isMoving = true;
_currentMovement = RequestedState.Lower;
if (_movementTimer.Enabled)
{
_movementTimer.Stop();
}
_movementTimer.Interval = LowerRelayConfig.MoveTimeInMs;
_movementTimer.Start();
}
else
{
InUpPosition = false;
}
break;
}
case eScreenLiftControlMode.latched:
{
LatchedRelay.On();
InUpPosition = false;
break;
}
}
}
@@ -339,16 +386,13 @@ namespace PepperDash.Essentials.Devices.Common.Shades
{
output.On();
var timer = new Timer(pulseTime)
{
AutoReset = false
};
var timer = new Timer(pulseTime) { AutoReset = false };
timer.Elapsed += (sender, e) =>
{
output.Off();
timer.Dispose();
};
{
output.Off();
timer.Dispose();
};
timer.Start();
}
@@ -361,7 +405,10 @@ namespace PepperDash.Essentials.Devices.Common.Shades
}
else
{
this.LogWarning("Error: Unable to get relay device with key '{relayKey}'", relayKey);
this.LogWarning(
"Error: Unable to get relay device with key '{relayKey}'",
relayKey
);
return null;
}
}
@@ -375,11 +422,13 @@ namespace PepperDash.Essentials.Devices.Common.Shades
}
else
{
this.LogWarning("Error: Unable to get display device with key '{displayKey}'", displayKey);
this.LogWarning(
"Error: Unable to get display device with key '{displayKey}'",
displayKey
);
return null;
}
}
}
/// <summary>
@@ -387,7 +436,7 @@ namespace PepperDash.Essentials.Devices.Common.Shades
/// </summary>
public class ScreenLiftControllerFactory : EssentialsDeviceFactory<RelayControlledShade>
{
/// <summary>
/// <summary>
/// Constructor for ScreenLiftControllerFactory
/// </summary>
public ScreenLiftControllerFactory()
@@ -404,4 +453,4 @@ namespace PepperDash.Essentials.Devices.Common.Shades
return new ScreenLiftController(dc.Key, dc.Name, props);
}
}
}
}

View File

@@ -5,37 +5,41 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials.Devices.Common.Shades
{
/// <summary>
/// Represents a ScreenLiftControllerConfigProperties
/// </summary>
public class ScreenLiftControllerConfigProperties
{
/// <summary>
/// Gets or sets the DisplayDeviceKey
/// Represents a ScreenLiftControllerConfigProperties
/// </summary>
[JsonProperty("displayDeviceKey")]
public string DisplayDeviceKey { get; set; }
public class ScreenLiftControllerConfigProperties
{
/// <summary>
/// Gets or sets the DisplayDeviceKey
/// </summary>
[JsonProperty("displayDeviceKey")]
public string DisplayDeviceKey { get; set; }
/// <summary>
/// Gets or sets the Type
/// </summary>
[JsonProperty("type")]
[JsonConverter(typeof(StringEnumConverter))]
public eScreenLiftControlType Type { get; set; }
/// <summary>
/// Gets or sets the Type
/// </summary>
[JsonProperty("type")]
[JsonConverter(typeof(StringEnumConverter))]
public eScreenLiftControlType Type { get; set; }
/// <summary>
/// Gets or sets the Mode
/// </summary>
[JsonProperty("mode")]
[JsonConverter(typeof(StringEnumConverter))]
public eScreenLiftControlMode Mode { get; set; }
/// <summary>
/// Gets or sets the Mode
/// </summary>
[JsonProperty("mode")]
[JsonConverter(typeof(StringEnumConverter))]
public eScreenLiftControlMode Mode { get; set; }
/// <summary>
/// Gets or sets the Relays
/// </summary>
[JsonProperty("relays")]
public Dictionary<string, ScreenLiftRelaysConfig> Relays { get; set; }
/// <summary>
/// Gets or sets the Relays
/// </summary>
[JsonProperty("relays")]
public Dictionary<string, ScreenLiftRelaysConfig> Relays { get; set; }
}
}
/// <summary>
/// Mutes the display when the screen is in the up position
/// </summary>
[JsonProperty("muteOnScreenUp")]
public bool MuteOnScreenUp { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
@@ -549,10 +549,7 @@ namespace PepperDash.Essentials
var applicationDirectory = new DirectoryInfo(Global.ApplicationDirectoryPathPrefix);
Debug.LogMessage(LogEventLevel.Information, "Searching: {applicationDirectory:l} for embedded assets - {Destination}", applicationDirectory.FullName, Global.FilePathPrefix);
var zipFiles = applicationDirectory.GetFiles("*")
.Where(f => f.Name.StartsWith("assets", StringComparison.OrdinalIgnoreCase) &&
f.Extension.Equals(".zip", StringComparison.OrdinalIgnoreCase))
.ToArray();
var zipFiles = applicationDirectory.GetFiles("assets*.zip");
if (zipFiles.Length > 1)
{
@@ -600,10 +597,7 @@ namespace PepperDash.Essentials
File.Delete(file.FullName);
}
var htmlZipFiles = applicationDirectory.GetFiles("*")
.Where(f => f.Name.StartsWith("htmlassets", StringComparison.OrdinalIgnoreCase) &&
f.Extension.Equals(".zip", StringComparison.OrdinalIgnoreCase))
.ToArray();
var htmlZipFiles = applicationDirectory.GetFiles("htmlassets*.zip");
if (htmlZipFiles.Length > 1)
{
@@ -664,10 +658,7 @@ namespace PepperDash.Essentials
File.Delete(file.FullName);
}
var jsonFiles = applicationDirectory.GetFiles("*")
.Where(f => f.Name.IndexOf("configurationFile", StringComparison.OrdinalIgnoreCase) >= 0 &&
f.Extension.Equals(".json", StringComparison.OrdinalIgnoreCase))
.ToArray();
var jsonFiles = applicationDirectory.GetFiles("*configurationFile*.json");
if (jsonFiles.Length > 1)
{