diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IInitializationExceptions.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IInitializationExceptions.cs
new file mode 100644
index 00000000..55ce51ab
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IInitializationExceptions.cs
@@ -0,0 +1,16 @@
+
+
+using System.Collections.Generic;
+
+namespace PepperDash.Essentials.Core.DeviceTypeInterfaces;
+
+///
+/// Defines the contract for devices that can report initialization exceptions.
+///
+public interface IInitializationExceptions
+{
+ ///
+ /// Gets a list of exceptions that occurred during the initialization of the program.
+ ///
+ List InitializationExceptions { get; }
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs
index f661a7ff..a1b81630 100644
--- a/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs
+++ b/src/PepperDash.Essentials.Core/Web/EssentialsWebApi.cs
@@ -184,6 +184,11 @@ public class EssentialsWebApi : EssentialsDevice
Name = "Get Routing Devices and TieLines",
RouteHandler = new GetRoutingDevicesAndTieLinesHandler()
},
+ new HttpCwsRoute("initializationExceptions")
+ {
+ Name = "Get Initialization Exceptions",
+ RouteHandler = new GetInitializationExceptionsRequestHandler()
+ }
};
AddRoute(routes);
@@ -296,4 +301,5 @@ public class EssentialsWebApi : EssentialsDevice
Debug.LogMessage(LogEventLevel.Information, this, new string('-', 50));
}
-}
\ No newline at end of file
+}
+
diff --git a/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetInitializationExceptionRequestHandler.cs b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetInitializationExceptionRequestHandler.cs
new file mode 100644
index 00000000..c0d77e41
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Web/RequestHandlers/GetInitializationExceptionRequestHandler.cs
@@ -0,0 +1,50 @@
+
+using Crestron.SimplSharp.WebScripting;
+using System.Collections.Generic;
+using System.Text;
+using PepperDash.Essentials.Core.DeviceTypeInterfaces;
+using PepperDash.Core.Web.RequestHandlers;
+using System.Linq;
+
+namespace PepperDash.Essentials.Core.Web.RequestHandlers;
+
+///
+/// Request handler for retrieving initialization exceptions from the control system.
+///
+public class GetInitializationExceptionsRequestHandler : WebApiBaseRequestHandler
+{
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public GetInitializationExceptionsRequestHandler() : base(true) { }
+
+ ///
+ protected override void HandleGet(HttpCwsContext context)
+ {
+ var exceptions = (Global.ControlSystem as IInitializationExceptions)?.InitializationExceptions ?? new List();
+
+ var response = Newtonsoft.Json.JsonConvert.SerializeObject(new
+ {
+ Exceptions = exceptions.Select(e => new
+ {
+ Message = e.Message,
+ StackTrace = e.StackTrace,
+ Type = e.GetType().FullName,
+ InnerException = e.InnerException != null ? new
+ {
+ Message = e.InnerException.Message,
+ StackTrace = e.InnerException.StackTrace,
+ Type = e.InnerException.GetType().FullName
+ } : null
+ }).ToList()
+ });
+
+ context.Response.StatusCode = 200;
+ context.Response.StatusDescription = "OK";
+ context.Response.ContentType = "application/json";
+ context.Response.ContentEncoding = Encoding.UTF8;
+ context.Response.Write(response, false);
+ context.Response.End();
+ }
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs
index 01859cb2..5a6b8777 100644
--- a/src/PepperDash.Essentials/ControlSystem.cs
+++ b/src/PepperDash.Essentials/ControlSystem.cs
@@ -18,6 +18,8 @@ using Timeout = Crestron.SimplSharp.Timeout;
using Serilog.Events;
using System.Threading.Tasks;
using PepperDash.Essentials.Core.Web;
+using System.Collections.Generic;
+using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials;
@@ -28,12 +30,19 @@ namespace PepperDash.Essentials;
/// This class extends and serves as the entry point for the control
/// system. It manages the initialization of devices, rooms, tie lines, and other system components. Additionally, it
/// provides methods for platform determination, configuration loading, and system teardown.
-public class ControlSystem : CrestronControlSystem, ILoadConfig
+public class ControlSystem : CrestronControlSystem, ILoadConfig, IInitializationExceptions
{
private Timer startTimer;
private ManualResetEventSlim initializeEvent;
private const long StartupTime = 500;
+ ///
+ /// List of exceptions that occurred during initialization.
+ /// This can be used to report issues with loading devices or tie lines without crashing the entire system,
+ /// which allows for partial functionality in cases where some components are misconfigured or have issues.
+ ///
+ public List InitializationExceptions { get; private set; } = new List();
+
///
/// Initializes a new instance of the class, setting up the system's global state and
/// dependencies.
@@ -457,6 +466,7 @@ public class ControlSystem : CrestronControlSystem, ILoadConfig
}
catch (Exception e)
{
+ InitializationExceptions.Add(e);
Debug.LogMessage(e, "ERROR: Creating device {deviceKey:l}. Skipping device.", args: new[] { devConf.Key });
}
}
@@ -482,12 +492,22 @@ public class ControlSystem : CrestronControlSystem, ILoadConfig
return;
}
- foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines)
+ try
{
- var newTL = tieLineConfig.GetTieLine();
- if (newTL != null)
- tlc.Add(newTL);
+
+ foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines)
+ {
+ var newTL = tieLineConfig.GetTieLine();
+ if (newTL != null)
+ tlc.Add(newTL);
+ }
}
+ catch (Exception e)
+ {
+ InitializationExceptions.Add(e);
+ Debug.LogMessage(e, "ERROR: Creating tie line. Skipping tie line.");
+ }
+
Debug.LogMessage(LogEventLevel.Information, "All Tie Lines Loaded.");
@@ -796,6 +816,7 @@ public class ControlSystem : CrestronControlSystem, ILoadConfig
}
catch (Exception ex)
{
+ InitializationExceptions.Add(ex);
Debug.LogMessage(ex, "Exception loading room {roomKey}:{roomType}", null, roomConfig.Key, roomConfig.Type);
continue;
}