diff --git a/src/PepperDash.Essentials.Core/Devices/ConfigSnippetAttribute.cs b/src/PepperDash.Essentials.Core/Devices/ConfigSnippetAttribute.cs
new file mode 100644
index 00000000..76d3640c
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Devices/ConfigSnippetAttribute.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace PepperDash.Essentials.Core
+{
+ ///
+ /// Represents a ConfigSnippetAttribute
+ ///
+ [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
+ public class ConfigSnippetAttribute : Attribute
+ {
+ private string _ConfigSnippet;
+
+ ///
+ /// Represents a configuration snippet for the device.
+ ///
+ ///
+ public ConfigSnippetAttribute(string configSnippet)
+ {
+ //Debug.LogMessage(LogEventLevel.Verbose, "Setting Config Snippet {0}", configSnippet);
+ _ConfigSnippet = configSnippet;
+ }
+
+ ///
+ /// Gets the configuration snippet for the device.
+ /// This snippet can be used in the DeviceConfig to instantiate the device.
+ ///
+ public string ConfigSnippet
+ {
+ get { return _ConfigSnippet; }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Devices/DescriptionAttribute.cs b/src/PepperDash.Essentials.Core/Devices/DescriptionAttribute.cs
new file mode 100644
index 00000000..6d4073d9
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Devices/DescriptionAttribute.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace PepperDash.Essentials.Core
+{
+ ///
+ /// Represents a description attribute for a device.
+ ///
+ [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
+ public class DescriptionAttribute : Attribute
+ {
+ private string _Description;
+
+ ///
+ /// Represents a description attribute for a device.
+ ///
+ ///
+ public DescriptionAttribute(string description)
+ {
+ //Debug.LogMessage(LogEventLevel.Verbose, "Setting Description: {0}", description);
+ _Description = description;
+ }
+
+ ///
+ /// Gets the description for the device.
+ ///
+ public string Description
+ {
+ get { return _Description; }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs b/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs
index fd116aed..7572835e 100644
--- a/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs
+++ b/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs
@@ -1,26 +1,38 @@
-using Crestron.SimplSharp;
-using Crestron.SimplSharpPro;
-using PepperDash.Core;
-using Serilog.Events;
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
+using Crestron.SimplSharp;
+using Crestron.SimplSharpPro;
+using PepperDash.Core;
+using Serilog.Events;
namespace PepperDash.Essentials.Core
{
+ ///
+ /// Manages the devices in the system
+ ///
public static class DeviceManager
{
+ ///
+ /// Raised when all devices have been activated
+ ///
public static event EventHandler AllDevicesActivated;
+
+ ///
+ /// Raised when all devices have been registered
+ ///
public static event EventHandler AllDevicesRegistered;
+
+ ///
+ /// Raised when all devices have been initialized
+ ///
public static event EventHandler AllDevicesInitialized;
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
- private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
- //public static List Devices { get { return _Devices; } }
- //static List _Devices = new List();
+ private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
private static readonly Dictionary Devices = new Dictionary(StringComparer.OrdinalIgnoreCase);
@@ -74,7 +86,7 @@ namespace PepperDash.Essentials.Core
foreach (var d in Devices.Values)
{
try
- {
+ {
if (d is Device)
(d as Device).PreActivate();
}
@@ -188,27 +200,6 @@ namespace PepperDash.Essentials.Core
}
}
- //static void ListMethods(string devKey)
- //{
- // var dev = GetDeviceForKey(devKey);
- // if(dev != null)
- // {
- // var type = dev.GetType().GetType();
- // var methods = type.GetMethods(BindingFlags.Public|BindingFlags.Instance);
- // var sb = new StringBuilder();
- // sb.AppendLine(string.Format("{2} methods on [{0}] ({1}):", dev.Key, type.Name, methods.Length));
- // foreach (var m in methods)
- // {
- // sb.Append(string.Format("{0}(", m.Name));
- // var pars = m.GetParameters();
- // foreach (var p in pars)
- // sb.Append(string.Format("({1}){0} ", p.Name, p.ParameterType.Name));
- // sb.AppendLine(")");
- // }
- // CrestronConsole.ConsoleCommandResponse(sb.ToString());
- // }
- //}
-
private static void ListDevices(string s)
{
Debug.LogMessage(LogEventLevel.Information, "{0} Devices registered with Device Manager:", Devices.Count);
@@ -397,6 +388,25 @@ namespace PepperDash.Essentials.Core
return null;
}
+ ///
+ /// GetDeviceForKey method
+ ///
+ ///
+ public static T GetDeviceForKey(string key)
+ {
+ //return _Devices.FirstOrDefault(d => d.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
+ if (key == null || !Devices.ContainsKey(key))
+ return default;
+
+ if (!(Devices[key] is T))
+ {
+ Debug.LogMessage(LogEventLevel.Error, "Device with key '{0}' is not of type '{1}'", key, typeof(T).Name);
+ return default;
+ }
+
+ return (T)Devices[key];
+ }
+
///
/// Console handler that simulates com port data receive
///
diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs
index 2fcbf1a4..59fba681 100644
--- a/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs
+++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs
@@ -1,12 +1,6 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using Crestron.SimplSharp;
-using System.Reflection;
-
+using System.Threading.Tasks;
using PepperDash.Core;
-using PepperDash.Essentials.Core.Config;
using Serilog.Events;
namespace PepperDash.Essentials.Core
@@ -17,9 +11,16 @@ namespace PepperDash.Essentials.Core
[Description("The base Essentials Device Class")]
public abstract class EssentialsDevice : Device
{
+ ///
+ /// Event raised when the device is initialized.
+ ///
public event EventHandler Initialized;
private bool _isInitialized;
+
+ ///
+ /// Gets a value indicating whether the device is initialized.
+ ///
public bool IsInitialized
{
get { return _isInitialized; }
@@ -36,12 +37,21 @@ namespace PepperDash.Essentials.Core
}
}
+ ///
+ /// Initializes a new instance of the EssentialsDevice class.
+ ///
+ /// The unique identifier for the device.
protected EssentialsDevice(string key)
: base(key)
{
SubscribeToActivateComplete();
}
+ ///
+ /// Initializes a new instance of the EssentialsDevice class.
+ ///
+ /// The unique identifier for the device.
+ /// The name of the device.
protected EssentialsDevice(string key, string name)
: base(key, name)
{
@@ -55,7 +65,7 @@ namespace PepperDash.Essentials.Core
private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs)
{
- CrestronInvoke.BeginInvoke((o) =>
+ Task.Run(() =>
{
try
{
@@ -90,138 +100,4 @@ namespace PepperDash.Essentials.Core
}
}
-
- [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
- public class DescriptionAttribute : Attribute
- {
- private string _Description;
-
- public DescriptionAttribute(string description)
- {
- //Debug.LogMessage(LogEventLevel.Verbose, "Setting Description: {0}", description);
- _Description = description;
- }
-
- public string Description
- {
- get { return _Description; }
- }
- }
-
- [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
- ///
- /// Represents a ConfigSnippetAttribute
- ///
- public class ConfigSnippetAttribute : Attribute
- {
- private string _ConfigSnippet;
-
- public ConfigSnippetAttribute(string configSnippet)
- {
- //Debug.LogMessage(LogEventLevel.Verbose, "Setting Config Snippet {0}", configSnippet);
- _ConfigSnippet = configSnippet;
- }
-
- public string ConfigSnippet
- {
- get { return _ConfigSnippet; }
- }
- }
-
- ///
- /// Devices the basic needs for a Device Factory
- ///
- public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice
- {
- #region IDeviceFactory Members
-
- ///
- /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
- ///
- public List TypeNames { get; protected set; }
-
- ///
- /// LoadTypeFactories method
- ///
- public void LoadTypeFactories()
- {
- foreach (var typeName in TypeNames)
- {
- //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
- var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
- string description = descriptionAttribute[0].Description;
- var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
- DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
- }
- }
-
- ///
- /// The method that will build the device
- ///
- /// The device config
- /// An instance of the device
- public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
-
- #endregion
- }
-
- public abstract class ProcessorExtensionDeviceFactory : IProcessorExtensionDeviceFactory where T: EssentialsDevice
- {
- #region IProcessorExtensionDeviceFactory Members
-
- ///
- /// Gets or sets the TypeNames
- ///
- public List TypeNames { get; protected set; }
-
- ///
- /// LoadFactories method
- ///
- public void LoadFactories()
- {
- foreach (var typeName in TypeNames)
- {
- //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
- var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
- string description = descriptionAttribute[0].Description;
- var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
- ProcessorExtensionDeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
- }
- }
-
- ///
- /// The method that will build the device
- ///
- /// The device config
- /// An instance of the device
- public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
-
- #endregion
-
- }
-
- ///
- /// Devices the basic needs for a Device Factory
- ///
- public abstract class EssentialsPluginDeviceFactory : EssentialsDeviceFactory, IPluginDeviceFactory where T : EssentialsDevice
- {
- ///
- /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
- ///
- public string MinimumEssentialsFrameworkVersion { get; protected set; }
- }
-
- public abstract class EssentialsPluginDevelopmentDeviceFactory : EssentialsDeviceFactory, IPluginDevelopmentDeviceFactory where T : EssentialsDevice
- {
- ///
- /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
- ///
- public string MinimumEssentialsFrameworkVersion { get; protected set; }
-
- ///
- /// Gets or sets the DevelopmentEssentialsFrameworkVersions
- ///
- public List DevelopmentEssentialsFrameworkVersions { get; protected set; }
- }
-
}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs
new file mode 100644
index 00000000..3ac326bf
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using PepperDash.Essentials.Core.Config;
+
+namespace PepperDash.Essentials.Core
+{
+ ///
+ /// Provides the basic needs for a Device Factory
+ ///
+ public abstract class EssentialsDeviceFactory : IDeviceFactory where T : EssentialsDevice
+ {
+ ///
+ public Type FactoryType => typeof(T);
+
+ ///
+ /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
+ ///
+ public List TypeNames { get; protected set; }
+
+ ///
+ /// The method that will build the device
+ ///
+ /// The device config
+ /// An instance of the device
+ public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
+ }
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsPluginDevelopmentDeviceFactory.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsPluginDevelopmentDeviceFactory.cs
new file mode 100644
index 00000000..62864551
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Devices/EssentialsPluginDevelopmentDeviceFactory.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace PepperDash.Essentials.Core
+{
+ public abstract class EssentialsPluginDevelopmentDeviceFactory : EssentialsDeviceFactory, IPluginDevelopmentDeviceFactory where T : EssentialsDevice
+ {
+ ///
+ /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
+ ///
+ public string MinimumEssentialsFrameworkVersion { get; protected set; }
+
+ ///
+ /// Gets or sets the DevelopmentEssentialsFrameworkVersions
+ ///
+ public List DevelopmentEssentialsFrameworkVersions { get; protected set; }
+ }
+
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsPluginDeviceFactory.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsPluginDeviceFactory.cs
new file mode 100644
index 00000000..7a891905
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Devices/EssentialsPluginDeviceFactory.cs
@@ -0,0 +1,14 @@
+namespace PepperDash.Essentials.Core
+{
+ ///
+ /// Devices the basic needs for a Device Factory
+ ///
+ public abstract class EssentialsPluginDeviceFactory : EssentialsDeviceFactory, IPluginDeviceFactory where T : EssentialsDevice
+ {
+ ///
+ /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
+ ///
+ public string MinimumEssentialsFrameworkVersion { get; protected set; }
+ }
+
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Devices/ProcessorExtensionDeviceFactory.cs b/src/PepperDash.Essentials.Core/Devices/ProcessorExtensionDeviceFactory.cs
new file mode 100644
index 00000000..469d18ec
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Devices/ProcessorExtensionDeviceFactory.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using PepperDash.Essentials.Core.Config;
+
+namespace PepperDash.Essentials.Core
+{
+ public abstract class ProcessorExtensionDeviceFactory : IProcessorExtensionDeviceFactory where T : EssentialsDevice
+ {
+ #region IProcessorExtensionDeviceFactory Members
+
+ ///
+ /// Gets or sets the TypeNames
+ ///
+ public List TypeNames { get; protected set; }
+
+ ///
+ /// LoadFactories method
+ ///
+ public void LoadFactories()
+ {
+ foreach (var typeName in TypeNames)
+ {
+ //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
+ var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
+ string description = descriptionAttribute[0].Description;
+ var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
+ ProcessorExtensionDeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
+ }
+ }
+
+ ///
+ /// The method that will build the device
+ ///
+ /// The device config
+ /// An instance of the device
+ public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
+
+ #endregion
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs
index 5c8d4dec..08aa67cf 100644
--- a/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs
+++ b/src/PepperDash.Essentials.Core/Factory/DeviceFactory.cs
@@ -1,123 +1,162 @@
-using Crestron.SimplSharp;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
using System.Reflection;
+using Crestron.SimplSharp;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using Serilog.Events;
-using System;
-using System.Collections.Generic;
-using System.Linq;
namespace PepperDash.Essentials.Core
{
///
- /// Wrapper class for device factory information
- ///
- public class DeviceFactoryWrapper
- {
- ///
- /// Gets or sets the device type
- ///
- public Type Type { get; set; }
-
- ///
- /// Gets or sets the Description
- ///
- public string Description { get; set; }
-
- ///
- /// Gets or sets the factory method for creating devices
- ///
- public Func FactoryMethod { get; set; }
-
- ///
- /// Initializes a new instance of the DeviceFactoryWrapper class
- ///
- public DeviceFactoryWrapper()
- {
- Type = null;
- Description = "Not Available";
- }
- }
-
- ///
- /// Represents a DeviceFactory
+ /// Provides functionality for managing and registering device factories, including loading plugin-based factories and
+ /// retrieving devices based on their configuration.
///
+ /// The class is responsible for discovering and registering device factories
+ /// from plugins, as well as providing methods to retrieve devices based on their configuration. It maintains a
+ /// collection of factory methods that are keyed by device type names, allowing for extensibility through plugins. This
+ /// class also handles metadata retrieval and secret management for device configurations.
public class DeviceFactory
{
///
- /// Initializes a new instance of the DeviceFactory class and loads all device type factories
+ /// Initializes a new instance of the class and loads all available device factories
+ /// from the current assembly.
///
+ /// This constructor scans the executing assembly for types that implement the interface and are not abstract or interfaces. For each valid type, an instance is
+ /// created and passed to the LoadDeviceFactories method for further processing. If a type cannot be
+ /// instantiated, an informational log message is generated, and the process continues with the remaining
+ /// types.
public DeviceFactory()
{
- var assy = Assembly.GetExecutingAssembly();
- PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
+ var programAssemblies = Directory.GetFiles(InitialParametersClass.ProgramDirectory.ToString(), "*.dll");
- var types = assy.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
-
- if (types != null)
+ foreach (var assembly in programAssemblies)
{
+ try
+ {
+ Assembly.LoadFrom(assembly);
+ }
+ catch (Exception e)
+ {
+ Debug.LogError("Unable to load assembly: {assemblyName} - {message}", assembly, e.Message);
+ }
+ }
+
+ var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
+
+ // Loop through all loaded assemblies that contain at least 1 type that implements IDeviceFactory
+ foreach (var assembly in loadedAssemblies)
+ {
+ Debug.LogDebug("loaded assembly: {assemblyName}", assembly.GetName().Name);
+
+ PluginLoader.AddLoadedAssembly(assembly.GetName().Name, assembly);
+
+ var types = assembly.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
+
+ if (types == null || !types.Any())
+ {
+ Debug.LogDebug("No DeviceFactory types found in assembly: {assemblyName}", assembly.GetName().Name);
+ continue;
+ }
+
foreach (var type in types)
{
try
{
var factory = (IDeviceFactory)Activator.CreateInstance(type);
- factory.LoadTypeFactories();
+ LoadDeviceFactories(factory);
}
catch (Exception e)
{
- Debug.LogMessage(LogEventLevel.Information, "Unable to load type: '{1}' DeviceFactory: {0}", e, type.Name);
+ Debug.LogError("Unable to load type: '{message}' DeviceFactory: {type}", e.Message, type.Name);
}
}
+
}
}
- ///
- /// A dictionary of factory methods, keyed by config types, added by plugins.
- /// These methods are looked up and called by GetDevice in this class.
- ///
- static Dictionary FactoryMethods =
+ ///
+ /// Loads device factories from the specified plugin device factory and registers them for use.
+ ///
+ /// This method retrieves metadata from the provided , including
+ /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
+ /// names are converted to lowercase for registration.
+ /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered.
+ private static void LoadDeviceFactories(IDeviceFactory deviceFactory)
+ {
+ foreach (var typeName in deviceFactory.TypeNames)
+ {
+ //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
+ var descriptionAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
+ string description = descriptionAttribute[0].Description;
+ var snippetAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
+ AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
+ }
+ }
+
+ ///
+ /// A dictionary of factory methods, keyed by config types, added by plugins.
+ /// These methods are looked up and called by GetDevice in this class.
+ ///
+ private static readonly Dictionary FactoryMethods =
new Dictionary(StringComparer.OrdinalIgnoreCase);
- ///
- /// Adds a plugin factory method
- ///
- ///
- ///
- public static void AddFactoryForType(string typeName, Func method)
- {
- //Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
- DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
- }
+ ///
+ /// Registers a factory method for creating instances of a specific type.
+ ///
+ /// This method associates a type name with a factory method, allowing instances of the type to
+ /// be created dynamically. The factory method is stored internally and can be retrieved or invoked as
+ /// needed.
+ /// The name of the type for which the factory method is being registered. This value cannot be null or empty.
+ /// A delegate that defines the factory method. The delegate takes a parameter and
+ /// returns an instance of .
+ public static void AddFactoryForType(string typeName, Func method)
+ {
+ FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method });
+ }
+ ///
+ /// Registers a factory method for creating instances of a specific device type.
+ ///
+ /// If a factory method for the specified already exists, the method
+ /// will not overwrite it and will log an informational message instead.
+ /// The unique name of the device type. This serves as the key for identifying the factory method.
+ /// A brief description of the device type. This is used for informational purposes.
+ /// The of the device being registered. This represents the runtime type of the device.
+ /// A factory method that takes a as input and returns an instance of .
public static void AddFactoryForType(string typeName, string description, Type Type, Func method)
{
- //Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
-
- if(FactoryMethods.ContainsKey(typeName))
+ if (FactoryMethods.ContainsKey(typeName))
{
- Debug.LogMessage(LogEventLevel.Information, "Unable to add type: '{0}'. Already exists in DeviceFactory", typeName);
+ Debug.LogInformation("Unable to add type: '{typeName}'. Already exists in DeviceFactory", typeName);
return;
}
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
- DeviceFactory.FactoryMethods.Add(typeName, wrapper);
+
+ FactoryMethods.Add(typeName, wrapper);
}
private static void CheckForSecrets(IEnumerable obj)
{
foreach (var prop in obj.Where(prop => prop.Value as JObject != null))
{
- if (prop.Name.ToLower() == "secret")
+ if (prop.Name.Equals("secret", StringComparison.CurrentCultureIgnoreCase))
{
var secret = GetSecret(prop.Children().First().ToObject());
- //var secret = GetSecret(JsonConvert.DeserializeObject(prop.Children().First().ToString()));
+
prop.Parent.Replace(secret);
}
- var recurseProp = prop.Value as JObject;
- if (recurseProp == null) return;
+
+ if (!(prop.Value is JObject recurseProp)) return;
+
CheckForSecrets(recurseProp.Properties());
}
}
@@ -127,66 +166,70 @@ namespace PepperDash.Essentials.Core
var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider);
if (secretProvider == null) return null;
var secret = secretProvider.GetSecret(data.Key);
- if (secret != null) return (string) secret.Value;
+ if (secret != null) return (string)secret.Value;
Debug.LogMessage(LogEventLevel.Debug,
"Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider",
data.Provider, data.Key);
- return String.Empty;
+ return string.Empty;
}
///
- /// The factory method for Core "things". Also iterates the Factory methods that have
- /// been loaded from plugins
- ///
- ///
- ///
- ///
- /// GetDevice method
+ /// Creates and returns a device instance based on the provided .
///
+ /// This method attempts to create a device using the type specified in the
+ /// parameter. If the type corresponds to a registered factory method, the device is created and returned. If the
+ /// type is unrecognized or an exception occurs, the method logs the error and returns .
+ /// The configuration object containing the key, name, type, and properties required to create the device.
+ /// An instance of a device that implements , or if the device type is
+ /// not recognized or an error occurs during creation.
public static IKeyed GetDevice(DeviceConfig dc)
{
try
{
- Debug.LogMessage(LogEventLevel.Information, "Loading '{0}' from Essentials Core", dc.Type);
-
var localDc = new DeviceConfig(dc);
var key = localDc.Key;
var name = localDc.Name;
var type = localDc.Type;
var properties = localDc.Properties;
- //var propRecurse = properties;
var typeName = localDc.Type.ToLower();
-
- var jObject = properties as JObject;
- if (jObject != null)
+ if (properties is JObject jObject)
{
var jProp = jObject.Properties();
CheckForSecrets(jProp);
}
- Debug.LogMessage(LogEventLevel.Verbose, "typeName = {0}", typeName);
- // Check for types that have been added by plugin dlls.
- return !FactoryMethods.ContainsKey(typeName) ? null : FactoryMethods[typeName].FactoryMethod(localDc);
+ if (!FactoryMethods.TryGetValue(typeName, out var wrapper))
+ {
+ Debug.LogWarning("Device type '{typeName}' not found in DeviceFactory", typeName);
+ return null;
+ }
+
+ Debug.LogInformation("Loading '{type}' from {assemblyName}", typeName, wrapper.Type.Assembly.FullName);
+
+ // Check for types that have been added by plugin dlls.
+ return wrapper.FactoryMethod(localDc);
}
catch (Exception ex)
{
- Debug.LogMessage(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message);
+ Debug.LogError(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message);
return null;
}
}
///
- /// Prints the type names and associated metadata from the FactoryMethods collection.
- ///
- ///
- ///
- /// GetDeviceFactoryTypes method
+ /// Displays a list of device factory types that match the specified filter.
///
+ /// The method outputs the filtered list of device factory types to the console, including their
+ /// key, type, and description. If a type is not specified by the plugin, it will be displayed as "Not Specified by
+ /// Plugin."
+ /// A string used to filter the device factory types by their keys. If the filter is null or empty, all device
+ /// factory types are displayed.
public static void GetDeviceFactoryTypes(string filter)
{
var types = !string.IsNullOrEmpty(filter)
@@ -212,16 +255,18 @@ namespace PepperDash.Essentials.Core
}
}
- ///
- /// Returns the device factory dictionary
- ///
- ///
- ///
- public static Dictionary GetDeviceFactoryDictionary(string filter)
- {
- return string.IsNullOrEmpty(filter)
- ? FactoryMethods
- : FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value);
- }
+ ///
+ /// Retrieves a dictionary of device factory wrappers, optionally filtered by a specified string.
+ ///
+ /// A string used to filter the dictionary keys. Only entries with keys containing the specified filter will be
+ /// included. If or empty, all entries are returned.
+ /// A dictionary where the keys are strings representing device identifiers and the values are instances. The dictionary may be empty if no entries match the filter.
+ public static Dictionary GetDeviceFactoryDictionary(string filter)
+ {
+ return string.IsNullOrEmpty(filter)
+ ? FactoryMethods
+ : FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value);
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/PepperDash.Essentials.Core/Factory/DeviceFactoryWrapper.cs b/src/PepperDash.Essentials.Core/Factory/DeviceFactoryWrapper.cs
new file mode 100644
index 00000000..dc1f72d9
--- /dev/null
+++ b/src/PepperDash.Essentials.Core/Factory/DeviceFactoryWrapper.cs
@@ -0,0 +1,43 @@
+
+
+using System;
+using PepperDash.Core;
+using PepperDash.Essentials.Core.Config;
+
+namespace PepperDash.Essentials.Core
+{
+ ///
+ /// Wraps a device factory, providing metadata and a factory method for creating devices.
+ ///
+ public class DeviceFactoryWrapper
+ {
+ ///
+ /// Gets or sets the type associated with the current instance.
+ ///
+ public Type Type { get; set; }
+
+ ///
+ /// Gets or sets the description associated with the object.
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// Gets or sets the factory method used to create an instance based on the provided .
+ ///
+ /// The factory method allows customization of how instances are created for
+ /// specific inputs. Ensure the delegate is not null before invoking it.
+ public Func FactoryMethod { get; set; }
+
+ ///
+ /// Initializes a new instance of the class with default values.
+ ///
+ /// The property is initialized to , and the property is set to "Not Available".
+ public DeviceFactoryWrapper()
+ {
+ Type = null;
+ Description = "Not Available";
+ }
+ }
+}
diff --git a/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs b/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs
index 31ff95d2..b267edf6 100644
--- a/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs
+++ b/src/PepperDash.Essentials.Core/Factory/IDeviceFactory.cs
@@ -1,4 +1,8 @@
-namespace PepperDash.Essentials.Core
+using System;
+using System.Collections.Generic;
+using PepperDash.Essentials.Core.Config;
+
+namespace PepperDash.Essentials.Core
{
///
/// Defines the contract for IDeviceFactory
@@ -6,8 +10,21 @@
public interface IDeviceFactory
{
///
- /// Loads all the types to the DeviceFactory
+ /// Gets the type of the factory associated with the current instance.
///
- void LoadTypeFactories();
+ Type FactoryType { get; }
+
+ ///
+ /// Gets a list of type names associated with the current plugin.
+ ///
+ List TypeNames { get; }
+
+ ///
+ /// Builds and returns an instance based on the provided configuration.
+ ///
+ /// The configuration settings used to initialize the device. This parameter cannot be null.
+ /// An instance configured according to the specified .
+ EssentialsDevice BuildDevice(DeviceConfig deviceConfig);
}
}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs b/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs
index ec823007..caad4b57 100644
--- a/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs
+++ b/src/PepperDash.Essentials.Core/Plugins/IPluginDeviceFactory.cs
@@ -1,5 +1,5 @@
+using System;
using System.Collections.Generic;
-using PepperDash.Core;
namespace PepperDash.Essentials.Core
@@ -16,8 +16,16 @@ namespace PepperDash.Essentials.Core
}
+ ///
+ /// Defines a class that is capable of loading custom plugin device types for development purposes
+ ///
+ [Obsolete("This interface is obsolete and will be removed in a future version." +
+ " Use IPluginDeviceFactory instead and check Global.IsRunningDevelopmentVersion to determine if the Essentials framework is in development mode.")]
public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory
{
+ ///
+ /// Gets a list of all the development versions of the Essentials framework that are supported by this factory.
+ ///
List DevelopmentEssentialsFrameworkVersions { get; }
}
}
diff --git a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs
index a74ba16a..8978c752 100644
--- a/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs
+++ b/src/PepperDash.Essentials.Core/Plugins/PluginLoader.cs
@@ -1,15 +1,13 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
-using Crestron.SimplSharp;
-// using Crestron.SimplSharp.CrestronIO;
using System.Reflection;
-
+using Crestron.SimplSharp;
+using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using Serilog.Events;
-using Newtonsoft.Json;
-using System.IO;
namespace PepperDash.Essentials
{
@@ -28,10 +26,19 @@ namespace PepperDash.Essentials
///
static List LoadedPluginFolderAssemblies;
+ ///
+ /// The assembly for the Essentials Framework
+ ///
public static LoadedAssembly EssentialsAssembly { get; private set; }
+ ///
+ /// The assembly for the PepperDash Core
+ ///
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
+ ///
+ /// The list of assemblies loaded from the Essentials plugins folder
+ ///
public static List EssentialsPluginAssemblies { get; private set; }
///
@@ -131,7 +138,7 @@ namespace PepperDash.Essentials
///
/// Loads an assembly via Reflection and adds it to the list of loaded assemblies
///
- ///
+ ///
static LoadedAssembly LoadAssembly(string filePath)
{
try
@@ -153,7 +160,8 @@ namespace PepperDash.Essentials
}
return null;
- } catch(Exception ex)
+ }
+ catch (Exception ex)
{
Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath);
return null;
@@ -212,6 +220,20 @@ namespace PepperDash.Essentials
}
}
+ ///
+ /// Associates the specified assembly with the given name in the loaded assemblies collection.
+ ///
+ /// If an assembly with the specified name already exists in the loaded assemblies collection,
+ /// this method updates its associated assembly. If no matching name is found, the method does nothing.
+ /// The name used to identify the assembly. This value is case-sensitive and must not be null or empty.
+ /// The assembly to associate with the specified name. This value must not be null.
+ public static void AddLoadedAssembly(string name, Assembly assembly)
+ {
+ var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name));
+
+ loadedAssembly?.SetAssembly(assembly);
+ }
+
///
/// Used by console command to report the currently loaded assemblies and versions
///
@@ -402,7 +424,7 @@ namespace PepperDash.Essentials
try
{
var assy = loadedAssembly.Assembly;
- Type[] types = {};
+ Type[] types = { };
try
{
types = assy.GetTypes();
@@ -419,8 +441,8 @@ namespace PepperDash.Essentials
foreach (var type in types)
{
try
- {
- if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
+ {
+ if (typeof(IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
{
var plugin =
(IPluginDeviceFactory)Activator.CreateInstance(type);
@@ -454,37 +476,61 @@ namespace PepperDash.Essentials
}
///
- /// Loads a
+ /// Loads a custom plugin and performs a dependency check to ensure compatibility with the required Essentials
+ /// framework version.
///
- ///
- ///
- static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly)
+ /// This method verifies that the plugin meets the minimum required Essentials framework version
+ /// before loading it. If the plugin fails the dependency check, it is skipped, and a log message is generated. If
+ /// the plugin passes the check, it is loaded, and its type factories are initialized.
+ /// The plugin to be loaded, implementing the interface. If the plugin also
+ /// implements , additional checks for development versions are
+ /// performed.
+ /// The assembly associated with the plugin being loaded. This is used for logging and tracking purposes.
+ static void LoadCustomPlugin(IPluginDeviceFactory pluginDeviceFactory, LoadedAssembly loadedAssembly)
{
- var developmentPlugin = plugin as IPluginDevelopmentDeviceFactory;
-
- var passed = developmentPlugin != null ? Global.IsRunningDevelopmentVersion
- (developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
- : Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
+ var passed = pluginDeviceFactory is IPluginDevelopmentDeviceFactory developmentPlugin ? Global.IsRunningDevelopmentVersion
+ (developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
+ : Global.IsRunningMinimumVersionOrHigher(pluginDeviceFactory.MinimumEssentialsFrameworkVersion);
if (!passed)
{
Debug.LogMessage(LogEventLevel.Information,
"\r\n********************\r\n\tPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n********************",
- plugin.MinimumEssentialsFrameworkVersion, loadedAssembly.Name);
+ pluginDeviceFactory.MinimumEssentialsFrameworkVersion, loadedAssembly.Name);
return;
}
else
{
- Debug.LogMessage(LogEventLevel.Information, "Passed plugin passed dependency check (required version {0})", plugin.MinimumEssentialsFrameworkVersion);
+ Debug.LogMessage(LogEventLevel.Information, "Passed plugin passed dependency check (required version {0})", pluginDeviceFactory.MinimumEssentialsFrameworkVersion);
}
- Debug.LogMessage(LogEventLevel.Information, "Loading plugin: {0}", loadedAssembly.Name);
- plugin.LoadTypeFactories();
+ Debug.LogMessage(LogEventLevel.Information, "Loading plugin factory: {0}", loadedAssembly.Name);
- if(!EssentialsPluginAssemblies.Contains(loadedAssembly))
+ LoadDeviceFactories(pluginDeviceFactory);
+
+ if (!EssentialsPluginAssemblies.Contains(loadedAssembly))
EssentialsPluginAssemblies.Add(loadedAssembly);
}
+ ///
+ /// Loads device factories from the specified plugin device factory and registers them for use.
+ ///
+ /// This method retrieves metadata from the provided , including
+ /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
+ /// names are converted to lowercase for registration.
+ /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered.
+ private static void LoadDeviceFactories(IPluginDeviceFactory deviceFactory)
+ {
+ foreach (var typeName in deviceFactory.TypeNames)
+ {
+ //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
+ var descriptionAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
+ string description = descriptionAttribute[0].Description;
+ var snippetAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
+ DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
+ }
+ }
+
///
/// Loads a a custom plugin via the legacy method
///
@@ -567,13 +613,30 @@ namespace PepperDash.Essentials
///
public class LoadedAssembly
{
+ ///
+ /// Gets the name of the assembly
+ ///
[JsonProperty("name")]
public string Name { get; private set; }
+
+ ///
+ /// Gets the version of the assembly
+ ///
[JsonProperty("version")]
public string Version { get; private set; }
+
+ ///
+ /// Gets the assembly
+ ///
[JsonIgnore]
public Assembly Assembly { get; private set; }
+ ///
+ /// Initializes a new instance of the LoadedAssembly class
+ ///
+ /// The name of the assembly
+ /// The version of the assembly
+ /// The assembly
public LoadedAssembly(string name, string version, Assembly assembly)
{
Name = name;
diff --git a/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs b/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs
index 7656b277..a0fa0c9f 100644
--- a/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs
+++ b/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs
@@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Devices.Common
{
var assy = Assembly.GetExecutingAssembly();
PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
-
+
var types = assy.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
if (types != null)
@@ -29,7 +29,7 @@ namespace PepperDash.Essentials.Devices.Common
try
{
var factory = (IDeviceFactory)Activator.CreateInstance(type);
- factory.LoadTypeFactories();
+ LoadDeviceFactories(factory);
}
catch (Exception e)
{
@@ -38,5 +38,24 @@ namespace PepperDash.Essentials.Devices.Common
}
}
}
+
+ ///
+ /// Loads device factories from the specified plugin device factory and registers them for use.
+ ///
+ /// This method retrieves metadata from the provided , including
+ /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
+ /// names are converted to lowercase for registration.
+ /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered.
+ private static void LoadDeviceFactories(IDeviceFactory deviceFactory)
+ {
+ foreach (var typeName in deviceFactory.TypeNames)
+ {
+ //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
+ var descriptionAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
+ string description = descriptionAttribute[0].Description;
+ var snippetAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
+ Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlFactory.cs b/src/PepperDash.Essentials.MobileControl/MobileControlFactory.cs
index 7d4b0340..ce40aa64 100644
--- a/src/PepperDash.Essentials.MobileControl/MobileControlFactory.cs
+++ b/src/PepperDash.Essentials.MobileControl/MobileControlFactory.cs
@@ -1,8 +1,8 @@
-using PepperDash.Core;
-using PepperDash.Essentials.Core;
-using System;
+using System;
using System.Linq;
using System.Reflection;
+using PepperDash.Core;
+using PepperDash.Essentials.Core;
namespace PepperDash.Essentials
{
@@ -30,7 +30,7 @@ namespace PepperDash.Essentials
{
var factory = (IDeviceFactory)Activator.CreateInstance(type);
- factory.LoadTypeFactories();
+ LoadDeviceFactories(factory);
}
catch (Exception ex)
{
@@ -38,5 +38,24 @@ namespace PepperDash.Essentials
}
}
}
+
+ ///
+ /// Loads device factories from the specified plugin device factory and registers them for use.
+ ///
+ /// This method retrieves metadata from the provided , including
+ /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
+ /// names are converted to lowercase for registration.
+ /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered.
+ private static void LoadDeviceFactories(IDeviceFactory deviceFactory)
+ {
+ foreach (var typeName in deviceFactory.TypeNames)
+ {
+ //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
+ var descriptionAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
+ string description = descriptionAttribute[0].Description;
+ var snippetAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
+ Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
+ }
+ }
}
}
diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs
index 56615017..3da56d8b 100644
--- a/src/PepperDash.Essentials/ControlSystem.cs
+++ b/src/PepperDash.Essentials/ControlSystem.cs
@@ -1,7 +1,9 @@
+using System;
+using System.Linq;
+using System.Reflection;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
-using System.Reflection;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.CrestronThread;
using Crestron.SimplSharpPro.Diagnostics;
@@ -9,12 +11,9 @@ using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
-using PepperDash.Essentials.Core.DeviceTypeInterfaces;
-using PepperDash.Essentials.Core.Web;
-using System;
-using System.Linq;
-using Serilog.Events;
using PepperDash.Essentials.Core.Routing;
+using PepperDash.Essentials.Core.Web;
+using Serilog.Events;
namespace PepperDash.Essentials
{
@@ -46,22 +45,22 @@ namespace PepperDash.Essentials
// AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
}
- private System.Reflection.Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
+ private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{
- var assemblyName = new System.Reflection.AssemblyName(args.Name).Name;
+ var assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName == "PepperDash_Core")
{
- return System.Reflection.Assembly.LoadFrom("PepperDashCore.dll");
+ return Assembly.LoadFrom("PepperDashCore.dll");
}
if (assemblyName == "PepperDash_Essentials_Core")
{
- return System.Reflection.Assembly.LoadFrom("PepperDash.Essentials.Core.dll");
+ return Assembly.LoadFrom("PepperDash.Essentials.Core.dll");
}
if (assemblyName == "Essentials Devices Common")
{
- return System.Reflection.Assembly.LoadFrom("PepperDash.Essentials.Devices.Common.dll");
+ return Assembly.LoadFrom("PepperDash.Essentials.Devices.Common.dll");
}
return null;
@@ -79,7 +78,7 @@ namespace PepperDash.Essentials
if (preventInitializationComplete)
{
Debug.LogMessage(LogEventLevel.Debug, "******************* InitializeSystem() Entering **********************");
-
+
_startTimer = new CTimer(StartSystem, preventInitializationComplete, StartupTime);
_initializeEvent = new CEvent(true, false);
DeviceManager.AllDevicesRegistered += (o, a) =>
@@ -88,7 +87,7 @@ namespace PepperDash.Essentials
};
_initializeEvent.Wait(30000);
Debug.LogMessage(LogEventLevel.Debug, "******************* InitializeSystem() Exiting **********************");
-
+
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
}
else
@@ -99,7 +98,7 @@ namespace PepperDash.Essentials
private void StartSystem(object preventInitialization)
{
- Debug.SetErrorLogMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose);
+ Debug.SetErrorLogMinimumDebugLevel(LogEventLevel.Verbose);
DeterminePlatform();
@@ -201,8 +200,8 @@ namespace PepperDash.Essentials
{
userFolder = "User";
nvramFolder = "Nvram";
- }
-
+ }
+
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{version:l} on {processorSeries:l} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series");
//Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{0} on {1} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series");
@@ -210,8 +209,8 @@ namespace PepperDash.Essentials
if (Directory.Exists(Global.ApplicationDirectoryPathPrefix + dirSeparator + userFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
{
-
- Debug.LogMessage(LogEventLevel.Information, "{userFolder:l}/program{applicationNumber} directory found", userFolder, InitialParametersClass.ApplicationNumber);
+
+ Debug.LogMessage(LogEventLevel.Information, "{userFolder:l}/program{applicationNumber} directory found", userFolder, InitialParametersClass.ApplicationNumber);
filePathPrefix = directoryPrefix + dirSeparator + userFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
@@ -220,7 +219,7 @@ namespace PepperDash.Essentials
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
{
Debug.LogMessage(LogEventLevel.Information, "{nvramFolder:l}/program{applicationNumber} directory found", nvramFolder, InitialParametersClass.ApplicationNumber);
-
+
filePathPrefix = directoryPrefix + dirSeparator + nvramFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
@@ -228,7 +227,7 @@ namespace PepperDash.Essentials
else
{
Debug.LogMessage(LogEventLevel.Information, "{userFolder:l}/program{applicationNumber} directory found", userFolder, InitialParametersClass.ApplicationNumber);
-
+
filePathPrefix = directoryPrefix + dirSeparator + userFolder
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
}
@@ -236,7 +235,7 @@ namespace PepperDash.Essentials
else // Handles Linux OS (Virtual Control)
{
//Debug.SetDebugLevel(2);
- Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{version:l} on Virtual Control Server", Global.AssemblyVersion);
+ Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{version:l} on Virtual Control Server", Global.AssemblyVersion);
// Set path to User/
filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator;
@@ -246,7 +245,7 @@ namespace PepperDash.Essentials
}
catch (Exception e)
{
- Debug.LogMessage(e, "Unable to determine platform due to exception");
+ Debug.LogMessage(e, "Unable to determine platform due to exception");
}
}
@@ -262,11 +261,11 @@ namespace PepperDash.Essentials
PluginLoader.AddProgramAssemblies();
_ = new Core.DeviceFactory();
- _ = new Devices.Common.DeviceFactory();
- _ = new DeviceFactory();
+ // _ = new Devices.Common.DeviceFactory();
+ // _ = new DeviceFactory();
- _ = new ProcessorExtensionDeviceFactory();
- _ = new MobileControlFactory();
+ // _ = new ProcessorExtensionDeviceFactory();
+ // _ = new MobileControlFactory();
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials load from configuration");
@@ -313,7 +312,7 @@ namespace PepperDash.Essentials
}
-
+
///
/// Verifies filesystem is set up. IR, SGD, and programX folders
@@ -333,46 +332,46 @@ namespace PepperDash.Essentials
Directory.Create(irDir);
var sgdDir = Global.FilePathPrefix + "sgd";
- if (!Directory.Exists(sgdDir))
- Directory.Create(sgdDir);
+ if (!Directory.Exists(sgdDir))
+ Directory.Create(sgdDir);
var pluginDir = Global.FilePathPrefix + "plugins";
if (!Directory.Exists(pluginDir))
Directory.Create(pluginDir);
var joinmapDir = Global.FilePathPrefix + "joinmaps";
- if(!Directory.Exists(joinmapDir))
+ if (!Directory.Exists(joinmapDir))
Directory.Create(joinmapDir);
- return configExists;
- }
+ return configExists;
+ }
- ///
- /// TearDown method
- ///
- public void TearDown()
- {
- Debug.LogMessage(LogEventLevel.Information, "Tearing down existing system");
- DeviceManager.DeactivateAll();
+ ///
+ /// TearDown method
+ ///
+ public void TearDown()
+ {
+ Debug.LogMessage(LogEventLevel.Information, "Tearing down existing system");
+ DeviceManager.DeactivateAll();
- TieLineCollection.Default.Clear();
+ TieLineCollection.Default.Clear();
- foreach (var key in DeviceManager.GetDevices())
- DeviceManager.RemoveDevice(key);
+ foreach (var key in DeviceManager.GetDevices())
+ DeviceManager.RemoveDevice(key);
- Debug.LogMessage(LogEventLevel.Information, "Tear down COMPLETE");
- }
+ Debug.LogMessage(LogEventLevel.Information, "Tear down COMPLETE");
+ }
- ///
- ///
- ///
- void Load()
- {
- LoadDevices();
- LoadRooms();
- LoadLogoServer();
+ ///
+ ///
+ ///
+ void Load()
+ {
+ LoadDevices();
+ LoadRooms();
+ LoadLogoServer();
- DeviceManager.ActivateAll();
+ DeviceManager.ActivateAll();
LoadTieLines();
@@ -381,8 +380,8 @@ namespace PepperDash.Essentials
if (mobileControl == null) return;
mobileControl.LinkSystemMonitorToAppServer();*/
-
- }
+
+ }
///
/// LoadDevices method
@@ -414,8 +413,8 @@ namespace PepperDash.Essentials
{
var prompt = Global.ControlSystem.ControllerPrompt;
- var typeMatch = String.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) ||
- String.Equals(devConf.Type, prompt.Replace("-", ""), StringComparison.OrdinalIgnoreCase);
+ var typeMatch = string.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(devConf.Type, prompt.Replace("-", ""), StringComparison.OrdinalIgnoreCase);
if (!typeMatch)
Debug.LogMessage(LogEventLevel.Information,
@@ -430,14 +429,14 @@ namespace PepperDash.Essentials
if (newDev == null)
newDev = Core.DeviceFactory.GetDevice(devConf);
- if (newDev != null)
- DeviceManager.AddDevice(newDev);
- else
+ if (newDev != null)
+ DeviceManager.AddDevice(newDev);
+ else
Debug.LogMessage(LogEventLevel.Information, "ERROR: Cannot load unknown device type '{deviceType:l}', key '{deviceKey:l}'.", devConf.Type, devConf.Key);
}
catch (Exception e)
{
- Debug.LogMessage(e, "ERROR: Creating device {deviceKey:l}. Skipping device.",args: new[] { devConf.Key });
+ Debug.LogMessage(e, "ERROR: Creating device {deviceKey:l}. Skipping device.", args: new[] { devConf.Key });
}
}
Debug.LogMessage(LogEventLevel.Information, "All Devices Loaded.");
@@ -475,27 +474,28 @@ namespace PepperDash.Essentials
/// LoadRooms method
///
public void LoadRooms()
- {
+ {
if (ConfigReader.ConfigObject.Rooms == null)
{
Debug.LogMessage(LogEventLevel.Information, "Notice: Configuration contains no rooms - Is this intentional? This may be a valid configuration.");
return;
}
- foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
+ foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
{
try
{
var room = Core.DeviceFactory.GetDevice(roomConfig);
- if(room == null)
+ if (room == null)
{
Debug.LogWarning("ERROR: Cannot load unknown room type '{roomType:l}', key '{roomKey:l}'.", roomConfig.Type, roomConfig.Key);
continue;
}
DeviceManager.AddDevice(room);
- } catch (Exception ex)
+ }
+ catch (Exception ex)
{
Debug.LogMessage(ex, "Exception loading room {roomKey}:{roomType}", null, roomConfig.Key, roomConfig.Type);
continue;
@@ -564,7 +564,7 @@ namespace PepperDash.Essentials
}
catch
{
- Debug.LogMessage(LogEventLevel.Information, "Unable to find logo information in any room config");
+ Debug.LogMessage(LogEventLevel.Information, "Unable to find logo information in any room config");
return false;
}
}
diff --git a/src/PepperDash.Essentials/Factory/DeviceFactory.cs b/src/PepperDash.Essentials/Factory/DeviceFactory.cs
index 7a2df7d1..092a67a2 100644
--- a/src/PepperDash.Essentials/Factory/DeviceFactory.cs
+++ b/src/PepperDash.Essentials/Factory/DeviceFactory.cs
@@ -3,11 +3,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
-using System.Reflection;
-
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
@@ -39,14 +38,33 @@ namespace PepperDash.Essentials
try
{
var factory = (IDeviceFactory)Activator.CreateInstance(type);
- factory.LoadTypeFactories();
+ LoadDeviceFactories(factory);
}
catch (Exception e)
{
- Debug.LogMessage(Serilog.Events.LogEventLevel.Error, "Unable to load type: '{exception}' DeviceFactory: {factoryName}", e, type.Name);
+ Debug.LogMessage(Serilog.Events.LogEventLevel.Error, "Unable to load type: '{exception}' DeviceFactory: {factoryName}", e, type.Name);
}
}
}
}
+
+ ///
+ /// Loads device factories from the specified plugin device factory and registers them for use.
+ ///
+ /// This method retrieves metadata from the provided , including
+ /// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
+ /// names are converted to lowercase for registration.
+ /// The plugin device factory that provides the device types, descriptions, and factory methods to be registered.
+ private static void LoadDeviceFactories(IDeviceFactory deviceFactory)
+ {
+ foreach (var typeName in deviceFactory.TypeNames)
+ {
+ //Debug.LogMessage(LogEventLevel.Verbose, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
+ var descriptionAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
+ string description = descriptionAttribute[0].Description;
+ var snippetAttribute = deviceFactory.FactoryType.GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
+ Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
+ }
+ }
}
}