From e03874a7a9e8ea78dfeb90a384342d2b8369a00d Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 29 Jul 2025 22:26:07 -0500 Subject: [PATCH 01/11] fix: add messenger and event to ICurrentSources --- .../Routing/ICurrentSources.cs | 16 ++++- .../Displays/DisplayBase.cs | 62 ++++++++++++----- .../Messengers/CurrentSourcesMessenger.cs | 68 +++++++++++++++++++ .../IHasCurrentSourceInfoMessenger.cs | 6 +- .../MobileControlSystemController.cs | 39 +++++++---- 5 files changed, 157 insertions(+), 34 deletions(-) create mode 100644 src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs diff --git a/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs b/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs index bef0fd95..a8940d08 100644 --- a/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs +++ b/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs @@ -1,5 +1,5 @@ +using System; using System.Collections.Generic; -using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Routing { @@ -25,5 +25,19 @@ namespace PepperDash.Essentials.Core.Routing /// Dictionary CurrentSourceKeys { get; } + /// + /// Event raised when the current sources change. + /// + event EventHandler CurrentSourcesChanged; + + /// + /// Sets the current source for a specific signal type. + /// This method updates the current source for the specified signal type and notifies any subscribers of the change. + /// + /// The signal type to update. + /// The key for the source list. + /// The source list item to set as the current source. + void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem); + } } diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 786fc00d..27a3e0e0 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -52,9 +52,9 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// public event SourceInfoChangeHandler CurrentSourceChange; - /// - /// Gets or sets the CurrentSourceInfoKey - /// + /// + /// Gets or sets the CurrentSourceInfoKey + /// public string CurrentSourceInfoKey { get; set; } /// @@ -89,29 +89,32 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// public Dictionary CurrentSourceKeys { get; private set; } + /// + public event EventHandler CurrentSourcesChanged; + /// /// Gets feedback indicating whether the display is currently cooling down after being powered off. /// public BoolFeedback IsCoolingDownFeedback { get; protected set; } - /// - /// Gets or sets the IsWarmingUpFeedback - /// + /// + /// Gets or sets the IsWarmingUpFeedback + /// public BoolFeedback IsWarmingUpFeedback { get; private set; } - /// - /// Gets or sets the UsageTracker - /// + /// + /// Gets or sets the UsageTracker + /// public UsageTracking UsageTracker { get; set; } - /// - /// Gets or sets the WarmupTime - /// + /// + /// Gets or sets the WarmupTime + /// public uint WarmupTime { get; set; } - /// - /// Gets or sets the CooldownTime - /// + /// + /// Gets or sets the CooldownTime + /// public uint CooldownTime { get; set; } /// @@ -189,7 +192,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// /// Gets the collection of feedback objects for this display device. /// - /// + /// public virtual FeedbackCollection Feedbacks { get @@ -378,6 +381,33 @@ namespace PepperDash.Essentials.Devices.Common.Displays volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]); } + /// + public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) + { + // Update the current source for the specified signal type + if (CurrentSources.ContainsKey(signalType)) + { + CurrentSources[signalType] = sourceListItem; + } + else + { + CurrentSources.Add(signalType, sourceListItem); + } + + // Update the current source key for the specified signal type + if (CurrentSourceKeys.ContainsKey(signalType)) + { + CurrentSourceKeys[signalType] = sourceListKey; + } + else + { + CurrentSourceKeys.Add(signalType, sourceListKey); + } + + // Raise the CurrentSourcesChanged event + CurrentSourcesChanged?.Invoke(this, EventArgs.Empty); + } + } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs new file mode 100644 index 00000000..01763b59 --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Routing; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Represents a IHasCurrentSourceInfoMessenger + /// + public class CurrentSourcesMessenger : MessengerBase + { + private readonly ICurrentSources sourceDevice; + public CurrentSourcesMessenger(string key, string messagePath, ICurrentSources device) : base(key, messagePath, device as IKeyName) + { + sourceDevice = device; + } + + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, content) => + { + var message = new CurrentSourcesStateMessage + { + CurrentSourceKeys = sourceDevice.CurrentSourceKeys, + CurrentSources = sourceDevice.CurrentSources + }; + + PostStatusMessage(message); + }); + + sourceDevice.CurrentSourcesChanged += (sender, e) => + { + PostStatusMessage(JToken.FromObject(new + { + currentSourceKeys = sourceDevice.CurrentSourceKeys, + currentSources = sourceDevice.CurrentSources + })); + }; + } + } + + /// + /// Represents a CurrentSourcesStateMessage + /// + public class CurrentSourcesStateMessage : DeviceStateMessageBase + { + + /// + /// Gets or sets the CurrentSourceKey + /// + [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public Dictionary CurrentSourceKeys { get; set; } + + + /// + /// Gets or sets the CurrentSource + /// + [JsonProperty("currentSource")] + public Dictionary CurrentSources { get; set; } + } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs index 12a6bfec..04130776 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs @@ -54,16 +54,18 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class CurrentSourceStateMessage : DeviceStateMessageBase { - [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the CurrentSourceKey /// + [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string CurrentSourceKey { get; set; } - [JsonProperty("currentSource")] + /// /// Gets or sets the CurrentSource /// + [JsonProperty("currentSource")] public SourceListItem CurrentSource { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs index fea28e01..3c853c01 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs @@ -1,4 +1,10 @@ -using Crestron.SimplSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.WebScripting; @@ -30,12 +36,6 @@ using PepperDash.Essentials.RoomBridges; using PepperDash.Essentials.Services; using PepperDash.Essentials.WebApiHandlers; using PepperDash.Essentials.WebSocketServer; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using WebSocketSharp; namespace PepperDash.Essentials @@ -582,7 +582,7 @@ namespace PepperDash.Essentials { this.LogVerbose( "Adding ISetTopBoxControlMessenger for {deviceKey}" - ); + ); var messenger = new ISetTopBoxControlsMessenger( $"{device.Key}-stb-{Key}", @@ -599,7 +599,7 @@ namespace PepperDash.Essentials { this.LogVerbose( "Adding IChannelMessenger for {deviceKey}", device.Key - ); + ); var messenger = new IChannelMessenger( $"{device.Key}-channel-{Key}", @@ -614,7 +614,7 @@ namespace PepperDash.Essentials if (device is IColor colorDevice) { - this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key); + this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key); var messenger = new IColorMessenger( $"{device.Key}-color-{Key}", @@ -629,7 +629,7 @@ namespace PepperDash.Essentials if (device is IDPad dPadDevice) { - this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key); + this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key); var messenger = new IDPadMessenger( $"{device.Key}-dPad-{Key}", @@ -644,7 +644,7 @@ namespace PepperDash.Essentials if (device is INumericKeypad nkDevice) { - this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key); + this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key); var messenger = new INumericKeypadMessenger( $"{device.Key}-numericKeypad-{Key}", @@ -659,7 +659,7 @@ namespace PepperDash.Essentials if (device is IHasPowerControl pcDevice) { - this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key); + this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key); var messenger = new IHasPowerMessenger( $"{device.Key}-powerControl-{Key}", @@ -693,7 +693,7 @@ namespace PepperDash.Essentials { this.LogVerbose( "Adding ITransportMessenger for {deviceKey}", device.Key - ); + ); var messenger = new ITransportMessenger( $"{device.Key}-transport-{Key}", @@ -721,6 +721,15 @@ namespace PepperDash.Essentials messengerAdded = true; } + if (device is ICurrentSources currentSources) + { + this.LogVerbose("Adding CurrentSourcesMessenger for {deviceKey}", device.Key); + + var messenger = new CurrentSourcesMessenger($"{device.Key}-currentSources-{Key}", $"/device/{device.Key}", currentSources); + + AddDefaultDeviceMessenger(messenger); + } + if (device is ISwitchedOutput switchedDevice) { this.LogVerbose( @@ -2309,7 +2318,7 @@ Mobile Control Direct Server Infromation: { this.LogInformation("-- Warning: Incoming message has no registered handler {type}", message.Type); break; - } + } foreach (var handler in handlers) { From fd1ba345aa2ac9fd22debaba574f1c3409a568d2 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 29 Jul 2025 23:01:13 -0500 Subject: [PATCH 02/11] fix: remove StringEnumConverter --- .../Messengers/CurrentSourcesMessenger.cs | 11 ++++++++++- .../MobileControlSystemController.cs | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs index 01763b59..8badfdf6 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs @@ -14,11 +14,21 @@ namespace PepperDash.Essentials.AppServer.Messengers public class CurrentSourcesMessenger : MessengerBase { private readonly ICurrentSources sourceDevice; + + /// + /// Initializes a new instance of the class. + /// + /// The key. + /// The message path. + /// The device. public CurrentSourcesMessenger(string key, string messagePath, ICurrentSources device) : base(key, messagePath, device as IKeyName) { sourceDevice = device; } + /// + /// Registers the actions for the messenger. + /// protected override void RegisterActions() { base.RegisterActions(); @@ -55,7 +65,6 @@ namespace PepperDash.Essentials.AppServer.Messengers /// Gets or sets the CurrentSourceKey /// [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] public Dictionary CurrentSourceKeys { get; set; } diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs index 3c853c01..da6349db 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs @@ -728,6 +728,8 @@ namespace PepperDash.Essentials var messenger = new CurrentSourcesMessenger($"{device.Key}-currentSources-{Key}", $"/device/{device.Key}", currentSources); AddDefaultDeviceMessenger(messenger); + + messengerAdded = true; } if (device is ISwitchedOutput switchedDevice) From a0314247521fd0dc2ac61d43cb10c77c37e96333 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 30 Jul 2025 11:20:54 -0500 Subject: [PATCH 03/11] fix: add destination & source keys to routelist --- src/Directory.Build.props | 2 +- .../Devices/SourceListItem.cs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 152c9f18..f65b37a0 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 2.4.0-local + 2.12.0-local $(Version) PepperDash Technology PepperDash Technology diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index d171b3d9..e6724760 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -244,6 +244,20 @@ namespace PepperDash.Essentials.Core /// [JsonProperty("type")] public eRoutingSignalType Type { get; set; } + + /// + /// Key for a destination list item. If BOTH SourceListItemKey AND DestinationListItemKey are defined, + /// then the direct route method should be used. + /// + [JsonProperty("destinationListItemKey", NullValueHandling = NullValueHandling.Ignore)] + public string DestinationListItemKey { get; set; } + + /// + /// Key for a source list item. If BOTH SourceListItemKey AND DestinationListItemKey are defined, + /// then the direct route method should be used. + /// + [JsonProperty("sourceListItemKey", NullValueHandling = NullValueHandling.Ignore)] + public string SourceListItemKey { get; set; } } /// From ce886aea632ae3885b5aa74ba3288cce020187f5 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 1 Aug 2025 09:21:18 -0500 Subject: [PATCH 04/11] chore: update local build version --- src/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index f65b37a0..b47efdc9 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 2.12.0-local + 2.12.1-local $(Version) PepperDash Technology PepperDash Technology From 27bf36c58c11f4c6cdf8ce65513e6c67f9c64047 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 1 Aug 2025 09:22:22 -0500 Subject: [PATCH 05/11] fix: modify how current sources dictionary gets updated --- .../Factory/DeviceFactory.cs | 5 +- .../Routing/TieLineConfig.cs | 88 +++++++++---------- .../Displays/DisplayBase.cs | 28 +++++- 3 files changed, 70 insertions(+), 51 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs index b723f6c9..ae18d9fb 100644 --- a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs @@ -135,7 +135,7 @@ namespace PepperDash.Essentials.Core { if (FactoryMethods.ContainsKey(typeName)) { - Debug.LogInformation("Unable to add type: '{typeName}'. Already exists in DeviceFactory", typeName); + Debug.LogInformation("Unable to add type: '{typeName}'. Already exists in DeviceFactory", typeName); return; } @@ -217,7 +217,8 @@ namespace PepperDash.Essentials.Core } catch (Exception ex) { - Debug.LogError(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message); + Debug.LogError(ex, "Exception occurred while creating device {key}: {message}", dc.Key, ex.Message); + Debug.LogDebug(ex, "Exception details: {stackTrace}", ex.StackTrace); return null; } } diff --git a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs index 8143c1f5..156b39b1 100644 --- a/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs +++ b/src/PepperDash.Essentials.Core/Routing/TieLineConfig.cs @@ -22,38 +22,38 @@ namespace PepperDash.Essentials.Core.Config /// The key of the source device. /// public string SourceKey { get; set; } - - /// - /// The key of the source card (if applicable, e.g., in a modular chassis). - /// + + /// + /// The key of the source card (if applicable, e.g., in a modular chassis). + /// public string SourceCard { get; set; } - - /// - /// The key of the source output port, used for routing configurations. - /// + + /// + /// The key of the source output port, used for routing configurations. + /// public string SourcePort { get; set; } - - /// - /// Gets or sets the DestinationKey - /// + + /// + /// Gets or sets the DestinationKey + /// public string DestinationKey { get; set; } - - /// - /// Gets or sets the DestinationCard - /// + + /// + /// Gets or sets the DestinationCard + /// public string DestinationCard { get; set; } - - /// - /// Gets or sets the DestinationPort - /// + + /// + /// Gets or sets the DestinationPort + /// public string DestinationPort { get; set; } - /// - /// Optional override for the signal type of the tie line. If set, this overrides the destination port's type for routing calculations. - /// - [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] - public eRoutingSignalType? OverrideType { get; set; } + /// + /// Optional override for the signal type of the tie line. If set, this overrides the destination port's type for routing calculations. + /// + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] + public eRoutingSignalType? OverrideType { get; set; } /// /// Returns the appropriate tie line for either a card-based device or @@ -62,40 +62,39 @@ namespace PepperDash.Essentials.Core.Config /// null if config data does not match ports, cards or devices public TieLine GetTieLine() { - Debug.LogMessage(LogEventLevel.Information, "Build TieLine: {0}",null, this); + Debug.LogInformation("Build TieLine: {config}", ToString()); + // Get the source device - var sourceDev = DeviceManager.GetDeviceForKey(SourceKey) as IRoutingOutputs; - if (sourceDev == null) + if (!(DeviceManager.GetDeviceForKey(SourceKey) is IRoutingOutputs sourceDev)) { LogError("Routable source not found"); return null; } // Get the destination device - var destDev = DeviceManager.GetDeviceForKey(DestinationKey) as IRoutingInputs; - if (destDev == null) + if (!(DeviceManager.GetDeviceForKey(DestinationKey) is IRoutingInputs destDev)) { LogError("Routable destination not found"); return null; } - //Get the source port - var sourceOutputPort = sourceDev.OutputPorts[SourcePort]; + //Get the source port + var sourceOutputPort = sourceDev.OutputPorts[SourcePort]; - if (sourceOutputPort == null) + if (sourceOutputPort == null) { LogError("Source does not contain port"); return null; } - //Get the Destination port - var destinationInputPort = destDev.InputPorts[DestinationPort]; + //Get the Destination port + var destinationInputPort = destDev.InputPorts[DestinationPort]; - if (destinationInputPort == null) - { - LogError("Destination does not contain port"); - return null; - } + if (destinationInputPort == null) + { + LogError("Destination does not contain port"); + return null; + } return new TieLine(sourceOutputPort, destinationInputPort, OverrideType); } @@ -104,9 +103,9 @@ namespace PepperDash.Essentials.Core.Config /// Logs an error message related to creating this tie line configuration. /// /// The specific error message. - void LogError(string msg) + private void LogError(string msg) { - Debug.LogMessage(LogEventLevel.Error, "WARNING: Cannot create tie line: {message}:\r {tieLineConfig}",null, msg, this); + Debug.LogError("Cannot create tie line: {message}", msg); } /// @@ -115,8 +114,7 @@ namespace PepperDash.Essentials.Core.Config /// A string describing the source and destination of the configured tie line. public override string ToString() { - return string.Format("{0}.{1}.{2} --> {3}.{4}.{5}", SourceKey, SourceCard, SourcePort, - DestinationKey, DestinationCard, DestinationPort); + return $"{SourceKey}.{SourceCard}.{SourcePort} --> {DestinationKey}.{DestinationCard}.{DestinationPort}"; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 27a3e0e0..7a6fa874 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; +using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.DeviceTypeInterfaces; @@ -384,7 +386,28 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) { - // Update the current source for the specified signal type + foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType))) + { + var flagValue = Convert.ToInt32(type); + if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0) + { + this.LogDebug("Skipping {type}", type); + continue; + } + + this.LogDebug("setting {type}", type); + + if (signalType.HasFlag(type)) + { + UpdateCurrentSources(type, sourceListKey, sourceListItem); + } + } + // Raise the CurrentSourcesChanged event + CurrentSourcesChanged?.Invoke(this, EventArgs.Empty); + } + + private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem) + { if (CurrentSources.ContainsKey(signalType)) { CurrentSources[signalType] = sourceListItem; @@ -403,9 +426,6 @@ namespace PepperDash.Essentials.Devices.Common.Displays { CurrentSourceKeys.Add(signalType, sourceListKey); } - - // Raise the CurrentSourcesChanged event - CurrentSourcesChanged?.Invoke(this, EventArgs.Empty); } } From 5bb0ab2626c314e54d42dd4978f819dd7761ab52 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 1 Aug 2025 21:17:35 -0500 Subject: [PATCH 06/11] fix: base config properties for use with streaming devices --- .../Config/BaseStreamingDeviceProperties.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/PepperDash.Essentials.Core/Config/BaseStreamingDeviceProperties.cs diff --git a/src/PepperDash.Essentials.Core/Config/BaseStreamingDeviceProperties.cs b/src/PepperDash.Essentials.Core/Config/BaseStreamingDeviceProperties.cs new file mode 100644 index 00000000..fe77b6af --- /dev/null +++ b/src/PepperDash.Essentials.Core/Config/BaseStreamingDeviceProperties.cs @@ -0,0 +1,23 @@ +using System; +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core.Config +{ + /// + /// Represents the base properties for a streaming device. + /// + public class BaseStreamingDeviceProperties + { + /// + /// The multicast video address for the streaming device. + /// + [JsonProperty("multicastVideoAddress", NullValueHandling = NullValueHandling.Ignore)] + public string MulticastVideoAddress { get; set; } + + /// + /// The multicast audio address for the streaming device. + /// + [JsonProperty("multicastAudioAddress", NullValueHandling = NullValueHandling.Ignore)] + public string MulticastAudioAddress { get; set; } + } +} From cf3ece423780a08eb4f5ef40a3c8f56fdf824aba Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 6 Aug 2025 09:00:45 -0500 Subject: [PATCH 07/11] fix: use cr-lf for line endings --- src/PepperDash.Core/Logging/Debug.cs | 14 ++--- .../Devices/DeviceManager.cs | 6 +- .../Factory/DeviceFactory.cs | 6 +- .../MobileControlSystemController.cs | 60 ++++++++----------- 4 files changed, 38 insertions(+), 48 deletions(-) diff --git a/src/PepperDash.Core/Logging/Debug.cs b/src/PepperDash.Core/Logging/Debug.cs index 4e248807..ccedc750 100644 --- a/src/PepperDash.Core/Logging/Debug.cs +++ b/src/PepperDash.Core/Logging/Debug.cs @@ -349,13 +349,13 @@ namespace PepperDash.Core if (levelString.Trim() == "?") { CrestronConsole.ConsoleCommandResponse( - $@"Used to set the minimum level of debug messages to be printed to the console: -{_logLevels[0]} = 0 -{_logLevels[1]} = 1 -{_logLevels[2]} = 2 -{_logLevels[3]} = 3 -{_logLevels[4]} = 4 -{_logLevels[5]} = 5"); + "Used to set the minimum level of debug messages to be printed to the console:\r\n" + + $"{_logLevels[0]} = 0\r\n" + + $"{_logLevels[1]} = 1\r\n" + + $"{_logLevels[2]} = 2\r\n" + + $"{_logLevels[3]} = 3\r\n" + + $"{_logLevels[4]} = 4\r\n" + + $"{_logLevels[5]} = 5"); return; } diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs b/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs index 7572835e..016464cd 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs @@ -475,9 +475,9 @@ namespace PepperDash.Essentials.Core if (String.IsNullOrEmpty(s) || s.Contains("?")) { CrestronConsole.ConsoleCommandResponse( - @"SETDEVICESTREAMDEBUG [{deviceKey}] [OFF |TX | RX | BOTH] [timeOutInMinutes] - {deviceKey} [OFF | TX | RX | BOTH] - Device to set stream debugging on, and which setting to use - timeOutInMinutes - Set timeout for stream debugging. Default is 30 minutes"); + "SETDEVICESTREAMDEBUG [{deviceKey}] [OFF |TX | RX | BOTH] [timeOutInMinutes]\r\n" + + " {deviceKey} [OFF | TX | RX | BOTH] - Device to set stream debugging on, and which setting to use\r\n" + + " timeOutInMinutes - Set timeout for stream debugging. Default is 30 minutes"); return; } diff --git a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs index ae18d9fb..b02daf4e 100644 --- a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs @@ -250,9 +250,9 @@ namespace PepperDash.Essentials.Core } CrestronConsole.ConsoleCommandResponse( - @"Type: '{0}' - Type: '{1}' - Description: {2}{3}", type.Key, Type, description, CrestronEnvironment.NewLine); + "Type: '{0}'\r\n" + + " Type: '{1}'\r\n" + + " Description: {2}{3}", type.Key, Type, description, CrestronEnvironment.NewLine); } } diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs index da6349db..f5854516 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs @@ -1636,15 +1636,14 @@ namespace PepperDash.Essentials if (Config.EnableApiServer) { CrestronConsole.ConsoleCommandResponse( - @"Mobile Control Edge Server API Information: - - Server address: {0} - System Name: {1} - System URL: {2} - System UUID: {3} - System User code: {4} - Connected?: {5} - Seconds Since Last Ack: {6}", + "Mobile Control Edge Server API Information:\r\n\r\n" + + "\tServer address: {0}\r\n" + + "\tSystem Name: {1}\r\n" + + "\tSystem URL: {2}\r\n" + + "\tSystem UUID: {3}\r\n" + + "\tSystem User code: {4}\r\n" + + "\tConnected?: {5}\r\n" + + "\tSeconds Since Last Ack: {6}\r\n", url, name, ConfigReader.ConfigObject.SystemUrl, @@ -1657,10 +1656,8 @@ namespace PepperDash.Essentials else { CrestronConsole.ConsoleCommandResponse( - @" -Mobile Control Edge Server API Information: - Not Enabled in Config. -" + "\r\nMobile Control Edge Server API Information:\r\n" + + " Not Enabled in Config.\r\n" ); } @@ -1671,21 +1668,17 @@ Mobile Control Edge Server API Information: ) { CrestronConsole.ConsoleCommandResponse( - @" -Mobile Control Direct Server Information: - User App URL: {0} - Server port: {1} -", + "\r\nMobile Control Direct Server Information:\r\n" + + " User App URL: {0}\r\n" + + " Server port: {1}\r\n", string.Format("{0}[insert_client_token]", _directServer.UserAppUrlPrefix), _directServer.Port ); CrestronConsole.ConsoleCommandResponse( - @" - UI Client Info: - Tokens Defined: {0} - Clients Connected: {1} -", + "\r\n UI Client Info:\r\n" + + " Tokens Defined: {0}\r\n" + + " Clients Connected: {1}\r\n", _directServer.UiClients.Count, _directServer.ConnectedUiClientsCount ); @@ -1703,15 +1696,13 @@ Mobile Control Direct Server Information: } CrestronConsole.ConsoleCommandResponse( - @" -Client {0}: -Room Key: {1} -Touchpanel Key: {6} -Token: {2} -Client URL: {3} -Connected: {4} -Duration: {5} -", + "\r\nClient {0}:\r\n" + + "Room Key: {1}\r\n" + + "Touchpanel Key: {6}\r\n" + + "Token: {2}\r\n" + + "Client URL: {3}\r\n" + + "Connected: {4}\r\n" + + "Duration: {5}\r\n", clientNo, clientContext.Value.Token.RoomKey, clientContext.Key, @@ -1726,9 +1717,8 @@ Duration: {5} else { CrestronConsole.ConsoleCommandResponse( - @" -Mobile Control Direct Server Infromation: - Not Enabled in Config." + "\r\nMobile Control Direct Server Information:\r\n" + + " Not Enabled in Config.\r\n" ); } } From 47017da527cb3d5fcedd7c25422fa6c1aac488a4 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 11 Aug 2025 17:47:14 -0500 Subject: [PATCH 08/11] fix: use correct property names --- .../Messengers/CurrentSourcesMessenger.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs index 8badfdf6..5b220256 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs @@ -64,14 +64,14 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Gets or sets the CurrentSourceKey /// - [JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)] + [JsonProperty("currentSourceKeys", NullValueHandling = NullValueHandling.Ignore)] public Dictionary CurrentSourceKeys { get; set; } /// /// Gets or sets the CurrentSource /// - [JsonProperty("currentSource")] + [JsonProperty("currentSources")] public Dictionary CurrentSources { get; set; } } } From ab4e85d081fe691ff94ace271bf1f43cecd240ef Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 11 Aug 2025 17:48:46 -0500 Subject: [PATCH 09/11] fix: use different methods for extensions The logging extension methods now use the appropriate methods from the debug class. Previously some messages were not getting handled correctly, and it was causing issues with log statements. --- .../Logging/DebugExtensions.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/PepperDash.Core/Logging/DebugExtensions.cs b/src/PepperDash.Core/Logging/DebugExtensions.cs index c5174541..ccee4943 100644 --- a/src/PepperDash.Core/Logging/DebugExtensions.cs +++ b/src/PepperDash.Core/Logging/DebugExtensions.cs @@ -1,5 +1,5 @@ -using Serilog.Events; -using System; +using System; +using Serilog.Events; using Log = PepperDash.Core.Debug; namespace PepperDash.Core.Logging @@ -11,7 +11,7 @@ namespace PepperDash.Core.Logging /// public static void LogException(this IKeyed device, Exception ex, string message, params object[] args) { - Log.LogMessage(ex, message, device, args); + Log.LogMessage(ex, message, device: device, args); } /// @@ -19,7 +19,7 @@ namespace PepperDash.Core.Logging /// public static void LogVerbose(this IKeyed device, Exception ex, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Verbose, ex, message, device, args); + Log.LogVerbose(ex, device, message, args); } /// @@ -27,7 +27,7 @@ namespace PepperDash.Core.Logging /// public static void LogVerbose(this IKeyed device, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Verbose, device, message, args); + Log.LogVerbose(device, message, args); } /// @@ -35,7 +35,7 @@ namespace PepperDash.Core.Logging /// public static void LogDebug(this IKeyed device, Exception ex, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Debug, ex, message, device, args); + Log.LogDebug(ex, device, message, args); } /// @@ -43,7 +43,7 @@ namespace PepperDash.Core.Logging /// public static void LogDebug(this IKeyed device, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Debug, device, message, args); + Log.LogDebug(device, message, args); } /// @@ -51,7 +51,7 @@ namespace PepperDash.Core.Logging /// public static void LogInformation(this IKeyed device, Exception ex, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Information, ex, message, device, args); + Log.LogInformation(ex, device, message, args); } /// @@ -59,7 +59,7 @@ namespace PepperDash.Core.Logging /// public static void LogInformation(this IKeyed device, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Information, device, message, args); + Log.LogInformation(device, message, args); } /// @@ -67,7 +67,7 @@ namespace PepperDash.Core.Logging /// public static void LogWarning(this IKeyed device, Exception ex, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Warning, ex, message, device, args); + Log.LogWarning(ex, device, message, args); } /// @@ -75,7 +75,7 @@ namespace PepperDash.Core.Logging /// public static void LogWarning(this IKeyed device, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Warning, device, message, args); + Log.LogWarning(device, message, args); } /// @@ -83,7 +83,7 @@ namespace PepperDash.Core.Logging /// public static void LogError(this IKeyed device, Exception ex, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Error, ex, message, device, args); + Log.LogError(ex, device, message, args); } /// @@ -91,7 +91,7 @@ namespace PepperDash.Core.Logging /// public static void LogError(this IKeyed device, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Error, device, message, args); + Log.LogError(device, message, args); } /// @@ -99,7 +99,7 @@ namespace PepperDash.Core.Logging /// public static void LogFatal(this IKeyed device, Exception ex, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Fatal, ex, message, device, args); + Log.LogFatal(ex, device, message, args); } /// @@ -107,7 +107,7 @@ namespace PepperDash.Core.Logging /// public static void LogFatal(this IKeyed device, string message, params object[] args) { - Log.LogMessage(LogEventLevel.Fatal, device, message, args); + Log.LogFatal(device, message, args); } } } From f2d0dca7b896909114daf0005dddbe051068cb95 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 11 Aug 2025 17:50:50 -0500 Subject: [PATCH 10/11] fix: make appdebug case-insensitive when commands like `appdebug verbose` are used rather than `appdebug 2`, the command would fail because Verbose != verbose. The enum conversion is now case-insensitive. --- src/PepperDash.Core/Logging/Debug.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PepperDash.Core/Logging/Debug.cs b/src/PepperDash.Core/Logging/Debug.cs index ccedc750..37b0f14a 100644 --- a/src/PepperDash.Core/Logging/Debug.cs +++ b/src/PepperDash.Core/Logging/Debug.cs @@ -376,7 +376,7 @@ namespace PepperDash.Core return; } - if (Enum.TryParse(levelString, out var levelEnum)) + if (Enum.TryParse(levelString, true, out var levelEnum)) { SetDebugLevel(levelEnum); return; From a0fc731701add92409b4d022a7f2455d2207a7d8 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 11 Aug 2025 17:55:02 -0500 Subject: [PATCH 11/11] chore: apply copilot suggestions Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Displays/DisplayBase.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index 7a6fa874..c94591a3 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.InteropServices; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; @@ -389,6 +388,8 @@ namespace PepperDash.Essentials.Devices.Common.Displays foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType))) { var flagValue = Convert.ToInt32(type); + // Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag). + // (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set. if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0) { this.LogDebug("Skipping {type}", type);