From 092896bb25deb825017bf9622d6f067cfe27b21a Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 23 Dec 2025 09:57:49 -0600 Subject: [PATCH 1/3] fix: support for legacy UDP EISC --- .../Bridges/BridgeBase.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs index 92ac2b9c..d8f19bc8 100644 --- a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs +++ b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs @@ -427,9 +427,12 @@ namespace PepperDash.Essentials.Core.Bridges /// public class EiscApiAdvancedFactory : EssentialsDeviceFactory { + /// + /// Constructor + /// public EiscApiAdvancedFactory() { - TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" }; + TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced", "eiscapiadvudp", "eiscapiadvancedudp" }; } /// @@ -438,7 +441,7 @@ namespace PepperDash.Essentials.Core.Bridges /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EiscApiAdvanced Device"); + Debug.LogDebug("Attempting to create new EiscApiAdvanced Device"); var controlProperties = CommFactory.GetControlPropertiesConfig(dc); @@ -446,6 +449,13 @@ namespace PepperDash.Essentials.Core.Bridges switch (dc.Type.ToLower()) { + case "eiscapiadvudp": + case "eiscapiadvancedudp": + { + eisc = new EthernetIntersystemCommunications(controlProperties.IpIdInt, + controlProperties.TcpSshProperties.Address, Global.ControlSystem); + break; + } case "eiscapiadv": case "eiscapiadvanced": { From 076e5dfa9d94fdad988b10f5543c7db76dae7d03 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 23 Dec 2025 10:25:53 -0600 Subject: [PATCH 2/3] chore: update comments, debug methods, and mark some things obsolete --- .../Bridges/BridgeBase.cs | 164 +++++++++--------- 1 file changed, 85 insertions(+), 79 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs index d8f19bc8..1b8e826e 100644 --- a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs +++ b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs @@ -2,25 +2,29 @@ using System; using System.Collections.Generic; -using System.Reflection; using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.EthernetCommunication; using Newtonsoft.Json; using PepperDash.Core; +using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Config; using Serilog.Events; -//using PepperDash.Essentials.Devices.Common.Cameras; namespace PepperDash.Essentials.Core.Bridges { /// /// Base class for bridge API variants /// + [Obsolete("Will be removed in v3.0.0")] public abstract class BridgeApi : EssentialsDevice { + /// + /// Constructor + /// + /// Device key protected BridgeApi(string key) : base(key) { @@ -29,23 +33,36 @@ namespace PepperDash.Essentials.Core.Bridges } /// - /// Represents a EiscApiAdvanced + /// Class to link devices and rooms to an EISC Instance /// public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor { + /// + /// Gets the PropertiesConfig + /// public EiscApiPropertiesConfig PropertiesConfig { get; private set; } + /// + /// Gets the JoinMaps dictionary + /// public Dictionary JoinMaps { get; private set; } + /// + /// Gets the EISC instance + /// public BasicTriList Eisc { get; private set; } + /// + /// Constructor + /// + /// Device configuration + /// EISC instance public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) : base(dc.Key) { JoinMaps = new Dictionary(); PropertiesConfig = dc.Properties.ToObject(); - //PropertiesConfig = JsonConvert.DeserializeObject(dc.Properties.ToString()); Eisc = eisc; @@ -60,8 +77,7 @@ namespace PepperDash.Essentials.Core.Bridges /// /// CustomActivate method - /// - /// + /// public override bool CustomActivate() { CommunicationMonitor.Start(); @@ -83,7 +99,7 @@ namespace PepperDash.Essentials.Core.Bridges if (PropertiesConfig.Devices == null) { - Debug.LogMessage(LogEventLevel.Debug, this, "No devices linked to this bridge"); + this.LogDebug("No devices linked to this bridge"); return; } @@ -104,9 +120,7 @@ namespace PepperDash.Essentials.Core.Bridges continue; } - Debug.LogMessage(LogEventLevel.Information, this, - "{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.", - device.Key); + this.LogWarning("{deviceKey} is not compatible with this bridge type. Please update the device.", device.Key); } } @@ -121,34 +135,31 @@ namespace PepperDash.Essentials.Core.Bridges if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Registration result: {0}", registerResult); + this.LogVerbose("Registration result: {registerResult}", registerResult); return; } - Debug.LogMessage(LogEventLevel.Debug, this, "EISC registration successful"); + this.LogDebug("EISC registration successful"); } /// - /// LinkRooms method + /// Link rooms to this EISC. Rooms MUST implement IBridgeAdvanced /// public void LinkRooms() { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking Rooms..."); + this.LogDebug("Linking Rooms..."); if (PropertiesConfig.Rooms == null) { - Debug.LogMessage(LogEventLevel.Debug, this, "No rooms linked to this bridge."); + this.LogDebug("No rooms linked to this bridge."); return; } foreach (var room in PropertiesConfig.Rooms) { - var rm = DeviceManager.GetDeviceForKey(room.RoomKey) as IBridgeAdvanced; - - if (rm == null) + if (!(DeviceManager.GetDeviceForKey(room.RoomKey) is IBridgeAdvanced rm)) { - Debug.LogMessage(LogEventLevel.Debug, this, - "Room {0} does not implement IBridgeAdvanced. Skipping...", room.RoomKey); + this.LogDebug("Room {roomKey} does not implement IBridgeAdvanced. Skipping...", room.RoomKey); continue; } @@ -159,11 +170,8 @@ namespace PepperDash.Essentials.Core.Bridges /// /// Adds a join map /// - /// - /// - /// - /// AddJoinMap method - /// + /// The key of the device to add the join map for + /// The join map to add public void AddJoinMap(string deviceKey, JoinMapBaseAdvanced joinMap) { if (!JoinMaps.ContainsKey(deviceKey)) @@ -172,14 +180,13 @@ namespace PepperDash.Essentials.Core.Bridges } else { - Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to add join map with key '{0}'. Key already exists in JoinMaps dictionary", deviceKey); + this.LogWarning("Unable to add join map with key '{deviceKey}'. Key already exists in JoinMaps dictionary", deviceKey); } } /// /// PrintJoinMaps method - /// - /// + /// public virtual void PrintJoinMaps() { CrestronConsole.ConsoleCommandResponse("Join Maps for EISC IPID: {0}\r\n", Eisc.ID.ToString("X")); @@ -190,17 +197,17 @@ namespace PepperDash.Essentials.Core.Bridges joinMap.Value.PrintJoinMapInfo(); } } + /// /// MarkdownForBridge method - /// - /// + /// public virtual void MarkdownForBridge(string bridgeKey) { - Debug.LogMessage(LogEventLevel.Information, this, "Writing Joinmaps to files for EISC IPID: {0}", Eisc.ID.ToString("X")); + this.LogInformation("Writing Joinmaps to files for EISC IPID: {eiscId}", Eisc.ID.ToString("X")); foreach (var joinMap in JoinMaps) { - Debug.LogMessage(LogEventLevel.Information, "Generating markdown for device '{0}':", joinMap.Key); + this.LogInformation("Generating markdown for device '{deviceKey}':", joinMap.Key); joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey); } } @@ -208,53 +215,45 @@ namespace PepperDash.Essentials.Core.Bridges /// /// Prints the join map for a device by key /// - /// - /// - /// PrintJoinMapForDevice method - /// + /// The key of the device to print the join map for public void PrintJoinMapForDevice(string deviceKey) { var joinMap = JoinMaps[deviceKey]; if (joinMap == null) { - Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey); + this.LogInformation("Unable to find joinMap for device with key: '{deviceKey}'", deviceKey); return; } - Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key); + this.LogInformation("Join map for device '{deviceKey}' on EISC '{eiscKey}':", deviceKey, Key); joinMap.PrintJoinMapInfo(); } /// - /// Prints the join map for a device by key - /// - /// - /// - /// MarkdownJoinMapForDevice method + /// Prints the join map for a device by key in Markdown format /// + /// The key of the device to print the join map for + /// The key of the bridge to use for the Markdown output public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey) { var joinMap = JoinMaps[deviceKey]; if (joinMap == null) { - Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey); + this.LogInformation("Unable to find joinMap for device with key: '{deviceKey}'", deviceKey); return; } - Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key); + this.LogInformation("Join map for device '{deviceKey}' on EISC '{eiscKey}':", deviceKey, Key); joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey); } /// /// Used for debugging to trigger an action based on a join number and type /// - /// - /// - /// - /// - /// ExecuteJoinAction method - /// + /// The join number to execute the action for + /// The type of join (digital, analog, serial) + /// The state to pass to the action public void ExecuteJoinAction(uint join, string type, object state) { try @@ -263,68 +262,66 @@ namespace PepperDash.Essentials.Core.Bridges { case "digital": { - var uo = Eisc.BooleanOutput[join].UserObject as Action; - if (uo != null) + if (Eisc.BooleanOutput[join].UserObject is Action userObject) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); - uo(Convert.ToBoolean(state)); + this.LogVerbose("Executing Boolean Action"); + userObject(Convert.ToBoolean(state)); } else - Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); + this.LogVerbose("User Object is null. Nothing to Execute"); break; } case "analog": { - var uo = Eisc.BooleanOutput[join].UserObject as Action; - if (uo != null) + if (Eisc.BooleanOutput[join].UserObject is Action userObject) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); - uo(Convert.ToUInt16(state)); + this.LogVerbose("Executing Analog Action"); + userObject(Convert.ToUInt16(state)); } else - Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); break; + this.LogVerbose("User Object is null. Nothing to Execute"); break; } case "serial": { - var uo = Eisc.BooleanOutput[join].UserObject as Action; - if (uo != null) + if (Eisc.BooleanOutput[join].UserObject is Action userObject) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString()); - uo(Convert.ToString(state)); + this.LogVerbose("Executing Serial Action"); + userObject(Convert.ToString(state)); } else - Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); + this.LogVerbose("User Object is null. Nothing to Execute"); break; } default: { - Debug.LogMessage(LogEventLevel.Verbose, "Unknown join type. Use digital/serial/analog"); + this.LogVerbose("Unknown join type. Use digital/serial/analog"); break; } } } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + this.LogError("ExecuteJoinAction error: {message}", e.Message); + this.LogDebug(e, "Stack Trace: "); } } /// - /// Handles incoming sig changes + /// Handle incoming sig changes /// - /// - /// + /// BasicTriList device that triggered the event + /// Event arguments containing the signal information protected void Eisc_SigChange(object currentDevice, SigEventArgs args) { try { - Debug.LogMessage(LogEventLevel.Verbose, this, "EiscApiAdvanced change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); + this.LogVerbose("EiscApiAdvanced change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); var uo = args.Sig.UserObject; if (uo == null) return; - Debug.LogMessage(LogEventLevel.Debug, this, "Executing Action: {0}", uo.ToString()); + this.LogDebug("Executing Action: {0}", uo.ToString()); if (uo is Action) (uo as Action)(args.Sig.BoolValue); else if (uo is Action) @@ -334,7 +331,8 @@ namespace PepperDash.Essentials.Core.Bridges } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error in Eisc_SigChange handler: {0}", e); + this.LogError("Eisc_SigChange handler error: {message}", e.Message); + this.LogDebug(e, "Stack Trace: "); } } @@ -423,8 +421,19 @@ namespace PepperDash.Essentials.Core.Bridges } /// - /// Represents a EiscApiAdvancedFactory + /// Factory class for EiscApiAdvanced devices /// + /// + /// Supported types: + /// eiscapiadv - Create a standard EISC client over TCP/IP + /// eiscapiadvanced - Create a standard EISC client over TCP/IP + /// eiscapiadvancedserver - Create an EISC server + /// eiscapiadvancedclient - Create an EISC client + /// vceiscapiadv - Create a VC-4 EISC client + /// vceiscapiadvanced - Create a VC-4 EISC client + /// eiscapiadvudp - Create a standard EISC client over UDP + /// eiscapiadvancedudp - Create a standard EISC client over UDP + /// public class EiscApiAdvancedFactory : EssentialsDeviceFactory { /// @@ -435,9 +444,6 @@ namespace PepperDash.Essentials.Core.Bridges TypeNames = new List { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced", "eiscapiadvudp", "eiscapiadvancedudp" }; } - /// - /// BuildDevice method - /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { @@ -478,7 +484,7 @@ namespace PepperDash.Essentials.Core.Bridges { if (string.IsNullOrEmpty(controlProperties.RoomId)) { - Debug.LogMessage(LogEventLevel.Information, "Unable to build VC-4 EISC Client for device {0}. Room ID is missing or empty", dc.Key); + Debug.LogInformation("Unable to build VC-4 EISC Client for device {0}. Room ID is missing or empty", dc.Key); eisc = null; break; } From 2cc37a4e40550704a5dabe0142247adbe8628373 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 23 Dec 2025 11:06:52 -0600 Subject: [PATCH 3/3] fix: ExecuteJoinAction now uses the correct Sig collections --- .../Bridges/BridgeBase.cs | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs index 1b8e826e..070f1743 100644 --- a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs +++ b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs @@ -273,17 +273,18 @@ namespace PepperDash.Essentials.Core.Bridges } case "analog": { - if (Eisc.BooleanOutput[join].UserObject is Action userObject) + if (Eisc.UShortOutput[join].UserObject is Action userObject) { this.LogVerbose("Executing Analog Action"); userObject(Convert.ToUInt16(state)); } else - this.LogVerbose("User Object is null. Nothing to Execute"); break; + this.LogVerbose("User Object is null. Nothing to Execute"); + break; } case "serial": { - if (Eisc.BooleanOutput[join].UserObject is Action userObject) + if (Eisc.StringOutput[join].UserObject is Action userObject) { this.LogVerbose("Executing Serial Action"); userObject(Convert.ToString(state)); @@ -316,18 +317,27 @@ namespace PepperDash.Essentials.Core.Bridges { try { - this.LogVerbose("EiscApiAdvanced change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); - var uo = args.Sig.UserObject; + this.LogVerbose("EiscApiAdvanced change: {type} {number}={value}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); + var userObject = args.Sig.UserObject; - if (uo == null) return; + if (userObject == null) return; - this.LogDebug("Executing Action: {0}", uo.ToString()); - if (uo is Action) - (uo as Action)(args.Sig.BoolValue); - else if (uo is Action) - (uo as Action)(args.Sig.UShortValue); - else if (uo is Action) - (uo as Action)(args.Sig.StringValue); + + if (userObject is Action) + { + this.LogDebug("Executing Boolean Action"); + (userObject as Action)(args.Sig.BoolValue); + } + else if (userObject is Action) + { + this.LogDebug("Executing Analog Action"); + (userObject as Action)(args.Sig.UShortValue); + } + else if (userObject is Action) + { + this.LogDebug("Executing Serial Action"); + (userObject as Action)(args.Sig.StringValue); + } } catch (Exception e) { @@ -484,7 +494,7 @@ namespace PepperDash.Essentials.Core.Bridges { if (string.IsNullOrEmpty(controlProperties.RoomId)) { - Debug.LogInformation("Unable to build VC-4 EISC Client for device {0}. Room ID is missing or empty", dc.Key); + Debug.LogInformation("Unable to build VC-4 EISC Client for device {deviceKey}. Room ID is missing or empty", dc.Key); eisc = null; break; }