From 2fa297a204f095411de5a4c8eced844d94ad4e66 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 26 Jun 2025 10:10:09 -0600 Subject: [PATCH 01/22] feat: Update .gitignore and enhance routing-related classes - Updated `.gitignore` to include additional files and directories. - Added summary comments and new properties in `LevelControlListItem.cs` for better clarity and functionality. - Enhanced documentation in `SourceListItem.cs` and introduced new properties, including `Destinations` and a `ToString` method. - Introduced `SourceRouteListItem` class with routing properties and expanded `eSourceListItemDestinationTypes` enum. - Added `IRoutingSinkWithInputPort` interface in `IRoutingSink.cs` to support input port functionality. --- .gitignore | 3 +- .../Devices/LevelControlListItem.cs | 35 +++++- .../Devices/SourceListItem.cs | 114 +++++++++++++++++- .../Routing/IRoutingSink.cs | 6 + 4 files changed, 154 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c5e1142f..bd60ff8d 100644 --- a/.gitignore +++ b/.gitignore @@ -393,4 +393,5 @@ essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/Pepp /._PepperDash.Essentials.sln .vscode/settings.json _site/ -api/ \ No newline at end of file +api/ +*.DS_Store diff --git a/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs b/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs index 4c2e83e4..821a0c2b 100644 --- a/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/LevelControlListItem.cs @@ -9,10 +9,15 @@ using PepperDash.Essentials.Core.Devices; namespace PepperDash.Essentials.Core { + /// + /// Represents a level control item in a list, which can be used to control volume or mute functionality. + /// public class LevelControlListItem : AudioControlListItemBase { - + /// + /// A reference to the IBasicVolumeWithFeedback device for control. + /// [JsonIgnore] public IBasicVolumeWithFeedback LevelControl { @@ -55,7 +60,7 @@ namespace PepperDash.Essentials.Core { get { - if(string.IsNullOrEmpty(ItemKey)) return ParentDeviceKey; + if (string.IsNullOrEmpty(ItemKey)) return ParentDeviceKey; else { return DeviceManager.AllDevices. @@ -70,13 +75,39 @@ namespace PepperDash.Essentials.Core [JsonProperty("type")] [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public eLevelControlType Type { get; set; } + + + /// + /// Indicates if the item is a mic or not. + /// + [JsonProperty("isMic", NullValueHandling = NullValueHandling.Ignore)] + public bool? IsMic { get; set; } + + /// + /// Indicates if the item should show the raw level in the UI. + /// + [JsonProperty("showRawLevel", NullValueHandling = NullValueHandling.Ignore)] + public bool? ShowRawLevel { get; set; } } + /// + /// Indicates the type of level control item. + /// [Flags] public enum eLevelControlType { + /// + /// Indicates that the item is a level control only + /// Level = 1, + /// + /// Indicates that the item is a mute control only + /// Mute = 2, + /// + /// Indicates that the item is both a level and mute control + /// LevelAndMute = Level | Mute, } + } diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index 6de2f35d..ae223005 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -10,7 +10,18 @@ namespace PepperDash.Essentials.Core /// public enum eSourceListItemType { - Route, Off, Other, SomethingAwesomerThanThese + /// + /// Represents a typical route. + /// + Route, + /// + /// Represents an off route. + /// + Off, + /// + /// Represents some other type of route + /// + Other, } /// @@ -18,6 +29,9 @@ namespace PepperDash.Essentials.Core /// public class SourceListItem { + /// + /// The key of the source item, which is used to identify it in the DeviceManager + /// [JsonProperty("sourceKey")] public string SourceKey { get; set; } @@ -117,6 +131,9 @@ namespace PepperDash.Essentials.Core [JsonProperty("disableRoutedSharing")] public bool DisableRoutedSharing { get; set; } + /// + /// + /// [JsonProperty("destinations")] public List Destinations { get; set; } /// @@ -149,31 +166,56 @@ namespace PepperDash.Essentials.Core [JsonProperty("disableSimpleRouting")] public bool DisableSimpleRouting { get; set; } + /// + /// Default constructor for SourceListItem, initializes the Icon to "Blank" + /// public SourceListItem() { Icon = "Blank"; } + /// + /// Returns a string representation of the SourceListItem, including the SourceKey and Name + /// + /// public override string ToString() { return $"{SourceKey}:{Name}"; } } + /// + /// Represents a route in a source list item, which defines the source and destination keys and the type of signal being routed + /// public class SourceRouteListItem { + /// + /// The key of the source device to route from + /// [JsonProperty("sourceKey")] public string SourceKey { get; set; } + /// + /// The key of the source port to route from + /// [JsonProperty("sourcePortKey")] public string SourcePortKey { get; set; } + /// + /// The key of the destination device to route to + /// [JsonProperty("destinationKey")] public string DestinationKey { get; set; } + /// + /// The key of the destination port to route to + /// [JsonProperty("destinationPortKey")] public string DestinationPortKey { get; set; } + /// + /// The type of signal being routed, such as audio or video + /// [JsonProperty("type")] public eRoutingSignalType Type { get; set; } } @@ -183,15 +225,85 @@ namespace PepperDash.Essentials.Core /// public enum eSourceListItemDestinationTypes { + /// + /// Default display, used for the main video output in a room + /// defaultDisplay, + /// + /// Left display + /// leftDisplay, + /// + /// Right display + /// rightDisplay, + /// + /// Center display + /// centerDisplay, + /// + /// Program audio, used for the main audio output in a room + /// programAudio, + /// + /// Codec content, used for sharing content to the far end in a video call + /// codecContent, + /// + /// Front left display, used for rooms with multiple displays + /// frontLeftDisplay, + /// + /// Front right display, used for rooms with multiple displays + /// frontRightDisplay, + /// + /// Rear left display, used for rooms with multiple displays + /// rearLeftDisplay, + /// + /// Rear right display, used for rooms with multiple displays + /// rearRightDisplay, + /// + /// Auxiliary display 1, used for additional displays in a room + /// + auxDisplay1, + /// + /// Auxiliary display 2, used for additional displays in a room + /// + auxDisplay2, + /// + /// Auxiliary display 3, used for additional displays in a room + /// + auxDisplay3, + /// + /// Auxiliary display 4, used for additional displays in a room + /// + auxDisplay4, + /// + /// Auxiliary display 5, used for additional displays in a room + /// + auxDisplay5, + /// + /// Auxiliary display 6, used for additional displays in a room + /// + auxDisplay6, + /// + /// Auxiliary display 7, used for additional displays in a room + /// + auxDisplay7, + /// + /// Auxiliary display 8, used for additional displays in a room + /// + auxDisplay8, + /// + /// Auxiliary display 9, used for additional displays in a room + /// + auxDisplay9, + /// + /// Auxiliary display 10, used for additional displays in a room + /// + auxDisplay10, } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs index b05c7744..59bcd65b 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs @@ -7,8 +7,14 @@ { } + /// + /// For fixed-source endpoint devices with an input port + /// public interface IRoutingSinkWithInputPort :IRoutingSink { + /// + /// Gets the current input port for this routing sink. + /// RoutingInputPort CurrentInputPort { get; } } /*/// From 8f1fb86d37cd3b387172a51fff2c920351b167aa Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Jul 2025 09:49:01 -0500 Subject: [PATCH 02/22] fix: add NVX network port info interface --- .../INvxNetworkPortInformation.cs | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs new file mode 100644 index 00000000..3fcb7e26 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs @@ -0,0 +1,89 @@ +using Crestron.SimplSharpPro.DM.Streaming; +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.Core +{ + /// + /// Represents a collection of network port information and provides notifications when the information changes. + /// + /// This interface is designed to provide access to a list of network port details and to notify + /// subscribers when the port information is updated. Implementations of this interface should ensure that the event is raised whenever the collection + /// changes. + public interface INvxNetworkPortInformation + { + /// + /// Occurs when the port information changes. + /// + /// This event is triggered whenever there is a change in the port information, such as + /// updates to port settings or status. Subscribers can handle this event to respond to such changes. + event EventHandler PortInformationChanged; + + /// + /// Gets the collection of network port information associated with the current instance. + /// + /// The collection provides information about the network ports, such as their status, + /// configuration, or other relevant details. The returned list is read-only and cannot be modified + /// directly. + List NetworkPorts { get; } + } + + /// + /// Represents information about a network port, including its configuration and associated system details. + /// + /// This class provides properties to describe various attributes of a network port, such as its + /// name, description, VLAN configuration, and management IP address. It is typically used to store and retrieve + /// metadata about network ports in a managed environment. + public class NvxNetworkPortInformation + { + private readonly DmNvxBaseClass.DmNvx35xNetwork.DmNvxNetworkLldpPort port; + + /// + /// Gets or sets the index of the device port. + /// + public uint DevicePortIndex { get; } + + /// + /// Gets or sets the name of the port used for communication. + /// + public string PortName => port.PortNameFeedback.StringValue; + + /// + /// Gets or sets the description of the port. + /// + public string PortDescription => port.PortNameDescriptionFeedback.StringValue; + + /// + /// Gets or sets the name of the VLAN (Virtual Local Area Network). + /// + public string VlanName => port.VlanNameFeedback.StringValue; + + /// + /// Gets the IP management address associated with the port. + /// + public string IpManagementAddress => port.IpManagementAddressFeedback.StringValue; + + /// + /// Gets the name of the system as reported by the associated port. + /// + public string SystemName => port.SystemNameFeedback.StringValue; + + /// + /// Gets the description of the system name. + /// + public string SystemNameDescription => port.SystemNameDescriptionFeedback.StringValue; + + /// + /// Initializes a new instance of the class with the specified network port + /// and device port index. + /// + /// The network port associated with the device. Cannot be . + /// The index of the device port. + /// Thrown if is . + public NvxNetworkPortInformation(DmNvxBaseClass.DmNvx35xNetwork.DmNvxNetworkLldpPort port, uint devicePortIndex) + { + this.port = port ?? throw new ArgumentNullException(nameof(port), "Port cannot be null"); + DevicePortIndex = devicePortIndex; + } +} From 5e880f01116c466b1bbfef07339fd20bf6fd75a0 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Jul 2025 10:06:23 -0500 Subject: [PATCH 03/22] chore: add missing brace --- .../DeviceTypeInterfaces/INvxNetworkPortInformation.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs index 3fcb7e26..7894eca1 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs @@ -86,4 +86,5 @@ namespace PepperDash.Essentials.Core this.port = port ?? throw new ArgumentNullException(nameof(port), "Port cannot be null"); DevicePortIndex = devicePortIndex; } + } } From a076d531bc4200f40f9a736b09880099bb5b5376 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Jul 2025 10:17:08 -0500 Subject: [PATCH 04/22] chore: remove BOM Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../DeviceTypeInterfaces/INvxNetworkPortInformation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs index 7894eca1..549dd3f5 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs @@ -1,4 +1,4 @@ -using Crestron.SimplSharpPro.DM.Streaming; +using Crestron.SimplSharpPro.DM.Streaming; using System; using System.Collections.Generic; From 2b15c2a56f4ad7ad0916d92faeae071af10291dc Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Jul 2025 10:17:37 -0500 Subject: [PATCH 05/22] docs: remove extra space Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../DeviceTypeInterfaces/INvxNetworkPortInformation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs index 549dd3f5..c1592c94 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/INvxNetworkPortInformation.cs @@ -33,7 +33,7 @@ namespace PepperDash.Essentials.Core /// Represents information about a network port, including its configuration and associated system details. /// /// This class provides properties to describe various attributes of a network port, such as its - /// name, description, VLAN configuration, and management IP address. It is typically used to store and retrieve + /// name, description, VLAN configuration, and management IP address. It is typically used to store and retrieve /// metadata about network ports in a managed environment. public class NvxNetworkPortInformation { From 056614cba111396fa79477d650f5863a0d3751c8 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 9 Jul 2025 14:32:01 -0500 Subject: [PATCH 06/22] fix: add IMeterFeedback interface --- .vscode/extensions.json | 9 +++++++++ .../DeviceTypeInterfaces/IMeterFeedback.cs | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 .vscode/extensions.json create mode 100644 src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMeterFeedback.cs diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..48c5715a --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "ms-dotnettools.vscode-dotnet-runtime", + "ms-dotnettools.csharp", + "ms-dotnettools.csdevkit", + "vivaxy.vscode-conventional-commits", + "mhutchie.git-graph" + ] +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMeterFeedback.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMeterFeedback.cs new file mode 100644 index 00000000..a4b935a5 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMeterFeedback.cs @@ -0,0 +1,18 @@ +using System; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + + /// + /// Interface for devices that provide audio meter feedback. + /// This interface is used to standardize access to meter feedback across different devices. + /// + public interface IMeterFeedback + { + /// + /// Gets the meter feedback for the device. + /// This property provides an IntFeedback that represents the current audio level or meter value. + /// + IntFeedback MeterFeedback { get; } + } +} From 2a70fc678e0394eca70489abdf33672c5d934344 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 11 Jul 2025 13:13:52 -0500 Subject: [PATCH 07/22] fix: add IStateFeedback interface --- .../DeviceTypeInterfaces/IStateFeedback.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs new file mode 100644 index 00000000..e4070594 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs @@ -0,0 +1,18 @@ +using System; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + + /// + /// Interface for devices that provide audio meter feedback. + /// This interface is used to standardize access to meter feedback across different devices. + /// + public interface IStateFeedback + { + /// + /// Gets the state feedback for the device. + /// This property provides a BoolFeedback that represents the current state (on/off) of the device. + /// + BoolFeedback StateFeedback { get; } + } +} From ddbcc13c50613ad752588df42d8e49d540043a1d Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 16 Jul 2025 10:41:46 -0500 Subject: [PATCH 08/22] fix: add property for sync device association --- .../Devices/SourceListItem.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index ae223005..0c7f3cf0 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -1,12 +1,14 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; using PepperDash.Core; -using System.Collections.Generic; namespace PepperDash.Essentials.Core { /// - /// + /// Defines the type of source list item, which can be a route, off, or other. + /// This is used to categorize the source list items in a room. + /// The type is serialized to JSON and can be used to determine how the item should be displayed or handled in the UI. /// public enum eSourceListItemType { @@ -166,6 +168,12 @@ namespace PepperDash.Essentials.Core [JsonProperty("disableSimpleRouting")] public bool DisableSimpleRouting { get; set; } + /// + /// The key of the device that provides video sync for this source item + /// + [JsonProperty("syncProviderDeviceKey")] + public string SyncProviderDeviceKey { get; set; } + /// /// Default constructor for SourceListItem, initializes the Icon to "Blank" /// @@ -177,7 +185,7 @@ namespace PepperDash.Essentials.Core /// /// Returns a string representation of the SourceListItem, including the SourceKey and Name /// - /// + /// A string representation of the SourceListItem public override string ToString() { return $"{SourceKey}:{Name}"; From 9813673b663d465cf0420b19233f13180fd108af Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Jul 2025 09:15:25 -0500 Subject: [PATCH 09/22] feat: ICurrentSources interface to allow for tracking breakaway routing --- .../DeviceTypeInterfaces/IDisplay.cs | 9 +- .../Devices/SourceListItem.cs | 7 + .../Routing/ICurrentSources.cs | 28 ++ .../Routing/IHasCurrentSourceInfoChange.cs | 16 + .../Routing/IRoutingSink.cs | 22 +- .../Displays/DisplayBase.cs | 341 ++++++++++++------ 6 files changed, 309 insertions(+), 114 deletions(-) create mode 100644 src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs index 9b82cacd..af3428f6 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IDisplay.cs @@ -2,7 +2,14 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { - public interface IDisplay: IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking, IKeyName + /// + /// Interface for display devices that can be controlled and monitored. + /// This interface combines functionality for feedback, routing, power control, + /// warming/cooling, usage tracking, and key name management. + /// It is designed to be implemented by devices that require these capabilities, + /// such as projectors, displays, and other visual output devices. + /// + public interface IDisplay : IHasFeedback, IRoutingSinkWithSwitching, IHasPowerControl, IWarmingCooling, IUsageTracking, IKeyName { } } diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index 0c7f3cf0..bfba4b4c 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -174,6 +174,13 @@ namespace PepperDash.Essentials.Core [JsonProperty("syncProviderDeviceKey")] public string SyncProviderDeviceKey { get; set; } + /// + /// Indicates if the source supports USB connections + /// + [JsonProperty("supportsUsb")] + public bool SupportsUsb { get; set; } + + /// /// Default constructor for SourceListItem, initializes the Icon to "Blank" /// diff --git a/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs b/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs new file mode 100644 index 00000000..d3f51483 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace PepperDash.Essentials.Core.Routing +{ + /// + /// The current sources for the room, keyed by eRoutingSignalType. + /// This allows for multiple sources to be tracked, such as audio and video. + /// + /// + /// This interface is used to provide access to the current sources in a room, + /// allowing for more complex routing scenarios where multiple signal types are involved. + /// + public interface ICurrentSources + { + /// + /// Gets the current sources for the room, keyed by eRoutingSignalType. + /// This dictionary contains the current source for each signal type, such as audio, video, + /// + Dictionary CurrentSources { get; } + + /// + /// Gets the current source keys for the room, keyed by eRoutingSignalType. + /// This dictionary contains the keys for the current source for each signal type, such as audio, + /// + Dictionary CurrentSourceKeys { get; } + + } +} diff --git a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs index 505a8652..a8dbc594 100644 --- a/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs +++ b/src/PepperDash.Essentials.Core/Routing/IHasCurrentSourceInfoChange.cs @@ -9,6 +9,8 @@ using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing.Interfaces */ +using System; + namespace PepperDash.Essentials.Core { /// @@ -21,10 +23,24 @@ namespace PepperDash.Essentials.Core /// /// For rooms with a single presentation source, change event /// + [Obsolete("Use ICurrentSources instead")] public interface IHasCurrentSourceInfoChange { + /// + /// The key for the current source info, used to look up the source in the SourceList + /// string CurrentSourceInfoKey { get; set; } + + /// + /// The current source info for the room, used to look up the source in the SourceList + /// SourceListItem CurrentSourceInfo { get; set; } + + /// + /// Event that is raised when the current source info changes. + /// This is used to notify the system of changes to the current source info. + /// The event handler receives the new source info and the type of change that occurred. + /// event SourceInfoChangeHandler CurrentSourceChange; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs index 59bcd65b..dd1d004e 100644 --- a/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs +++ b/src/PepperDash.Essentials.Core/Routing/IRoutingSink.cs @@ -1,29 +1,29 @@ -namespace PepperDash.Essentials.Core +using PepperDash.Essentials.Core.Routing; + +namespace PepperDash.Essentials.Core { /// /// For fixed-source endpoint devices /// public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange - { + { } /// /// For fixed-source endpoint devices with an input port /// - public interface IRoutingSinkWithInputPort :IRoutingSink + public interface IRoutingSinkWithInputPort : IRoutingSink { /// /// Gets the current input port for this routing sink. /// RoutingInputPort CurrentInputPort { get; } } - /*/// - /// For fixed-source endpoint devices - /// - public interface IRoutingSink : IRoutingInputs, IHasCurrentSourceInfoChange - { - void UpdateRouteRequest(RouteRequest request); - RouteRequest GetRouteRequest(); - }*/ + /// + /// Interface for routing sinks that have access to the current source information. + /// + public interface IRoutingSinkWithCurrentSources : IRoutingSink, ICurrentSources + { + } } \ 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 24d55c2e..926fca04 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -1,110 +1,199 @@ -using Crestron.SimplSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Routing; using Serilog.Events; -using System; -using System.Collections.Generic; -using System.Linq; using Feedback = PepperDash.Essentials.Core.Feedback; namespace PepperDash.Essentials.Devices.Common.Displays { - public abstract class DisplayBase : EssentialsDevice, IDisplay + /// + /// Abstract base class for display devices that provides common display functionality + /// including power control, input switching, and routing capabilities. + /// + public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources { - private RoutingInputPort _currentInputPort; - public RoutingInputPort CurrentInputPort - { - get - { - return _currentInputPort; - } + private RoutingInputPort _currentInputPort; - protected set - { - if (_currentInputPort == value) return; + /// + /// Gets or sets the current input port that is selected on the display. + /// + public RoutingInputPort CurrentInputPort + { + get + { + return _currentInputPort; + } - _currentInputPort = value; + protected set + { + if (_currentInputPort == value) return; - InputChanged?.Invoke(this, _currentInputPort); - } - } + _currentInputPort = value; - public event InputChangedEventHandler InputChanged; + InputChanged?.Invoke(this, _currentInputPort); + } + } - public event SourceInfoChangeHandler CurrentSourceChange; + /// + /// Event that is raised when the input changes on the display. + /// + public event InputChangedEventHandler InputChanged; - public string CurrentSourceInfoKey { get; set; } - public SourceListItem CurrentSourceInfo - { - get - { - return _CurrentSourceInfo; - } - set - { - if (value == _CurrentSourceInfo) return; + /// + /// Event that is raised when the current source information changes. + /// + public event SourceInfoChangeHandler CurrentSourceChange; - var handler = CurrentSourceChange; + /// + /// Gets or sets the key of the current source information. + /// + public string CurrentSourceInfoKey { get; set; } - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.WillChange); + /// + /// Gets or sets the current source information for the display. + /// + public SourceListItem CurrentSourceInfo + { + get + { + return _CurrentSourceInfo; + } + set + { + if (value == _CurrentSourceInfo) return; - _CurrentSourceInfo = value; + var handler = CurrentSourceChange; - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.DidChange); - } - } - SourceListItem _CurrentSourceInfo; + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.WillChange); + _CurrentSourceInfo = value; + + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.DidChange); + } + } + SourceListItem _CurrentSourceInfo; + + /// + public Dictionary CurrentSources { get; private set; } + + /// + public Dictionary CurrentSourceKeys { get; private set; } + + /// + /// Gets feedback indicating whether the display is currently cooling down after being powered off. + /// public BoolFeedback IsCoolingDownFeedback { get; protected set; } + + /// + /// Gets feedback indicating whether the display is currently warming up after being powered on. + /// public BoolFeedback IsWarmingUpFeedback { get; private set; } - public UsageTracking UsageTracker { get; set; } + /// + /// Gets or sets the usage tracking instance for monitoring display usage statistics. + /// + public UsageTracking UsageTracker { get; set; } + /// + /// Gets or sets the warmup time in milliseconds for the display to become ready after power on. + /// public uint WarmupTime { get; set; } + + /// + /// Gets or sets the cooldown time in milliseconds for the display to fully power down. + /// public uint CooldownTime { get; set; } /// - /// Bool Func that will provide a value for the PowerIsOn Output. Must be implemented - /// by concrete sub-classes + /// Abstract function that must be implemented by derived classes to provide the cooling down feedback value. + /// Must be implemented by concrete sub-classes. /// abstract protected Func IsCoolingDownFeedbackFunc { get; } - abstract protected Func IsWarmingUpFeedbackFunc { get; } - + /// + /// Abstract function that must be implemented by derived classes to provide the warming up feedback value. + /// Must be implemented by concrete sub-classes. + /// + abstract protected Func IsWarmingUpFeedbackFunc { get; } + + /// + /// Timer used for managing display warmup timing. + /// protected CTimer WarmupTimer; + + /// + /// Timer used for managing display cooldown timing. + /// protected CTimer CooldownTimer; #region IRoutingInputs Members + /// + /// Gets the collection of input ports available on this display device. + /// public RoutingPortCollection InputPorts { get; private set; } #endregion - protected DisplayBase(string key, string name) - : base(key, name) + /// + /// Initializes a new instance of the DisplayBase class. + /// + /// The unique key identifier for this display device. + /// The friendly name for this display device. + protected DisplayBase(string key, string name) + : base(key, name) { IsCoolingDownFeedback = new BoolFeedback("IsCoolingDown", IsCoolingDownFeedbackFunc); IsWarmingUpFeedback = new BoolFeedback("IsWarmingUp", IsWarmingUpFeedbackFunc); InputPorts = new RoutingPortCollection(); + CurrentSources = new Dictionary + { + { eRoutingSignalType.Audio, null }, + { eRoutingSignalType.Video, null }, + }; + + CurrentSourceKeys = new Dictionary + { + { eRoutingSignalType.Audio, string.Empty }, + { eRoutingSignalType.Video, string.Empty }, + }; } + /// + /// Powers on the display device. Must be implemented by derived classes. + /// public abstract void PowerOn(); + + /// + /// Powers off the display device. Must be implemented by derived classes. + /// public abstract void PowerOff(); + + /// + /// Toggles the power state of the display device. Must be implemented by derived classes. + /// public abstract void PowerToggle(); - public virtual FeedbackCollection Feedbacks + /// + /// Gets the collection of feedback objects for this display device. + /// + public virtual FeedbackCollection Feedbacks { get { - return new FeedbackCollection + return new FeedbackCollection { IsCoolingDownFeedback, IsWarmingUpFeedback @@ -112,30 +201,50 @@ namespace PepperDash.Essentials.Devices.Common.Displays } } - public abstract void ExecuteSwitch(object selector); + /// + /// Executes a switch to the specified input on the display device. Must be implemented by derived classes. + /// + /// The selector object that identifies which input to switch to. + public abstract void ExecuteSwitch(object selector); - protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey, - EiscApiAdvanced bridge) - { - var joinMap = new DisplayControllerJoinMap(joinStart); + /// + /// Links the display device to an API using a trilist, join start, join map key, and bridge. + /// This overload uses serialized join map configuration. + /// + /// The display device to link. + /// The BasicTriList for communication. + /// The starting join number for the device. + /// The key for the join map configuration. + /// The EISC API bridge instance. + protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey, + EiscApiAdvanced bridge) + { + var joinMap = new DisplayControllerJoinMap(joinStart); - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); - if (bridge != null) - { - bridge.AddJoinMap(Key, joinMap); - } - else - { - Debug.LogMessage(LogEventLevel.Information,this,"Please update config to use 'eiscapiadvanced' to get all join map features for this device."); - } + if (bridge != null) + { + bridge.AddJoinMap(Key, joinMap); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + } LinkDisplayToApi(displayDevice, trilist, joinMap); - } + } + /// + /// Links the display device to an API using a trilist and join map. + /// This overload uses a pre-configured join map instance. + /// + /// The display device to link. + /// The BasicTriList for communication. + /// The join map configuration for the device. protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, DisplayControllerJoinMap joinMap) { Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); @@ -268,68 +377,96 @@ namespace PepperDash.Essentials.Devices.Common.Displays volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]); } - } + } - public abstract class TwoWayDisplayBase : DisplayBase, IRoutingFeedback, IHasPowerControlWithFeedback + /// + /// Abstract base class for two-way display devices that provide feedback capabilities. + /// Extends DisplayBase with routing feedback and power control feedback functionality. + /// + public abstract class TwoWayDisplayBase : DisplayBase, IRoutingFeedback, IHasPowerControlWithFeedback { - public StringFeedback CurrentInputFeedback { get; private set; } + /// + /// Gets feedback for the current input selection on the display. + /// + public StringFeedback CurrentInputFeedback { get; private set; } - abstract protected Func CurrentInputFeedbackFunc { get; } + /// + /// Abstract function that must be implemented by derived classes to provide the current input feedback value. + /// Must be implemented by concrete sub-classes. + /// + abstract protected Func CurrentInputFeedbackFunc { get; } - public BoolFeedback PowerIsOnFeedback { get; protected set; } + /// + /// Gets feedback indicating whether the display is currently powered on. + /// + public BoolFeedback PowerIsOnFeedback { get; protected set; } - abstract protected Func PowerIsOnFeedbackFunc { get; } + /// + /// Abstract function that must be implemented by derived classes to provide the power state feedback value. + /// Must be implemented by concrete sub-classes. + /// + abstract protected Func PowerIsOnFeedbackFunc { get; } - - public static MockDisplay DefaultDisplay - { - get + /// + /// Gets the default mock display instance for testing and development purposes. + /// + public static MockDisplay DefaultDisplay + { + get { if (_DefaultDisplay == null) _DefaultDisplay = new MockDisplay("default", "Default Display"); return _DefaultDisplay; - } + } } static MockDisplay _DefaultDisplay; + /// + /// Initializes a new instance of the TwoWayDisplayBase class. + /// + /// The unique key identifier for this display device. + /// The friendly name for this display device. public TwoWayDisplayBase(string key, string name) : base(key, name) { - CurrentInputFeedback = new StringFeedback(CurrentInputFeedbackFunc); + CurrentInputFeedback = new StringFeedback(CurrentInputFeedbackFunc); WarmupTime = 7000; CooldownTime = 15000; - PowerIsOnFeedback = new BoolFeedback("PowerOnFeedback", PowerIsOnFeedbackFunc); + PowerIsOnFeedback = new BoolFeedback("PowerOnFeedback", PowerIsOnFeedbackFunc); - Feedbacks.Add(CurrentInputFeedback); - Feedbacks.Add(PowerIsOnFeedback); + Feedbacks.Add(CurrentInputFeedback); + Feedbacks.Add(PowerIsOnFeedback); - PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; + PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; } - void PowerIsOnFeedback_OutputChange(object sender, EventArgs e) - { - if (UsageTracker != null) - { - if (PowerIsOnFeedback.BoolValue) - UsageTracker.StartDeviceUsage(); - else - UsageTracker.EndDeviceUsage(); - } - } + void PowerIsOnFeedback_OutputChange(object sender, EventArgs e) + { + if (UsageTracker != null) + { + if (PowerIsOnFeedback.BoolValue) + UsageTracker.StartDeviceUsage(); + else + UsageTracker.EndDeviceUsage(); + } + } - public event EventHandler NumericSwitchChange; + /// + /// Event that is raised when a numeric switch change occurs on the display. + /// + public event EventHandler NumericSwitchChange; - /// - /// Raise an event when the status of a switch object changes. - /// - /// Arguments defined as IKeyName sender, output, input, and eRoutingSignalType - protected void OnSwitchChange(RoutingNumericEventArgs e) - { - var newEvent = NumericSwitchChange; - if (newEvent != null) newEvent(this, e); - } + /// + /// Raise an event when the status of a switch object changes. + /// + /// Arguments defined as IKeyName sender, output, input, and eRoutingSignalType + protected void OnSwitchChange(RoutingNumericEventArgs e) + { + var newEvent = NumericSwitchChange; + if (newEvent != null) newEvent(this, e); + } } } \ No newline at end of file From 9d313d8c7ca3041eca6429d7ddb419027f97e89a Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Jul 2025 09:54:08 -0500 Subject: [PATCH 10/22] fix: use Control Subnet IP if MC TP devices are on the CS Lan --- .../DeviceTypeInterfaces/IMobileControl.cs | 18 ++- .../MobileControlTouchpanelController.cs | 125 +++++++++++++++--- .../MobileControlWebsocketServer.cs | 48 +++---- 3 files changed, 145 insertions(+), 46 deletions(-) diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs index c30edebd..1a7fab25 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.ObjectModel; +using Crestron.SimplSharpPro; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; @@ -33,11 +35,11 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces string SystemUuid { get; } - BoolFeedback ApiOnlineAndAuthorized { get;} + BoolFeedback ApiOnlineAndAuthorized { get; } void SendMessageObject(IMobileControlMessage o); - void AddAction(T messenger, Action action) where T:IMobileControlMessenger; + void AddAction(T messenger, Action action) where T : IMobileControlMessenger; void RemoveAction(string key); @@ -45,14 +47,14 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces bool CheckForDeviceMessenger(string key); - IMobileControlRoomMessenger GetRoomMessenger(string key); + IMobileControlRoomMessenger GetRoomMessenger(string key); - } + } /// /// Describes a mobile control messenger /// - public interface IMobileControlMessenger: IKeyed + public interface IMobileControlMessenger : IKeyed { IMobileControl AppServerController { get; } string MessagePath { get; } @@ -104,9 +106,9 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces public interface IMobileControlAction { - IMobileControlMessenger Messenger { get; } + IMobileControlMessenger Messenger { get; } - Action Action { get; } + Action Action { get; } } public interface IMobileControlTouchpanelController : IKeyed @@ -115,5 +117,7 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces void SetAppUrl(string url); bool UseDirectServer { get; } bool ZoomRoomController { get; } + + ReadOnlyCollection ConnectedIps { get; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs index 9acd04f4..24f5f8e5 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -1,4 +1,8 @@ -using Crestron.SimplSharpPro; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.UI; using Newtonsoft.Json; @@ -10,21 +14,14 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceInfo; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.UI; -using System; -using System.Collections.Generic; -using System.Linq; using Feedback = PepperDash.Essentials.Core.Feedback; namespace PepperDash.Essentials.Touchpanel { - //public interface IMobileControlTouchpanelController - //{ - // StringFeedback AppUrlFeedback { get; } - // string DefaultRoomKey { get; } - // string DeviceKey { get; } - //} - - + /// + /// Mobile Control touchpanel controller that provides app control, Zoom integration, + /// and mobile control functionality for Crestron touchpanels. + /// public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlTouchpanelController, ITheme { private readonly MobileControlTouchpanelProperties localConfig; @@ -32,42 +29,90 @@ namespace PepperDash.Essentials.Touchpanel private string _appUrl; + /// + /// Gets feedback for the current application URL. + /// public StringFeedback AppUrlFeedback { get; private set; } + private readonly StringFeedback QrCodeUrlFeedback; private readonly StringFeedback McServerUrlFeedback; private readonly StringFeedback UserCodeFeedback; private readonly BoolFeedback _appOpenFeedback; + /// + /// Gets feedback indicating whether an application is currently open on the touchpanel. + /// public BoolFeedback AppOpenFeedback => _appOpenFeedback; private readonly BoolFeedback _zoomIncomingCallFeedback; + /// + /// Gets feedback indicating whether there is an incoming Zoom call. + /// public BoolFeedback ZoomIncomingCallFeedback => _zoomIncomingCallFeedback; private readonly BoolFeedback _zoomInCallFeedback; + /// + /// Event that is raised when device information changes. + /// public event DeviceInfoChangeHandler DeviceInfoChanged; + /// + /// Gets feedback indicating whether a Zoom call is currently active. + /// public BoolFeedback ZoomInCallFeedback => _zoomInCallFeedback; - + /// + /// Gets the collection of feedback objects for this touchpanel controller. + /// public FeedbackCollection Feedbacks { get; private set; } + /// + /// Gets the collection of Zoom-related feedback objects. + /// public FeedbackCollection ZoomFeedbacks { get; private set; } + /// + /// Gets the default room key for this touchpanel controller. + /// public string DefaultRoomKey => _config.DefaultRoomKey; + /// + /// Gets a value indicating whether to use direct server communication. + /// public bool UseDirectServer => localConfig.UseDirectServer; + /// + /// Gets a value indicating whether this touchpanel acts as a Zoom Room controller. + /// public bool ZoomRoomController => localConfig.ZoomRoomController; + /// + /// Gets the current theme for the touchpanel interface. + /// public string Theme => localConfig.Theme; + /// + /// Gets feedback for the current theme setting. + /// public StringFeedback ThemeFeedback { get; private set; } + /// + /// Gets device information including MAC address and IP address. + /// public DeviceInfo DeviceInfo => new DeviceInfo(); + public ReadOnlyCollection ConnectedIps => Panel.ConnectedIpList; + + /// + /// Initializes a new instance of the MobileControlTouchpanelController class. + /// + /// The unique key identifier for this touchpanel controller. + /// The friendly name for this touchpanel controller. + /// The touchpanel hardware device. + /// The configuration properties for this controller. public MobileControlTouchpanelController(string key, string name, BasicTriListWithSmartObject panel, MobileControlTouchpanelProperties config) : base(key, name, panel, config) { localConfig = config; @@ -139,6 +184,10 @@ namespace PepperDash.Essentials.Touchpanel RegisterForExtenders(); } + /// + /// Updates the theme setting for this touchpanel controller and persists the change to configuration. + /// + /// The new theme identifier to apply. public void UpdateTheme(string theme) { localConfig.Theme = theme; @@ -271,6 +320,11 @@ namespace PepperDash.Essentials.Touchpanel } } + /// + /// Performs custom activation setup for the touchpanel controller, including + /// registering messengers and linking to mobile control. + /// + /// True if activation was successful; otherwise, false. public override bool CustomActivate() { var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this); @@ -300,12 +354,20 @@ namespace PepperDash.Essentials.Touchpanel return base.CustomActivate(); } - + /// + /// Handles device extender signal changes for system reserved signals. + /// + /// The device extender that generated the signal change. + /// The signal event arguments containing the changed signal information. protected override void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"System Device Extender args: ${args.Event}:${args.Sig}"); } + /// + /// Sets up the panel drivers and signal mappings for the specified room. + /// + /// The room key to configure the panel drivers for. protected override void SetupPanelDrivers(string roomKey) { AppUrlFeedback.LinkInputSig(Panel.StringInput[1]); @@ -366,6 +428,10 @@ namespace PepperDash.Essentials.Touchpanel SetAppUrl(_bridge.AppUrl); } + /// + /// Sets the application URL and updates the corresponding feedback. + /// + /// The new application URL to set. public void SetAppUrl(string url) { _appUrl = url; @@ -391,6 +457,9 @@ namespace PepperDash.Essentials.Touchpanel } } + /// + /// Hides the currently open application on the touchpanel. + /// public void HideOpenApp() { if (Panel is TswX70Base x70Panel) @@ -406,6 +475,9 @@ namespace PepperDash.Essentials.Touchpanel } } + /// + /// Opens an application on the touchpanel. Note: X60 panels do not support Zoom app opening. + /// public void OpenApp() { if (Panel is TswX70Base x70Panel) @@ -421,6 +493,9 @@ namespace PepperDash.Essentials.Touchpanel } } + /// + /// Closes the currently open application on the touchpanel. + /// public void CloseOpenApp() { if (Panel is TswX70Base x70Panel) @@ -436,6 +511,9 @@ namespace PepperDash.Essentials.Touchpanel } } + /// + /// Ends the current Zoom call on the touchpanel. + /// public void EndZoomCall() { if (Panel is TswX70Base x70Panel) @@ -451,6 +529,10 @@ namespace PepperDash.Essentials.Touchpanel } } + /// + /// Updates the device information (MAC address and IP address) from the touchpanel + /// and raises the DeviceInfoChanged event. + /// public void UpdateDeviceInfo() { if (Panel is TswXX70Base x70Panel) @@ -487,14 +569,27 @@ namespace PepperDash.Essentials.Touchpanel } } + /// + /// Factory class for creating MobileControlTouchpanelController instances from device configuration. + /// Supports various Crestron touchpanel models including TSW, TS, CrestronApp, XPanel, and DGE series. + /// public class MobileControlTouchpanelControllerFactory : EssentialsPluginDeviceFactory { + /// + /// Initializes a new instance of the MobileControlTouchpanelControllerFactory class. + /// Sets up supported device type names and minimum framework version requirements. + /// public MobileControlTouchpanelControllerFactory() { TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" }; MinimumEssentialsFrameworkVersion = "2.0.0"; } + /// + /// Builds a MobileControlTouchpanelController device from the provided device configuration. + /// + /// The device configuration containing the device properties and settings. + /// A configured MobileControlTouchpanelController instance. public override EssentialsDevice BuildDevice(DeviceConfig dc) { var comm = CommFactory.GetControlPropertiesConfig(dc); @@ -557,7 +652,7 @@ namespace PepperDash.Essentials.Touchpanel return new Ts1070(id, Global.ControlSystem); else if (type == "dge1000") return new Dge1000(id, Global.ControlSystem); - else + else { Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW controller with type '{0}'", type); diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs index 859a7c7b..846a674a 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs @@ -1,4 +1,10 @@ -using Crestron.SimplSharp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Text; +using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core; @@ -9,12 +15,6 @@ using PepperDash.Essentials.Core.Web; using PepperDash.Essentials.RoomBridges; using PepperDash.Essentials.WebApiHandlers; using Serilog.Events; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Text; using WebSocketSharp; using WebSocketSharp.Net; using WebSocketSharp.Server; @@ -60,7 +60,7 @@ namespace PepperDash.Essentials.WebSocketServer private string lanIpAddress => CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter)); - private System.Net.IPAddress csIpAddress; + private System.Net.IPAddress csIpAddress; private System.Net.IPAddress csSubnetMask; @@ -122,7 +122,7 @@ namespace PepperDash.Essentials.WebSocketServer _parent = parent; // Set the default port to be 50000 plus the slot number of the program - Port = 50000 + (int)Global.ControlSystem.ProgramNumber; + Port = 50000 + (int)Global.ControlSystem.ProgramNumber; if (customPort != 0) { @@ -156,9 +156,9 @@ namespace PepperDash.Essentials.WebSocketServer } try - { + { var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); - var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId); + var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId); var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask); @@ -298,8 +298,6 @@ namespace PepperDash.Essentials.WebSocketServer var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); - this.LogVerbose("Processor IP: {processorIp}", processorIp); - foreach (var touchpanel in touchpanels.Select(tp => { var token = _secret.Tokens.FirstOrDefault((t) => t.Value.TouchpanelKey.Equals(tp.Key, StringComparison.InvariantCultureIgnoreCase)); @@ -321,11 +319,13 @@ namespace PepperDash.Essentials.WebSocketServer continue; } - var appUrl = $"http://{processorIp}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; + var ip = touchpanel.Touchpanel.ConnectedIps.Any(ipInfo => csIpAddress.IsInSameSubnet(System.Net.IPAddress.Parse(ipInfo.DeviceIpAddress), csSubnetMask)) ? csIpAddress.ToString() : processorIp; + + var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; this.LogVerbose("Sending URL {appUrl}", appUrl); - touchpanel.Messenger.UpdateAppUrl($"http://{processorIp}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"); + touchpanel.Messenger.UpdateAppUrl($"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"); } } @@ -349,7 +349,7 @@ namespace PepperDash.Essentials.WebSocketServer if (!Directory.Exists($"{userAppPath}{localConfigFolderName}")) { Directory.CreateDirectory($"{userAppPath}{localConfigFolderName}"); - } + } using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigFileName}", FileMode.Create, FileAccess.ReadWrite))) { @@ -358,7 +358,7 @@ namespace PepperDash.Essentials.WebSocketServer this.LogDebug("LAN Adapter ID: {lanAdapterId}", lanAdapterId); - var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); + var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); var config = GetApplicationConfig(processorIp); @@ -378,7 +378,7 @@ namespace PepperDash.Essentials.WebSocketServer return; } - if(csAdapterId == -1) + if (csAdapterId == -1) { this.LogDebug("CS LAN Adapter not found"); return; @@ -389,8 +389,8 @@ namespace PepperDash.Essentials.WebSocketServer using (var sw = new StreamWriter(File.Open($"{userAppPath}{localConfigFolderName}{Global.DirectorySeparator}{appConfigCsFileName}", FileMode.Create, FileAccess.ReadWrite))) { // Write the CS application configuration file. Used when a request comes in for the application config from the CS - var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); - + var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); + var config = GetApplicationConfig(processorIp); var contents = JsonConvert.SerializeObject(config, Formatting.Indented); @@ -400,7 +400,7 @@ namespace PepperDash.Essentials.WebSocketServer } private MobileControlApplicationConfig GetApplicationConfig(string processorIp) - { + { try { var config = new MobileControlApplicationConfig @@ -430,10 +430,10 @@ namespace PepperDash.Essentials.WebSocketServer } catch (Exception ex) { - this.LogError(ex, "Error getting application configuration"); + this.LogError(ex, "Error getting application configuration"); return null; - } + } } /// @@ -572,7 +572,7 @@ namespace PepperDash.Essentials.WebSocketServer var values = s.Split(' '); - if(values.Length < 2) + if (values.Length < 2) { CrestronConsole.ConsoleCommandResponse("Invalid number of arguments. Please provide a room key and a grant code"); return; From e59c50d0aac1341e4bfda303d67cb4a3ff362740 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Jul 2025 10:15:19 -0500 Subject: [PATCH 11/22] refactor: use tryParse for IP Address parsing Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../WebSocketServer/MobileControlWebsocketServer.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs index 846a674a..012f948f 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs @@ -319,7 +319,15 @@ namespace PepperDash.Essentials.WebSocketServer continue; } - var ip = touchpanel.Touchpanel.ConnectedIps.Any(ipInfo => csIpAddress.IsInSameSubnet(System.Net.IPAddress.Parse(ipInfo.DeviceIpAddress), csSubnetMask)) ? csIpAddress.ToString() : processorIp; + var ip = touchpanel.Touchpanel.ConnectedIps.Any(ipInfo => + { + if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp)) + { + return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask); + } + this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress); + return false; + }) ? csIpAddress.ToString() : processorIp; var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; From c1eccfd790633770f0f8ffb03e3c33f677d64f2b Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Jul 2025 12:13:08 -0500 Subject: [PATCH 12/22] fix: refactor interfaces for backwards compatibility --- .../DeviceTypeInterfaces/IMobileControl.cs | 35 +++++++++++++++++-- .../MobileControlTouchpanelController.cs | 2 +- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs index 1a7fab25..edc2e627 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs @@ -111,13 +111,42 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces Action Action { get; } } + /// + /// Describes a MobileControl Touchpanel Controller + /// public interface IMobileControlTouchpanelController : IKeyed { + /// + /// The default room key for the controller + /// string DefaultRoomKey { get; } - void SetAppUrl(string url); - bool UseDirectServer { get; } - bool ZoomRoomController { get; } + /// + /// Sets the application URL for the controller + /// + /// The application URL + void SetAppUrl(string url); + + /// + /// Indicates whether the controller uses a direct server connection + /// + bool UseDirectServer { get; } + + /// + /// Indicates whether the controller is a Zoom Room controller + /// + bool ZoomRoomController { get; } + } + + /// + /// Describes a MobileControl Crestron Touchpanel Controller + /// This interface extends the IMobileControlTouchpanelController to include connected IP information + /// + public interface IMobileControlCrestronTouchpanelController : IMobileControlTouchpanelController + { + /// + /// Gets a collection of connected IP information for the touchpanel controller + /// ReadOnlyCollection ConnectedIps { get; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs index 24f5f8e5..53f600ef 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -22,7 +22,7 @@ namespace PepperDash.Essentials.Touchpanel /// Mobile Control touchpanel controller that provides app control, Zoom integration, /// and mobile control functionality for Crestron touchpanels. /// - public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlTouchpanelController, ITheme + public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlCrestronTouchpanelController, ITheme { private readonly MobileControlTouchpanelProperties localConfig; private IMobileControlRoomMessenger _bridge; From 2bf0f2092bb5f2d588482c2fc87c47ae44b4f6bd Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Jul 2025 12:16:32 -0500 Subject: [PATCH 13/22] fix: use new interface in direct server --- .../MobileControlWebsocketServer.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs index 012f948f..2b0d5cbd 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs @@ -319,15 +319,19 @@ namespace PepperDash.Essentials.WebSocketServer continue; } - var ip = touchpanel.Touchpanel.ConnectedIps.Any(ipInfo => + string ip = processorIp; + if (touchpanel.Touchpanel is IMobileControlCrestronTouchpanelController crestronTouchpanel) { - if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp)) + ip = crestronTouchpanel.ConnectedIps.Any(ipInfo => { - return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask); - } - this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress); - return false; - }) ? csIpAddress.ToString() : processorIp; + if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp)) + { + return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask); + } + this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress); + return false; + }) ? csIpAddress.ToString() : processorIp; + } var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; From e76369726d58e897e47904fdc77460a0d4ef890c Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Jul 2025 12:25:52 -0500 Subject: [PATCH 14/22] docs: XML comments for DestinationListItem --- .../Devices/DestinationListItem.cs | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs index 0c21216a..19c40adb 100644 --- a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs @@ -5,19 +5,34 @@ using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core { + /// + /// Represents a destination item in a routing system that can receive audio/video signals. + /// Contains information about the destination device, its properties, and location settings. + /// public class DestinationListItem { + /// + /// Gets or sets the key identifier for the sink device that this destination represents. + /// [JsonProperty("sinkKey")] public string SinkKey { get; set; } private EssentialsDevice _sinkDevice; + /// + /// Gets the actual device instance for this destination. + /// Lazily loads the device from the DeviceManager using the SinkKey. + /// [JsonIgnore] public EssentialsDevice SinkDevice { get { return _sinkDevice ?? (_sinkDevice = DeviceManager.GetDeviceForKey(SinkKey) as EssentialsDevice); } } + /// + /// Gets the preferred display name for this destination. + /// Returns the custom Name if set, otherwise returns the SinkDevice name, or "---" if no device is found. + /// [JsonProperty("preferredName")] public string PreferredName { @@ -32,30 +47,62 @@ namespace PepperDash.Essentials.Core } } + /// + /// Gets or sets the custom name for this destination. + /// If set, this name will be used as the PreferredName instead of the device name. + /// [JsonProperty("name")] public string Name { get; set; } + /// + /// Gets or sets a value indicating whether this destination should be included in destination lists. + /// [JsonProperty("includeInDestinationList")] public bool IncludeInDestinationList { get; set; } + /// + /// Gets or sets the display order for this destination in lists. + /// Lower values appear first in sorted lists. + /// [JsonProperty("order")] public int Order { get; set; } + /// + /// Gets or sets the surface location identifier for this destination. + /// Used to specify which surface or screen this destination is located on. + /// [JsonProperty("surfaceLocation")] public int SurfaceLocation { get; set; } + /// + /// Gets or sets the vertical location position for this destination. + /// Used for spatial positioning in multi-display configurations. + /// [JsonProperty("verticalLocation")] public int VerticalLocation { get; set; } - + + /// + /// Gets or sets the horizontal location position for this destination. + /// Used for spatial positioning in multi-display configurations. + /// [JsonProperty("horizontalLocation")] public int HorizontalLocation { get; set; } + /// + /// Gets or sets the signal type that this destination can receive (Audio, Video, AudioVideo, etc.). + /// [JsonProperty("sinkType")] public eRoutingSignalType SinkType { get; set; } + /// + /// Gets or sets a value indicating whether this destination is used for codec content sharing. + /// [JsonProperty("isCodecContentDestination")] public bool isCodecContentDestination { get; set; } + /// + /// Gets or sets a value indicating whether this destination is used for program audio output. + /// [JsonProperty("isProgramAudioDestination")] public bool isProgramAudioDestination { get; set; } } From 1dcd4e328c8f84795e85c8ce197496632c701599 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Jul 2025 12:32:26 -0500 Subject: [PATCH 15/22] fix: Destination support for USB --- .../Devices/DestinationListItem.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs index 19c40adb..41043b82 100644 --- a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs @@ -105,5 +105,12 @@ namespace PepperDash.Essentials.Core /// [JsonProperty("isProgramAudioDestination")] public bool isProgramAudioDestination { get; set; } + + /// + /// Gets or sets a value indicating whether this destination supports USB connections. + /// This is used to determine if the destination can handle USB. + /// + [JsonProperty("supportsUsb")] + public bool SupportsUsb { get; set; } } } \ No newline at end of file From 2bbefa062d26db30578a169399f83c7e7648898b Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Jul 2025 13:28:10 -0500 Subject: [PATCH 16/22] docs: fix comments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../DeviceTypeInterfaces/IStateFeedback.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs index e4070594..a4f6c2bb 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IStateFeedback.cs @@ -4,8 +4,8 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { /// - /// Interface for devices that provide audio meter feedback. - /// This interface is used to standardize access to meter feedback across different devices. + /// Interface for devices that provide state feedback. + /// This interface is used to standardize access to state feedback across different devices. /// public interface IStateFeedback { From 97b2ffed9c07ee3a9e012041a33538ee4b65cb11 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Jul 2025 13:28:37 -0500 Subject: [PATCH 17/22] docs: fix comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs b/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs index d3f51483..8c6323d4 100644 --- a/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs +++ b/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs @@ -14,13 +14,13 @@ namespace PepperDash.Essentials.Core.Routing { /// /// Gets the current sources for the room, keyed by eRoutingSignalType. - /// This dictionary contains the current source for each signal type, such as audio, video, + /// This dictionary contains the current source for each signal type, such as audio, video, and control signals. /// Dictionary CurrentSources { get; } /// /// Gets the current source keys for the room, keyed by eRoutingSignalType. - /// This dictionary contains the keys for the current source for each signal type, such as audio, + /// This dictionary contains the keys for the current source for each signal type, such as audio, video, and control signals. /// Dictionary CurrentSourceKeys { get; } From 660836bd5a3c19149b9322188f736c6dc2684aa2 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Jul 2025 13:28:59 -0500 Subject: [PATCH 18/22] docs: remove spaces Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/PepperDash.Essentials.Core/Devices/SourceListItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index bfba4b4c..3d08a218 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -169,7 +169,7 @@ namespace PepperDash.Essentials.Core public bool DisableSimpleRouting { get; set; } /// - /// The key of the device that provides video sync for this source item + /// The key of the device that provides video sync for this source item /// [JsonProperty("syncProviderDeviceKey")] public string SyncProviderDeviceKey { get; set; } From 789113008ea553dab398a2e49b554c9db77e6c50 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Jul 2025 13:29:11 -0500 Subject: [PATCH 19/22] docs: update comments Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs index 41043b82..c0837401 100644 --- a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs @@ -108,7 +108,8 @@ namespace PepperDash.Essentials.Core /// /// Gets or sets a value indicating whether this destination supports USB connections. - /// This is used to determine if the destination can handle USB. + /// Indicates if the destination can handle USB functionality, such as USB signal routing or device connections. + /// This property is used to determine compatibility with USB-based devices or systems. /// [JsonProperty("supportsUsb")] public bool SupportsUsb { get; set; } From 311452beaccc18f6c28a7acdfb9a077148d2cf1a Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Jul 2025 13:30:11 -0500 Subject: [PATCH 20/22] fix: use correct namespaces Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs b/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs index 8c6323d4..bef0fd95 100644 --- a/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs +++ b/src/PepperDash.Essentials.Core/Routing/ICurrentSources.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Routing { From a6cd9a0571fb15e50a4f4129934c57208dd43bf7 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 22 Jul 2025 14:56:28 -0500 Subject: [PATCH 21/22] feat: add destination and source port key properties for advanced routing --- .../Devices/DestinationListItem.cs | 7 +++++++ src/PepperDash.Essentials.Core/Devices/SourceListItem.cs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs index c0837401..788714b7 100644 --- a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs @@ -113,5 +113,12 @@ namespace PepperDash.Essentials.Core /// [JsonProperty("supportsUsb")] public bool SupportsUsb { get; set; } + + /// + /// The key of the destination port associated with this source item + /// This is used to identify the specific port on the destination device that this item refers to for advanced routing + /// + [JsonProperty("destinationPortKey")] + public string DestinationPortKey { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs index 3d08a218..fe0bde9d 100644 --- a/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/SourceListItem.cs @@ -180,6 +180,13 @@ namespace PepperDash.Essentials.Core [JsonProperty("supportsUsb")] public bool SupportsUsb { get; set; } + /// + /// The key of the source port associated with this source item + /// This is used to identify the specific port on the source device that this item refers to for advanced routing + /// + [JsonProperty("sourcePortKey")] + public string SourcePortKey { get; set; } + /// /// Default constructor for SourceListItem, initializes the Icon to "Blank" From 799d4c127cce5c8c416db72ee0be981844331cdc Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 22 Jul 2025 14:02:01 -0600 Subject: [PATCH 22/22] Update src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs index 788714b7..5a66c0b3 100644 --- a/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs +++ b/src/PepperDash.Essentials.Core/Devices/DestinationListItem.cs @@ -115,7 +115,7 @@ namespace PepperDash.Essentials.Core public bool SupportsUsb { get; set; } /// - /// The key of the destination port associated with this source item + /// The key of the destination port associated with this destination item /// This is used to identify the specific port on the destination device that this item refers to for advanced routing /// [JsonProperty("destinationPortKey")]