mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-16 05:05:00 +00:00
Merge pull request #1299 from PepperDash/factory-updates
Multiple Updates
This commit is contained in:
282
Crestron-Library-Usage-Analysis.md
Normal file
282
Crestron-Library-Usage-Analysis.md
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
# Crestron Library Usage Analysis - PepperDash Essentials
|
||||||
|
|
||||||
|
This document provides a comprehensive analysis of Crestron classes and interfaces used throughout the PepperDash Essentials framework, organized by namespace and library component.
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
|
||||||
|
The PepperDash Essentials framework extensively leverages Crestron SDK components across 100+ files, providing abstractions for:
|
||||||
|
- Control system hardware (processors, touchpanels, IO devices)
|
||||||
|
- Communication interfaces (Serial, TCP/IP, SSH, CEC, IR)
|
||||||
|
- Device management and routing
|
||||||
|
- User interface components and smart objects
|
||||||
|
- System monitoring and diagnostics
|
||||||
|
|
||||||
|
## 1. Core Crestron Libraries
|
||||||
|
|
||||||
|
### 1.1 Crestron.SimplSharp
|
||||||
|
|
||||||
|
**Primary Usage**: Foundational framework components, collections, and basic types.
|
||||||
|
|
||||||
|
**Key Files**:
|
||||||
|
- Multiple files across all projects use `Crestron.SimplSharp` namespaces
|
||||||
|
- Provides basic C# runtime support for Crestron processors
|
||||||
|
|
||||||
|
### 1.2 Crestron.SimplSharpPro
|
||||||
|
|
||||||
|
**Primary Usage**: Main hardware abstraction layer for Crestron devices.
|
||||||
|
|
||||||
|
**Key Classes Used**:
|
||||||
|
|
||||||
|
#### CrestronControlSystem
|
||||||
|
- **File**: `/src/PepperDash.Essentials/ControlSystem.cs`
|
||||||
|
- **Usage**: Base class for the main control system implementation
|
||||||
|
- **Implementation**: `public class ControlSystem : CrestronControlSystem, ILoadConfig`
|
||||||
|
|
||||||
|
#### Device (Base Class)
|
||||||
|
- **Files**: 50+ files inherit from or use this class
|
||||||
|
- **Key Implementations**:
|
||||||
|
- `/src/PepperDash.Core/Device.cs` - Core device abstraction
|
||||||
|
- `/src/PepperDash.Essentials.Core/Devices/EssentialsDevice.cs` - Extended device base
|
||||||
|
- `/src/PepperDash.Essentials.Core/Room/Room.cs` - Room device implementation
|
||||||
|
- `/src/PepperDash.Essentials.Core/Devices/CrestronProcessor.cs` - Processor device wrapper
|
||||||
|
|
||||||
|
#### BasicTriList
|
||||||
|
- **Files**: 30+ files use this class extensively
|
||||||
|
- **Primary Usage**: Touchpanel communication and SIMPL bridging
|
||||||
|
- **Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/Touchpanels/TriListExtensions.cs` - Extension methods for signal handling
|
||||||
|
- `/src/PepperDash.Essentials.Core/Devices/EssentialsBridgeableDevice.cs` - Bridge interface
|
||||||
|
- `/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs` - UI dialog implementation
|
||||||
|
|
||||||
|
#### BasicTriListWithSmartObject
|
||||||
|
- **Files**: Multiple touchpanel and UI files
|
||||||
|
- **Usage**: Enhanced touchpanel support with smart object integration
|
||||||
|
- **Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/Touchpanels/Interfaces.cs` - Interface definitions
|
||||||
|
- `/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferenceList/SubpageReferenceList.cs`
|
||||||
|
|
||||||
|
## 2. Communication Hardware
|
||||||
|
|
||||||
|
### 2.1 Serial Communication (ComPort)
|
||||||
|
|
||||||
|
**Primary Class**: `ComPort`
|
||||||
|
**Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/Comm and IR/ComPortController.cs`
|
||||||
|
- `/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs`
|
||||||
|
|
||||||
|
**Usage Pattern**:
|
||||||
|
```csharp
|
||||||
|
public class ComPortController : Device, IBasicCommunicationWithStreamDebugging
|
||||||
|
public static ComPort GetComPort(EssentialsControlPropertiesConfig config)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Interface Support**: `IComPorts` - Used for devices that provide multiple COM ports
|
||||||
|
|
||||||
|
### 2.2 IR Communication (IROutputPort)
|
||||||
|
|
||||||
|
**Primary Class**: `IROutputPort`
|
||||||
|
**Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/Devices/IrOutputPortController.cs`
|
||||||
|
- `/src/PepperDash.Essentials.Core/Devices/GenericIRController.cs`
|
||||||
|
- `/src/PepperDash.Essentials.Core/Comm and IR/IRPortHelper.cs`
|
||||||
|
|
||||||
|
**Usage Pattern**:
|
||||||
|
```csharp
|
||||||
|
public class IrOutputPortController : Device
|
||||||
|
IROutputPort IrPort;
|
||||||
|
public IrOutputPortController(string key, IROutputPort port, string irDriverFilepath)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 CEC Communication (ICec)
|
||||||
|
|
||||||
|
**Primary Interface**: `ICec`
|
||||||
|
**Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/Comm and IR/CecPortController.cs`
|
||||||
|
- `/src/PepperDash.Essentials.Core/Comm and IR/CommFactory.cs`
|
||||||
|
|
||||||
|
**Usage Pattern**:
|
||||||
|
```csharp
|
||||||
|
public class CecPortController : Device, IBasicCommunicationWithStreamDebugging
|
||||||
|
public static ICec GetCecPort(ControlPropertiesConfig config)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Input/Output Hardware
|
||||||
|
|
||||||
|
### 3.1 Digital Input
|
||||||
|
|
||||||
|
**Primary Interface**: `IDigitalInput`
|
||||||
|
**Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs`
|
||||||
|
- `/src/PepperDash.Essentials.Core/Microphone Privacy/MicrophonePrivacyController.cs`
|
||||||
|
|
||||||
|
**Usage Pattern**:
|
||||||
|
```csharp
|
||||||
|
public List<IDigitalInput> Inputs { get; private set; }
|
||||||
|
void AddInput(IDigitalInput input)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Versiport Support
|
||||||
|
|
||||||
|
**Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs`
|
||||||
|
- `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs`
|
||||||
|
- `/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs`
|
||||||
|
|
||||||
|
**Usage**: Provides flexible I/O port configuration for various signal types
|
||||||
|
|
||||||
|
## 4. Touchpanel Hardware
|
||||||
|
|
||||||
|
### 4.1 MPC3 Touchpanel
|
||||||
|
|
||||||
|
**Primary Class**: `MPC3Basic`
|
||||||
|
**Key File**: `/src/PepperDash.Essentials.Core/Touchpanels/Mpc3Touchpanel.cs`
|
||||||
|
|
||||||
|
**Usage Pattern**:
|
||||||
|
```csharp
|
||||||
|
public class Mpc3TouchpanelController : Device
|
||||||
|
readonly MPC3Basic _touchpanel;
|
||||||
|
_touchpanel = processor.ControllerTouchScreenSlotDevice as MPC3Basic;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 TSW Series Support
|
||||||
|
|
||||||
|
**Evidence**: References found in messenger files and mobile control components
|
||||||
|
**Usage**: Integrated through mobile control messaging system for TSW touchpanel features
|
||||||
|
|
||||||
|
## 5. Timer and Threading
|
||||||
|
|
||||||
|
### 5.1 CTimer
|
||||||
|
|
||||||
|
**Primary Class**: `CTimer`
|
||||||
|
**Key File**: `/src/PepperDash.Core/PasswordManagement/PasswordManager.cs`
|
||||||
|
|
||||||
|
**Usage Pattern**:
|
||||||
|
```csharp
|
||||||
|
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started"));
|
||||||
|
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset"));
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Networking and Communication
|
||||||
|
|
||||||
|
### 6.1 Ethernet Communication
|
||||||
|
|
||||||
|
**Libraries Used**:
|
||||||
|
- `Crestron.SimplSharpPro.EthernetCommunication`
|
||||||
|
- `Crestron.SimplSharp.Net.Utilities.EthernetHelper`
|
||||||
|
|
||||||
|
**Key Files**:
|
||||||
|
- `/src/PepperDash.Core/Comm/GenericTcpIpClient.cs`
|
||||||
|
- `/src/PepperDash.Core/Comm/GenericTcpIpServer.cs`
|
||||||
|
- `/src/PepperDash.Core/Comm/GenericSecureTcpIpClient.cs`
|
||||||
|
- `/src/PepperDash.Core/Comm/GenericSshClient.cs`
|
||||||
|
- `/src/PepperDash.Core/Comm/GenericUdpServer.cs`
|
||||||
|
|
||||||
|
**Usage Pattern**:
|
||||||
|
```csharp
|
||||||
|
public class GenericTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
|
||||||
|
public class GenericSecureTcpIpClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Device Management Libraries
|
||||||
|
|
||||||
|
### 7.1 DeviceSupport
|
||||||
|
|
||||||
|
**Library**: `Crestron.SimplSharpPro.DeviceSupport`
|
||||||
|
**Usage**: Core device support infrastructure used throughout the framework
|
||||||
|
|
||||||
|
### 7.2 DM (DigitalMedia)
|
||||||
|
|
||||||
|
**Library**: `Crestron.SimplSharpPro.DM`
|
||||||
|
**Usage**: Digital media routing and switching support
|
||||||
|
**Evidence**: Found in routing configuration and DM output card references
|
||||||
|
|
||||||
|
## 8. User Interface Libraries
|
||||||
|
|
||||||
|
### 8.1 UI Components
|
||||||
|
|
||||||
|
**Library**: `Crestron.SimplSharpPro.UI`
|
||||||
|
**Usage**: User interface elements and touchpanel controls
|
||||||
|
|
||||||
|
### 8.2 Smart Objects
|
||||||
|
|
||||||
|
**Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/SmartObjects/SmartObjectDynamicList.cs`
|
||||||
|
- `/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferenceList/SubpageReferenceList.cs`
|
||||||
|
|
||||||
|
**Usage**: Advanced UI components with dynamic content
|
||||||
|
|
||||||
|
## 9. System Monitoring and Diagnostics
|
||||||
|
|
||||||
|
### 9.1 Diagnostics
|
||||||
|
|
||||||
|
**Library**: `Crestron.SimplSharpPro.Diagnostics`
|
||||||
|
**Usage**: System health monitoring and performance tracking
|
||||||
|
|
||||||
|
### 9.2 System Information
|
||||||
|
|
||||||
|
**Key Files**:
|
||||||
|
- `/src/PepperDash.Essentials.Core/Monitoring/SystemMonitorController.cs`
|
||||||
|
|
||||||
|
**Usage**: Provides system status, Ethernet information, and program details
|
||||||
|
|
||||||
|
## 10. Integration Patterns
|
||||||
|
|
||||||
|
### 10.1 SIMPL Bridging
|
||||||
|
|
||||||
|
**Pattern**: Extensive use of `BasicTriList` for SIMPL integration
|
||||||
|
**Files**: Bridge classes throughout the framework implement `LinkToApi` methods:
|
||||||
|
```csharp
|
||||||
|
public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10.2 Device Factory Pattern
|
||||||
|
|
||||||
|
**Implementation**: Factory classes create hardware-specific implementations
|
||||||
|
**Example**: `CommFactory.cs` provides communication device creation
|
||||||
|
|
||||||
|
### 10.3 Extension Methods
|
||||||
|
|
||||||
|
**Pattern**: Extensive use of extension methods for Crestron classes
|
||||||
|
**Example**: `TriListExtensions.cs` adds 30+ extension methods to `BasicTriList`
|
||||||
|
|
||||||
|
## 11. Signal Processing
|
||||||
|
|
||||||
|
### 11.1 Signal Types
|
||||||
|
|
||||||
|
**Bool Signals**: Digital control and feedback
|
||||||
|
**UShort Signals**: Analog values and numeric data
|
||||||
|
**String Signals**: Text and configuration data
|
||||||
|
|
||||||
|
**Implementation**: Comprehensive signal handling in `TriListExtensions.cs`
|
||||||
|
|
||||||
|
## 12. Error Handling and Logging
|
||||||
|
|
||||||
|
**Pattern**: Consistent use of Crestron's Debug logging throughout
|
||||||
|
**Examples**:
|
||||||
|
```csharp
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "Device {0} is not a valid device", dc.PortDeviceKey);
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?");
|
||||||
|
```
|
||||||
|
|
||||||
|
## 13. Threading and Synchronization
|
||||||
|
|
||||||
|
**Components**:
|
||||||
|
- CTimer for time-based operations
|
||||||
|
- Thread-safe collections and patterns
|
||||||
|
- Event-driven programming models
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
The PepperDash Essentials framework demonstrates sophisticated integration with the Crestron ecosystem, leveraging:
|
||||||
|
|
||||||
|
- **Core Infrastructure**: CrestronControlSystem, Device base classes
|
||||||
|
- **Communication**: COM, IR, CEC, TCP/IP, SSH protocols
|
||||||
|
- **Hardware Abstraction**: Touchpanels, I/O devices, processors
|
||||||
|
- **User Interface**: Smart objects, signal processing, SIMPL bridging
|
||||||
|
- **System Services**: Monitoring, diagnostics, device management
|
||||||
|
|
||||||
|
This analysis shows that Essentials serves as a comprehensive middleware layer, abstracting Crestron hardware complexities while providing modern software development patterns and practices.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Generated: [Current Date]*
|
||||||
|
*Framework Version: PepperDash Essentials (Based on codebase analysis)*
|
||||||
@@ -146,31 +146,31 @@ namespace PepperDash.Core
|
|||||||
base(key)
|
base(key)
|
||||||
{
|
{
|
||||||
StreamDebugging = new CommunicationStreamDebugging(key);
|
StreamDebugging = new CommunicationStreamDebugging(key);
|
||||||
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
||||||
Key = key;
|
Key = key;
|
||||||
Hostname = hostname;
|
Hostname = hostname;
|
||||||
Port = port;
|
Port = port;
|
||||||
Username = username;
|
Username = username;
|
||||||
Password = password;
|
Password = password;
|
||||||
AutoReconnectIntervalMs = 5000;
|
AutoReconnectIntervalMs = 5000;
|
||||||
|
|
||||||
ReconnectTimer = new CTimer(o =>
|
ReconnectTimer = new CTimer(o =>
|
||||||
{
|
{
|
||||||
if (ConnectEnabled)
|
if (ConnectEnabled)
|
||||||
{
|
{
|
||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
}, System.Threading.Timeout.Infinite);
|
}, System.Threading.Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// S+ Constructor - Must set all properties before calling Connect
|
/// S+ Constructor - Must set all properties before calling Connect
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GenericSshClient()
|
public GenericSshClient()
|
||||||
: base(SPlusKey)
|
: base(SPlusKey)
|
||||||
{
|
{
|
||||||
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
||||||
AutoReconnectIntervalMs = 5000;
|
AutoReconnectIntervalMs = 5000;
|
||||||
|
|
||||||
ReconnectTimer = new CTimer(o =>
|
ReconnectTimer = new CTimer(o =>
|
||||||
{
|
{
|
||||||
@@ -179,18 +179,18 @@ namespace PepperDash.Core
|
|||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
}, System.Threading.Timeout.Infinite);
|
}, System.Threading.Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles closing this up when the program shuts down
|
/// Handles closing this up when the program shuts down
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
|
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
|
||||||
{
|
{
|
||||||
if (programEventType == eProgramStatusEventType.Stopping)
|
if (programEventType == eProgramStatusEventType.Stopping)
|
||||||
{
|
{
|
||||||
if (Client != null)
|
if (Client != null)
|
||||||
{
|
{
|
||||||
this.LogDebug("Program stopping. Closing connection");
|
this.LogDebug("Program stopping. Closing connection");
|
||||||
Disconnect();
|
Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,10 +223,7 @@ namespace PepperDash.Core
|
|||||||
this.LogDebug("Attempting connect");
|
this.LogDebug("Attempting connect");
|
||||||
|
|
||||||
// Cancel reconnect if running.
|
// Cancel reconnect if running.
|
||||||
if (ReconnectTimer != null)
|
ReconnectTimer?.Stop();
|
||||||
{
|
|
||||||
ReconnectTimer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup the old client if it already exists
|
// Cleanup the old client if it already exists
|
||||||
if (Client != null)
|
if (Client != null)
|
||||||
@@ -268,20 +265,26 @@ namespace PepperDash.Core
|
|||||||
|
|
||||||
if (ie is SocketException)
|
if (ie is SocketException)
|
||||||
{
|
{
|
||||||
this.LogException(ie, "CONNECTION failure: Cannot reach host");
|
this.LogError("CONNECTION failure: Cannot reach host");
|
||||||
|
this.LogVerbose(ie, "Exception details: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ie is System.Net.Sockets.SocketException socketException)
|
if (ie is System.Net.Sockets.SocketException socketException)
|
||||||
{
|
{
|
||||||
this.LogException(ie, "Connection failure: Cannot reach {host} on {port}",
|
this.LogError("Connection failure: Cannot reach {host} on {port}",
|
||||||
Hostname, Port);
|
Hostname, Port);
|
||||||
|
this.LogVerbose(socketException, "SocketException details: ");
|
||||||
}
|
}
|
||||||
if (ie is SshAuthenticationException)
|
if (ie is SshAuthenticationException)
|
||||||
{
|
{
|
||||||
this.LogException(ie, "Authentication failure for username {userName}", Username);
|
this.LogError("Authentication failure for username {userName}", Username);
|
||||||
|
this.LogVerbose(ie, "AuthenticationException details: ");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.LogException(ie, "Error on connect");
|
{
|
||||||
|
this.LogError("Error on connect: {error}", ie.Message);
|
||||||
|
this.LogVerbose(ie, "Exception details: ");
|
||||||
|
}
|
||||||
|
|
||||||
DisconnectLogged = true;
|
DisconnectLogged = true;
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
@@ -291,7 +294,7 @@ namespace PepperDash.Core
|
|||||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(SshOperationTimeoutException ex)
|
catch (SshOperationTimeoutException ex)
|
||||||
{
|
{
|
||||||
this.LogWarning("Connection attempt timed out: {message}", ex.Message);
|
this.LogWarning("Connection attempt timed out: {message}", ex.Message);
|
||||||
|
|
||||||
@@ -306,7 +309,8 @@ namespace PepperDash.Core
|
|||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error;
|
var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error;
|
||||||
this.LogException(e, "Unhandled exception on connect");
|
this.LogError("Unhandled exception on connect: {error}", e.Message);
|
||||||
|
this.LogVerbose(e, "Exception details: ");
|
||||||
DisconnectLogged = true;
|
DisconnectLogged = true;
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect)
|
if (AutoReconnect)
|
||||||
@@ -323,18 +327,18 @@ namespace PepperDash.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnect method
|
/// Disconnect method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
{
|
{
|
||||||
ConnectEnabled = false;
|
ConnectEnabled = false;
|
||||||
// Stop trying reconnects, if we are
|
// Stop trying reconnects, if we are
|
||||||
if (ReconnectTimer != null)
|
if (ReconnectTimer != null)
|
||||||
{
|
{
|
||||||
ReconnectTimer.Stop();
|
ReconnectTimer.Stop();
|
||||||
// ReconnectTimer = null;
|
// ReconnectTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
||||||
}
|
}
|
||||||
@@ -360,7 +364,7 @@ namespace PepperDash.Core
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
this.LogException(ex,"Exception in Kill Client");
|
this.LogException(ex, "Exception in Kill Client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +372,7 @@ namespace PepperDash.Core
|
|||||||
/// Kills the stream
|
/// Kills the stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void KillStream()
|
void KillStream()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (TheStream != null)
|
if (TheStream != null)
|
||||||
@@ -384,59 +388,59 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
this.LogException(ex, "Exception in Kill Stream:{0}");
|
this.LogException(ex, "Exception in Kill Stream:{0}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the keyboard interactive authentication, should it be required.
|
/// Handles the keyboard interactive authentication, should it be required.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e)
|
void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e)
|
||||||
{
|
{
|
||||||
foreach (AuthenticationPrompt prompt in e.Prompts)
|
foreach (AuthenticationPrompt prompt in e.Prompts)
|
||||||
if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
|
if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
|
||||||
prompt.Response = Password;
|
prompt.Response = Password;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for data receive on ShellStream. Passes data across to queue for line parsing.
|
/// Handler for data receive on ShellStream. Passes data across to queue for line parsing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Stream_DataReceived(object sender, ShellDataEventArgs e)
|
void Stream_DataReceived(object sender, ShellDataEventArgs e)
|
||||||
{
|
{
|
||||||
if (((ShellStream)sender).Length <= 0L)
|
if (((ShellStream)sender).Length <= 0L)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var response = ((ShellStream)sender).Read();
|
var response = ((ShellStream)sender).Read();
|
||||||
|
|
||||||
var bytesHandler = BytesReceived;
|
var bytesHandler = BytesReceived;
|
||||||
|
|
||||||
if (bytesHandler != null)
|
if (bytesHandler != null)
|
||||||
{
|
{
|
||||||
var bytes = Encoding.UTF8.GetBytes(response);
|
var bytes = Encoding.UTF8.GetBytes(response);
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
||||||
{
|
{
|
||||||
this.LogInformation("Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
|
this.LogInformation("Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
|
||||||
}
|
}
|
||||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
var textHandler = TextReceived;
|
var textHandler = TextReceived;
|
||||||
if (textHandler != null)
|
if (textHandler != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
||||||
this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response));
|
this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response));
|
||||||
|
|
||||||
textHandler(this, new GenericCommMethodReceiveTextArgs(response));
|
textHandler(this, new GenericCommMethodReceiveTextArgs(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange
|
/// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange
|
||||||
/// event
|
/// event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Client_ErrorOccurred(object sender, ExceptionEventArgs e)
|
void Client_ErrorOccurred(object sender, ExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
CrestronInvoke.BeginInvoke(o =>
|
CrestronInvoke.BeginInvoke(o =>
|
||||||
{
|
{
|
||||||
if (e.Exception is SshConnectionException || e.Exception is System.Net.Sockets.SocketException)
|
if (e.Exception is SshConnectionException || e.Exception is System.Net.Sockets.SocketException)
|
||||||
@@ -465,61 +469,54 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void OnConnectionChange()
|
void OnConnectionChange()
|
||||||
{
|
{
|
||||||
if (ConnectionChange != null)
|
ConnectionChange?.Invoke(this, new GenericSocketStatusChageEventArgs(this));
|
||||||
ConnectionChange(this, new GenericSocketStatusChageEventArgs(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IBasicCommunication Members
|
#region IBasicCommunication Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends text to the server
|
/// Sends text to the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text"></param>
|
/// <param name="text">The text to send</param>
|
||||||
/// <summary>
|
public void SendText(string text)
|
||||||
/// SendText method
|
{
|
||||||
/// </summary>
|
try
|
||||||
public void SendText(string text)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Client != null && TheStream != null && IsConnected)
|
|
||||||
{
|
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
|
||||||
this.LogInformation(
|
|
||||||
"Sending {length} characters of text: '{text}'",
|
|
||||||
text.Length,
|
|
||||||
ComTextHelper.GetDebugText(text));
|
|
||||||
|
|
||||||
TheStream.Write(text);
|
|
||||||
TheStream.Flush();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this.LogDebug("Client is null or disconnected. Cannot Send Text");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException)
|
|
||||||
{
|
{
|
||||||
this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim());
|
if (Client != null && TheStream != null && IsConnected)
|
||||||
|
{
|
||||||
|
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
||||||
|
this.LogInformation(
|
||||||
|
"Sending {length} characters of text: '{text}'",
|
||||||
|
text.Length,
|
||||||
|
ComTextHelper.GetDebugText(text));
|
||||||
|
|
||||||
|
TheStream.Write(text);
|
||||||
|
TheStream.Flush();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.LogDebug("Client is null or disconnected. Cannot Send Text");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim());
|
||||||
|
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
ReconnectTimer.Reset();
|
ReconnectTimer.Reset();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
this.LogException(ex, "Exception sending text: '{message}'", text);
|
this.LogException(ex, "Exception sending text: '{message}'", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends Bytes to the server
|
/// Sends Bytes to the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes"></param>
|
/// <param name="bytes">The bytes to send</param>
|
||||||
/// <summary>
|
public void SendBytes(byte[] bytes)
|
||||||
/// SendBytes method
|
{
|
||||||
/// </summary>
|
|
||||||
public void SendBytes(byte[] bytes)
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Client != null && TheStream != null && IsConnected)
|
if (Client != null && TheStream != null && IsConnected)
|
||||||
@@ -545,38 +542,38 @@ namespace PepperDash.Core
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes));
|
this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//*****************************************************************************************************
|
//*****************************************************************************************************
|
||||||
//*****************************************************************************************************
|
//*****************************************************************************************************
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a SshConnectionChangeEventArgs
|
/// Represents a SshConnectionChangeEventArgs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SshConnectionChangeEventArgs : EventArgs
|
public class SshConnectionChangeEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connection State
|
/// Connection State
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsConnected { get; private set; }
|
public bool IsConnected { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the UIsConnected
|
/// Gets or sets the UIsConnected
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ushort UIsConnected { get { return (ushort)(Client.IsConnected ? 1 : 0); } }
|
public ushort UIsConnected { get { return (ushort)(Client.IsConnected ? 1 : 0); } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Client
|
/// Gets or sets the Client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GenericSshClient Client { get; private set; }
|
public GenericSshClient Client { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Status
|
/// Gets or sets the Status
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ushort Status { get { return Client.UStatus; } }
|
public ushort Status { get { return Client.UStatus; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// S+ Constructor
|
/// S+ Constructor
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a ConfigSnippetAttribute
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||||
|
public class ConfigSnippetAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a configuration snippet for the device.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configSnippet"></param>
|
||||||
|
public ConfigSnippetAttribute(string configSnippet)
|
||||||
|
{
|
||||||
|
ConfigSnippet = configSnippet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configuration snippet for the device.
|
||||||
|
/// This snippet can be used in the DeviceConfig to instantiate the device.
|
||||||
|
/// </summary>
|
||||||
|
public string ConfigSnippet { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a description attribute for a device.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
|
||||||
|
public class DescriptionAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a description attribute for a device.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description"></param>
|
||||||
|
public DescriptionAttribute(string description)
|
||||||
|
{
|
||||||
|
Description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description for the device.
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,26 +1,38 @@
|
|||||||
using Crestron.SimplSharp;
|
using System;
|
||||||
using Crestron.SimplSharpPro;
|
|
||||||
using PepperDash.Core;
|
|
||||||
using Serilog.Events;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Crestron.SimplSharp;
|
||||||
|
using Crestron.SimplSharpPro;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages the devices in the system
|
||||||
|
/// </summary>
|
||||||
public static class DeviceManager
|
public static class DeviceManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when all devices have been activated
|
||||||
|
/// </summary>
|
||||||
public static event EventHandler<EventArgs> AllDevicesActivated;
|
public static event EventHandler<EventArgs> AllDevicesActivated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when all devices have been registered
|
||||||
|
/// </summary>
|
||||||
public static event EventHandler<EventArgs> AllDevicesRegistered;
|
public static event EventHandler<EventArgs> AllDevicesRegistered;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when all devices have been initialized
|
||||||
|
/// </summary>
|
||||||
public static event EventHandler<EventArgs> AllDevicesInitialized;
|
public static event EventHandler<EventArgs> AllDevicesInitialized;
|
||||||
|
|
||||||
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
|
private static readonly CCriticalSection DeviceCriticalSection = new CCriticalSection();
|
||||||
private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
|
|
||||||
|
|
||||||
//public static List<Device> Devices { get { return _Devices; } }
|
private static readonly CEvent AllowAddDevicesCEvent = new CEvent(false, true);
|
||||||
//static List<Device> _Devices = new List<Device>();
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, IKeyed> Devices = new Dictionary<string, IKeyed>(StringComparer.OrdinalIgnoreCase);
|
private static readonly Dictionary<string, IKeyed> Devices = new Dictionary<string, IKeyed>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
@@ -74,7 +86,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
foreach (var d in Devices.Values)
|
foreach (var d in Devices.Values)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (d is Device)
|
if (d is Device)
|
||||||
(d as Device).PreActivate();
|
(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)
|
private static void ListDevices(string s)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "{0} Devices registered with Device Manager:", Devices.Count);
|
Debug.LogMessage(LogEventLevel.Information, "{0} Devices registered with Device Manager:", Devices.Count);
|
||||||
@@ -397,6 +388,25 @@ namespace PepperDash.Essentials.Core
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GetDeviceForKey method
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
public static T GetDeviceForKey<T>(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];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Console handler that simulates com port data receive
|
/// Console handler that simulates com port data receive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Threading.Tasks;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core.Config;
|
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
@@ -17,9 +11,16 @@ namespace PepperDash.Essentials.Core
|
|||||||
[Description("The base Essentials Device Class")]
|
[Description("The base Essentials Device Class")]
|
||||||
public abstract class EssentialsDevice : Device
|
public abstract class EssentialsDevice : Device
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event raised when the device is initialized.
|
||||||
|
/// </summary>
|
||||||
public event EventHandler Initialized;
|
public event EventHandler Initialized;
|
||||||
|
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the device is initialized.
|
||||||
|
/// </summary>
|
||||||
public bool IsInitialized
|
public bool IsInitialized
|
||||||
{
|
{
|
||||||
get { return _isInitialized; }
|
get { return _isInitialized; }
|
||||||
@@ -36,12 +37,21 @@ namespace PepperDash.Essentials.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the EssentialsDevice class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The unique identifier for the device.</param>
|
||||||
protected EssentialsDevice(string key)
|
protected EssentialsDevice(string key)
|
||||||
: base(key)
|
: base(key)
|
||||||
{
|
{
|
||||||
SubscribeToActivateComplete();
|
SubscribeToActivateComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the EssentialsDevice class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The unique identifier for the device.</param>
|
||||||
|
/// <param name="name">The name of the device.</param>
|
||||||
protected EssentialsDevice(string key, string name)
|
protected EssentialsDevice(string key, string name)
|
||||||
: base(key, name)
|
: base(key, name)
|
||||||
{
|
{
|
||||||
@@ -55,7 +65,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
|
|
||||||
private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs)
|
private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs)
|
||||||
{
|
{
|
||||||
CrestronInvoke.BeginInvoke((o) =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
try
|
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)]
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a ConfigSnippetAttribute
|
|
||||||
/// </summary>
|
|
||||||
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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Devices the basic needs for a Device Factory
|
|
||||||
/// </summary>
|
|
||||||
public abstract class EssentialsDeviceFactory<T> : IDeviceFactory where T:EssentialsDevice
|
|
||||||
{
|
|
||||||
#region IDeviceFactory Members
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
|
|
||||||
/// </summary>
|
|
||||||
public List<string> TypeNames { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// LoadTypeFactories method
|
|
||||||
/// </summary>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method that will build the device
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dc">The device config</param>
|
|
||||||
/// <returns>An instance of the device</returns>
|
|
||||||
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class ProcessorExtensionDeviceFactory<T> : IProcessorExtensionDeviceFactory where T: EssentialsDevice
|
|
||||||
{
|
|
||||||
#region IProcessorExtensionDeviceFactory Members
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the TypeNames
|
|
||||||
/// </summary>
|
|
||||||
public List<string> TypeNames { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// LoadFactories method
|
|
||||||
/// </summary>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method that will build the device
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dc">The device config</param>
|
|
||||||
/// <returns>An instance of the device</returns>
|
|
||||||
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Devices the basic needs for a Device Factory
|
|
||||||
/// </summary>
|
|
||||||
public abstract class EssentialsPluginDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDeviceFactory where T : EssentialsDevice
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
|
|
||||||
/// </summary>
|
|
||||||
public string MinimumEssentialsFrameworkVersion { get; protected set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class EssentialsPluginDevelopmentDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDevelopmentDeviceFactory where T : EssentialsDevice
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
|
|
||||||
/// </summary>
|
|
||||||
public string MinimumEssentialsFrameworkVersion { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the DevelopmentEssentialsFrameworkVersions
|
|
||||||
/// </summary>
|
|
||||||
public List<string> DevelopmentEssentialsFrameworkVersions { get; protected set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PepperDash.Essentials.Core.Config;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the basic needs for a Device Factory
|
||||||
|
/// </summary>
|
||||||
|
public abstract class EssentialsDeviceFactory<T> : IDeviceFactory where T : EssentialsDevice
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Type FactoryType => typeof(T);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
|
||||||
|
/// </summary>
|
||||||
|
public List<string> TypeNames { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The method that will build the device
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dc">The device config</param>
|
||||||
|
/// <returns>An instance of the device</returns>
|
||||||
|
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
public abstract class EssentialsPluginDevelopmentDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDevelopmentDeviceFactory where T : EssentialsDevice
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
|
||||||
|
/// </summary>
|
||||||
|
public string MinimumEssentialsFrameworkVersion { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the DevelopmentEssentialsFrameworkVersions
|
||||||
|
/// </summary>
|
||||||
|
public List<string> DevelopmentEssentialsFrameworkVersions { get; protected set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Devices the basic needs for a Device Factory
|
||||||
|
/// </summary>
|
||||||
|
public abstract class EssentialsPluginDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDeviceFactory where T : EssentialsDevice
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
|
||||||
|
/// </summary>
|
||||||
|
public string MinimumEssentialsFrameworkVersion { get; protected set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using PepperDash.Core;
|
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IOnline
|
|
||||||
/// </summary>
|
|
||||||
public interface IOnline
|
|
||||||
{
|
|
||||||
BoolFeedback IsOnline { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Defines the contract for IAttachVideoStatus
|
|
||||||
/// </summary>
|
|
||||||
public interface IAttachVideoStatus : IKeyed
|
|
||||||
{
|
|
||||||
// Extension methods will depend on this
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// For display classes that can provide usage data
|
|
||||||
/// </summary>
|
|
||||||
public interface IDisplayUsage
|
|
||||||
{
|
|
||||||
IntFeedback LampHours { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IMakeModel : IKeyed
|
|
||||||
{
|
|
||||||
string DeviceMake { get; }
|
|
||||||
string DeviceModel { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
13
src/PepperDash.Essentials.Core/Devices/IAttachVideoStatus.cs
Normal file
13
src/PepperDash.Essentials.Core/Devices/IAttachVideoStatus.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using PepperDash.Core;
|
||||||
|
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the contract for IAttachVideoStatus
|
||||||
|
/// </summary>
|
||||||
|
public interface IAttachVideoStatus : IKeyed
|
||||||
|
{
|
||||||
|
// Extension methods will depend on this
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/PepperDash.Essentials.Core/Devices/IDisplayUsage.cs
Normal file
10
src/PepperDash.Essentials.Core/Devices/IDisplayUsage.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// For display classes that can provide usage data
|
||||||
|
/// </summary>
|
||||||
|
public interface IDisplayUsage
|
||||||
|
{
|
||||||
|
IntFeedback LampHours { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/PepperDash.Essentials.Core/Devices/IMakeModel.cs
Normal file
22
src/PepperDash.Essentials.Core/Devices/IMakeModel.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using PepperDash.Core;
|
||||||
|
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the contract for device make and model information
|
||||||
|
/// </summary>
|
||||||
|
public interface IMakeModel : IKeyed
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the make of the device
|
||||||
|
/// </summary>
|
||||||
|
string DeviceMake { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the model of the device
|
||||||
|
/// </summary>
|
||||||
|
string DeviceModel { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/PepperDash.Essentials.Core/Devices/IOnline.cs
Normal file
13
src/PepperDash.Essentials.Core/Devices/IOnline.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the contract for IOnline
|
||||||
|
/// </summary>
|
||||||
|
public interface IOnline
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the device is online.
|
||||||
|
/// </summary>
|
||||||
|
BoolFeedback IsOnline { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PepperDash.Essentials.Core.Config;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a factory for creating processor extension devices.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of the processor extension device.</typeparam>
|
||||||
|
[Obsolete("will be removed in a future version")]
|
||||||
|
public abstract class ProcessorExtensionDeviceFactory<T> : IProcessorExtensionDeviceFactory where T : EssentialsDevice
|
||||||
|
{
|
||||||
|
#region IProcessorExtensionDeviceFactory Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the TypeNames
|
||||||
|
/// </summary>
|
||||||
|
public List<string> TypeNames { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// LoadFactories method
|
||||||
|
/// </summary>
|
||||||
|
public void LoadFactories()
|
||||||
|
{
|
||||||
|
foreach (var typeName in TypeNames)
|
||||||
|
{
|
||||||
|
string description = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0
|
||||||
|
? descriptionAttribute[0].Description
|
||||||
|
: "No description available";
|
||||||
|
|
||||||
|
ProcessorExtensionDeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The method that will build the device
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dc">The device config</param>
|
||||||
|
/// <returns>An instance of the device</returns>
|
||||||
|
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
@@ -248,6 +249,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the valid destination types for SourceListItems in a room
|
/// Defines the valid destination types for SourceListItems in a room
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete]
|
||||||
public enum eSourceListItemDestinationTypes
|
public enum eSourceListItemDestinationTypes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,123 +1,162 @@
|
|||||||
|
|
||||||
|
|
||||||
using Crestron.SimplSharp;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Crestron.SimplSharp;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core.Config;
|
using PepperDash.Essentials.Core.Config;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wrapper class for device factory information
|
/// Provides functionality for managing and registering device factories, including loading plugin-based factories and
|
||||||
/// </summary>
|
/// retrieving devices based on their configuration.
|
||||||
public class DeviceFactoryWrapper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the device type
|
|
||||||
/// </summary>
|
|
||||||
public Type Type { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the Description
|
|
||||||
/// </summary>
|
|
||||||
public string Description { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the factory method for creating devices
|
|
||||||
/// </summary>
|
|
||||||
public Func<DeviceConfig, IKeyed> FactoryMethod { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the DeviceFactoryWrapper class
|
|
||||||
/// </summary>
|
|
||||||
public DeviceFactoryWrapper()
|
|
||||||
{
|
|
||||||
Type = null;
|
|
||||||
Description = "Not Available";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a DeviceFactory
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>The <see cref="DeviceFactory"/> 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.</remarks>
|
||||||
public class DeviceFactory
|
public class DeviceFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the DeviceFactory class and loads all device type factories
|
/// Initializes a new instance of the <see cref="DeviceFactory"/> class and loads all available device factories
|
||||||
|
/// from the current assembly.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>This constructor scans the executing assembly for types that implement the <see
|
||||||
|
/// cref="IDeviceFactory"/> interface and are not abstract or interfaces. For each valid type, an instance is
|
||||||
|
/// created and passed to the <c>LoadDeviceFactories</c> method for further processing. If a type cannot be
|
||||||
|
/// instantiated, an informational log message is generated, and the process continues with the remaining
|
||||||
|
/// types.</remarks>
|
||||||
public DeviceFactory()
|
public DeviceFactory()
|
||||||
{
|
{
|
||||||
var assy = Assembly.GetExecutingAssembly();
|
var programAssemblies = Directory.GetFiles(InitialParametersClass.ProgramDirectory.ToString(), "*.dll");
|
||||||
PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
|
|
||||||
|
|
||||||
var types = assy.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
|
foreach (var assembly in programAssemblies)
|
||||||
|
|
||||||
if (types != null)
|
|
||||||
{
|
{
|
||||||
|
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 ?? "Unknown");
|
||||||
|
|
||||||
|
PluginLoader.AddLoadedAssembly(assembly.GetName()?.Name ?? "Unknown", 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)
|
foreach (var type in types)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||||
factory.LoadTypeFactories();
|
LoadDeviceFactories(factory);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A dictionary of factory methods, keyed by config types, added by plugins.
|
/// Loads device factories from the specified plugin device factory and registers them for use.
|
||||||
/// These methods are looked up and called by GetDevice in this class.
|
/// </summary>
|
||||||
/// </summary>
|
/// <remarks>This method retrieves metadata from the provided <paramref name="deviceFactory"/>, including
|
||||||
static Dictionary<string, DeviceFactoryWrapper> FactoryMethods =
|
/// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
|
||||||
|
/// names are converted to lowercase for registration.</remarks>
|
||||||
|
/// <param name="deviceFactory">The plugin device factory that provides the device types, descriptions, and factory methods to be registered.</param>
|
||||||
|
private static void LoadDeviceFactories(IDeviceFactory deviceFactory)
|
||||||
|
{
|
||||||
|
foreach (var typeName in deviceFactory.TypeNames)
|
||||||
|
{
|
||||||
|
string description = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0
|
||||||
|
? descriptionAttribute[0].Description
|
||||||
|
: "No description available";
|
||||||
|
|
||||||
|
AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A dictionary of factory methods, keyed by config types, added by plugins.
|
||||||
|
/// These methods are looked up and called by GetDevice in this class.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<string, DeviceFactoryWrapper> FactoryMethods =
|
||||||
new Dictionary<string, DeviceFactoryWrapper>(StringComparer.OrdinalIgnoreCase);
|
new Dictionary<string, DeviceFactoryWrapper>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a plugin factory method
|
/// Registers a factory method for creating instances of a specific type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dc"></param>
|
/// <remarks>This method associates a type name with a factory method, allowing instances of the type to
|
||||||
/// <returns></returns>
|
/// be created dynamically. The factory method is stored internally and can be retrieved or invoked as
|
||||||
public static void AddFactoryForType(string typeName, Func<DeviceConfig, IKeyed> method)
|
/// needed.</remarks>
|
||||||
{
|
/// <param name="typeName">The name of the type for which the factory method is being registered. This value cannot be null or empty.</param>
|
||||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
/// <param name="method">A delegate that defines the factory method. The delegate takes a <see cref="DeviceConfig"/> parameter and
|
||||||
DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
|
/// returns an instance of <see cref="IKeyed"/>.</param>
|
||||||
}
|
public static void AddFactoryForType(string typeName, Func<DeviceConfig, IKeyed> method)
|
||||||
|
{
|
||||||
|
FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers a factory method for creating instances of a specific device type.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>If a factory method for the specified <paramref name="typeName"/> already exists, the method
|
||||||
|
/// will not overwrite it and will log an informational message instead.</remarks>
|
||||||
|
/// <param name="typeName">The unique name of the device type. This serves as the key for identifying the factory method.</param>
|
||||||
|
/// <param name="description">A brief description of the device type. This is used for informational purposes.</param>
|
||||||
|
/// <param name="Type">The <see cref="Type"/> of the device being registered. This represents the runtime type of the device.</param>
|
||||||
|
/// <param name="method">A factory method that takes a <see cref="DeviceConfig"/> as input and returns an instance of <see
|
||||||
|
/// cref="IKeyed"/>.</param>
|
||||||
public static void AddFactoryForType(string typeName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
public static void AddFactoryForType(string typeName, string description, Type Type, Func<DeviceConfig, IKeyed> 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||||
DeviceFactory.FactoryMethods.Add(typeName, wrapper);
|
|
||||||
|
FactoryMethods.Add(typeName, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CheckForSecrets(IEnumerable<JProperty> obj)
|
private static void CheckForSecrets(IEnumerable<JProperty> obj)
|
||||||
{
|
{
|
||||||
foreach (var prop in obj.Where(prop => prop.Value as JObject != null))
|
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<SecretsPropertiesConfig>());
|
var secret = GetSecret(prop.Children().First().ToObject<SecretsPropertiesConfig>());
|
||||||
//var secret = GetSecret(JsonConvert.DeserializeObject<SecretsPropertiesConfig>(prop.Children().First().ToString()));
|
|
||||||
prop.Parent.Replace(secret);
|
prop.Parent.Replace(secret);
|
||||||
}
|
}
|
||||||
var recurseProp = prop.Value as JObject;
|
|
||||||
if (recurseProp == null) return;
|
if (!(prop.Value is JObject recurseProp)) continue;
|
||||||
|
|
||||||
CheckForSecrets(recurseProp.Properties());
|
CheckForSecrets(recurseProp.Properties());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,66 +166,70 @@ namespace PepperDash.Essentials.Core
|
|||||||
var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider);
|
var secretProvider = SecretsManager.GetSecretProviderByKey(data.Provider);
|
||||||
if (secretProvider == null) return null;
|
if (secretProvider == null) return null;
|
||||||
var secret = secretProvider.GetSecret(data.Key);
|
var secret = secretProvider.GetSecret(data.Key);
|
||||||
if (secret != null) return (string) secret.Value;
|
if (secret != null) return (string)secret.Value;
|
||||||
Debug.LogMessage(LogEventLevel.Debug,
|
Debug.LogMessage(LogEventLevel.Debug,
|
||||||
"Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider",
|
"Unable to retrieve secret {0}{1} - Make sure you've added it to the secrets provider",
|
||||||
data.Provider, data.Key);
|
data.Provider, data.Key);
|
||||||
return String.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The factory method for Core "things". Also iterates the Factory methods that have
|
/// Creates and returns a device instance based on the provided <see cref="DeviceConfig"/>.
|
||||||
/// been loaded from plugins
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dc"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <summary>
|
|
||||||
/// GetDevice method
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>This method attempts to create a device using the type specified in the <paramref name="dc"/>
|
||||||
|
/// 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 <see
|
||||||
|
/// langword="null"/>.</remarks>
|
||||||
|
/// <param name="dc">The configuration object containing the key, name, type, and properties required to create the device.</param>
|
||||||
|
/// <returns>An instance of a device that implements <see cref="IKeyed"/>, or <see langword="null"/> if the device type is
|
||||||
|
/// not recognized or an error occurs during creation.</returns>
|
||||||
public static IKeyed GetDevice(DeviceConfig dc)
|
public static IKeyed GetDevice(DeviceConfig dc)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading '{0}' from Essentials Core", dc.Type);
|
|
||||||
|
|
||||||
var localDc = new DeviceConfig(dc);
|
var localDc = new DeviceConfig(dc);
|
||||||
|
|
||||||
var key = localDc.Key;
|
var key = localDc.Key;
|
||||||
var name = localDc.Name;
|
var name = localDc.Name;
|
||||||
var type = localDc.Type;
|
var type = localDc.Type;
|
||||||
var properties = localDc.Properties;
|
var properties = localDc.Properties;
|
||||||
//var propRecurse = properties;
|
|
||||||
|
|
||||||
var typeName = localDc.Type.ToLower();
|
var typeName = localDc.Type.ToLower();
|
||||||
|
|
||||||
|
if (properties is JObject jObject)
|
||||||
var jObject = properties as JObject;
|
|
||||||
if (jObject != null)
|
|
||||||
{
|
{
|
||||||
var jProp = jObject.Properties();
|
var jProp = jObject.Properties();
|
||||||
|
|
||||||
CheckForSecrets(jProp);
|
CheckForSecrets(jProp);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "typeName = {0}", typeName);
|
if (!FactoryMethods.TryGetValue(typeName, out var wrapper))
|
||||||
// Check for types that have been added by plugin dlls.
|
{
|
||||||
return !FactoryMethods.ContainsKey(typeName) ? null : FactoryMethods[typeName].FactoryMethod(localDc);
|
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)
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prints the type names and associated metadata from the FactoryMethods collection.
|
/// Displays a list of device factory types that match the specified filter.
|
||||||
/// </summary>
|
|
||||||
/// <param name="filter"></param>
|
|
||||||
/// <summary>
|
|
||||||
/// GetDeviceFactoryTypes method
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>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."</remarks>
|
||||||
|
/// <param name="filter">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.</param>
|
||||||
public static void GetDeviceFactoryTypes(string filter)
|
public static void GetDeviceFactoryTypes(string filter)
|
||||||
{
|
{
|
||||||
var types = !string.IsNullOrEmpty(filter)
|
var types = !string.IsNullOrEmpty(filter)
|
||||||
@@ -212,16 +255,18 @@ namespace PepperDash.Essentials.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the device factory dictionary
|
/// Retrieves a dictionary of device factory wrappers, optionally filtered by a specified string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filter"></param>
|
/// <param name="filter">A string used to filter the dictionary keys. Only entries with keys containing the specified filter will be
|
||||||
/// <returns></returns>
|
/// included. If <see langword="null"/> or empty, all entries are returned.</param>
|
||||||
public static Dictionary<string, DeviceFactoryWrapper> GetDeviceFactoryDictionary(string filter)
|
/// <returns>A dictionary where the keys are strings representing device identifiers and the values are <see
|
||||||
{
|
/// cref="DeviceFactoryWrapper"/> instances. The dictionary may be empty if no entries match the filter.</returns>
|
||||||
return string.IsNullOrEmpty(filter)
|
public static Dictionary<string, DeviceFactoryWrapper> GetDeviceFactoryDictionary(string filter)
|
||||||
? FactoryMethods
|
{
|
||||||
: FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value);
|
return string.IsNullOrEmpty(filter)
|
||||||
}
|
? FactoryMethods
|
||||||
|
: FactoryMethods.Where(k => k.Key.Contains(filter)).ToDictionary(k => k.Key, k => k.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Essentials.Core.Config;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wraps a device factory, providing metadata and a factory method for creating devices.
|
||||||
|
/// </summary>
|
||||||
|
public class DeviceFactoryWrapper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type associated with the current instance.
|
||||||
|
/// </summary>
|
||||||
|
public Type Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the description associated with the object.
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the factory method used to create an <see cref="IKeyed"/> instance based on the provided <see
|
||||||
|
/// cref="DeviceConfig"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The factory method allows customization of how <see cref="IKeyed"/> instances are created for
|
||||||
|
/// specific <see cref="DeviceConfig"/> inputs. Ensure the delegate is not null before invoking it.</remarks>
|
||||||
|
public Func<DeviceConfig, IKeyed> FactoryMethod { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DeviceFactoryWrapper"/> class with default values.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The <see cref="Type"/> property is initialized to <see langword="null"/>, and the <see
|
||||||
|
/// cref="Description"/> property is set to "Not Available".</remarks>
|
||||||
|
public DeviceFactoryWrapper()
|
||||||
|
{
|
||||||
|
Type = null;
|
||||||
|
Description = "Not Available";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
namespace PepperDash.Essentials.Core
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using PepperDash.Essentials.Core.Config;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the contract for IDeviceFactory
|
/// Defines the contract for IDeviceFactory
|
||||||
@@ -6,8 +10,21 @@
|
|||||||
public interface IDeviceFactory
|
public interface IDeviceFactory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads all the types to the DeviceFactory
|
/// Gets the type of the factory associated with the current instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void LoadTypeFactories();
|
Type FactoryType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of type names associated with the current plugin.
|
||||||
|
/// </summary>
|
||||||
|
List<string> TypeNames { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds and returns an <see cref="EssentialsDevice"/> instance based on the provided configuration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="deviceConfig">The configuration settings used to initialize the device. This parameter cannot be null.</param>
|
||||||
|
/// <returns>An <see cref="EssentialsDevice"/> instance configured according to the specified <paramref
|
||||||
|
/// name="deviceConfig"/>.</returns>
|
||||||
|
EssentialsDevice BuildDevice(DeviceConfig deviceConfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
/// it will NOT reflect an actual value from a device until <seealso cref="FireUpdate"/> has been called
|
/// it will NOT reflect an actual value from a device until <seealso cref="FireUpdate"/> has been called
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="valueFunc">Delegate to invoke when this feedback needs to be updated</param>
|
/// <param name="valueFunc">Delegate to invoke when this feedback needs to be updated</param>
|
||||||
|
[Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")]
|
||||||
public BoolFeedback(Func<bool> valueFunc)
|
public BoolFeedback(Func<bool> valueFunc)
|
||||||
: this(null, valueFunc)
|
: this(null, valueFunc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,45 +9,54 @@ using PepperDash.Core;
|
|||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
public abstract class Feedback : IKeyed
|
/// <summary>
|
||||||
{
|
/// Base class for all feedback types
|
||||||
public event EventHandler<FeedbackEventArgs> OutputChange;
|
/// </summary>
|
||||||
|
public abstract class Feedback : IKeyed
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when the output value changes
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<FeedbackEventArgs> OutputChange;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Key
|
/// Gets or sets the Key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Key { get; private set; }
|
public string Key { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the BoolValue
|
/// Gets or sets the BoolValue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual bool BoolValue { get { return false; } }
|
public virtual bool BoolValue { get { return false; } }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the IntValue
|
/// Gets or sets the IntValue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual int IntValue { get { return 0; } }
|
public virtual int IntValue { get { return 0; } }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the StringValue
|
/// Gets or sets the StringValue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string StringValue { get { return ""; } }
|
public virtual string StringValue { get { return ""; } }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the SerialValue
|
/// Gets or sets the SerialValue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string SerialValue { get { return ""; } }
|
public virtual string SerialValue { get { return ""; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the InTestMode
|
/// Gets or sets the InTestMode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool InTestMode { get; protected set; }
|
public bool InTestMode { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base Constructor - empty
|
/// Base Constructor - empty
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Feedback()
|
[Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")]
|
||||||
{
|
protected Feedback() : this(null) { }
|
||||||
}
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor with Key parameter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key for the feedback</param>
|
||||||
protected Feedback(string key)
|
protected Feedback(string key)
|
||||||
{
|
{
|
||||||
if (key == null)
|
if (key == null)
|
||||||
@@ -58,27 +67,27 @@ namespace PepperDash.Essentials.Core
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ClearTestValue method
|
/// ClearTestValue method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ClearTestValue()
|
public void ClearTestValue()
|
||||||
{
|
{
|
||||||
InTestMode = false;
|
InTestMode = false;
|
||||||
FireUpdate();
|
FireUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fires an update synchronously
|
/// Fires an update synchronously
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void FireUpdate();
|
public abstract void FireUpdate();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fires the update asynchronously within a CrestronInvoke
|
/// Fires the update asynchronously within a CrestronInvoke
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void InvokeFireUpdate()
|
public void InvokeFireUpdate()
|
||||||
{
|
{
|
||||||
CrestronInvoke.BeginInvoke(o => FireUpdate());
|
CrestronInvoke.BeginInvoke(o => FireUpdate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper method that fires event. Use this intstead of calling OutputChange
|
/// Helper method that fires event. Use this intstead of calling OutputChange
|
||||||
@@ -103,5 +112,5 @@ namespace PepperDash.Essentials.Core
|
|||||||
{
|
{
|
||||||
if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value));
|
if (OutputChange != null) OutputChange(this, new FeedbackEventArgs(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,6 +43,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
/// it will NOT reflect an actual value from a device until <seealso cref="FireUpdate"/> has been called
|
/// it will NOT reflect an actual value from a device until <seealso cref="FireUpdate"/> has been called
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="valueFunc">Delegate to invoke when this feedback needs to be updated</param>
|
/// <param name="valueFunc">Delegate to invoke when this feedback needs to be updated</param>
|
||||||
|
[Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")]
|
||||||
public IntFeedback(Func<int> valueFunc)
|
public IntFeedback(Func<int> valueFunc)
|
||||||
: this(null, valueFunc)
|
: this(null, valueFunc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SerialFeedback : Feedback
|
public class SerialFeedback : Feedback
|
||||||
{
|
{
|
||||||
public override string SerialValue { get { return _SerialValue; } }
|
public override string SerialValue { get { return _SerialValue; } }
|
||||||
string _SerialValue;
|
string _SerialValue;
|
||||||
|
|
||||||
//public override eCueType Type { get { return eCueType.Serial; } }
|
//public override eCueType Type { get { return eCueType.Serial; } }
|
||||||
@@ -25,6 +25,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
|
|
||||||
List<StringInputSig> LinkedInputSigs = new List<StringInputSig>();
|
List<StringInputSig> LinkedInputSigs = new List<StringInputSig>();
|
||||||
|
|
||||||
|
[Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")]
|
||||||
public SerialFeedback()
|
public SerialFeedback()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
/// it will NOT reflect an actual value from a device until <seealso cref="FireUpdate"/> has been called
|
/// it will NOT reflect an actual value from a device until <seealso cref="FireUpdate"/> has been called
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="valueFunc">Delegate to invoke when this feedback needs to be updated</param>
|
/// <param name="valueFunc">Delegate to invoke when this feedback needs to be updated</param>
|
||||||
|
[Obsolete("use constructor with Key parameter. This constructor will be removed in a future version")]
|
||||||
public StringFeedback(Func<string> valueFunc)
|
public StringFeedback(Func<string> valueFunc)
|
||||||
: this(null, valueFunc)
|
: this(null, valueFunc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using PepperDash.Core;
|
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
@@ -16,8 +16,16 @@ namespace PepperDash.Essentials.Core
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a class that is capable of loading custom plugin device types for development purposes
|
||||||
|
/// </summary>
|
||||||
|
[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
|
public interface IPluginDevelopmentDeviceFactory : IPluginDeviceFactory
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of all the development versions of the Essentials framework that are supported by this factory.
|
||||||
|
/// </summary>
|
||||||
List<string> DevelopmentEssentialsFrameworkVersions { get; }
|
List<string> DevelopmentEssentialsFrameworkVersions { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Crestron.SimplSharp;
|
|
||||||
// using Crestron.SimplSharp.CrestronIO;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Crestron.SimplSharp;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
@@ -28,10 +26,19 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The assembly for the Essentials Framework
|
||||||
|
/// </summary>
|
||||||
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The assembly for the PepperDash Core
|
||||||
|
/// </summary>
|
||||||
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of assemblies loaded from the Essentials plugins folder
|
||||||
|
/// </summary>
|
||||||
public static List<LoadedAssembly> EssentialsPluginAssemblies { get; private set; }
|
public static List<LoadedAssembly> EssentialsPluginAssemblies { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -131,7 +138,7 @@ namespace PepperDash.Essentials
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads an assembly via Reflection and adds it to the list of loaded assemblies
|
/// Loads an assembly via Reflection and adds it to the list of loaded assemblies
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fileName"></param>
|
/// <param name="filePath"></param>
|
||||||
static LoadedAssembly LoadAssembly(string filePath)
|
static LoadedAssembly LoadAssembly(string filePath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -153,7 +160,8 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
} catch(Exception ex)
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath);
|
Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath);
|
||||||
return null;
|
return null;
|
||||||
@@ -212,6 +220,20 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Associates the specified assembly with the given name in the loaded assemblies collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>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.</remarks>
|
||||||
|
/// <param name="name">The name used to identify the assembly. This value is case-sensitive and must not be null or empty.</param>
|
||||||
|
/// <param name="assembly">The assembly to associate with the specified name. This value must not be null.</param>
|
||||||
|
public static void AddLoadedAssembly(string name, Assembly assembly)
|
||||||
|
{
|
||||||
|
var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name));
|
||||||
|
|
||||||
|
loadedAssembly?.SetAssembly(assembly);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used by console command to report the currently loaded assemblies and versions
|
/// Used by console command to report the currently loaded assemblies and versions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -402,7 +424,7 @@ namespace PepperDash.Essentials
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var assy = loadedAssembly.Assembly;
|
var assy = loadedAssembly.Assembly;
|
||||||
Type[] types = {};
|
Type[] types = { };
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
types = assy.GetTypes();
|
types = assy.GetTypes();
|
||||||
@@ -419,8 +441,8 @@ namespace PepperDash.Essentials
|
|||||||
foreach (var type in types)
|
foreach (var type in types)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
|
if (typeof(IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
|
||||||
{
|
{
|
||||||
var plugin =
|
var plugin =
|
||||||
(IPluginDeviceFactory)Activator.CreateInstance(type);
|
(IPluginDeviceFactory)Activator.CreateInstance(type);
|
||||||
@@ -454,84 +476,62 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads a
|
/// Loads a custom plugin and performs a dependency check to ensure compatibility with the required Essentials
|
||||||
|
/// framework version.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="plugin"></param>
|
/// <remarks>This method verifies that the plugin meets the minimum required Essentials framework version
|
||||||
/// <param name="loadedAssembly"></param>
|
/// before loading it. If the plugin fails the dependency check, it is skipped, and a log message is generated. If
|
||||||
static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly)
|
/// the plugin passes the check, it is loaded, and its type factories are initialized.</remarks>
|
||||||
|
/// <param name="pluginDeviceFactory">The plugin to be loaded, implementing the <see cref="IPluginDeviceFactory"/> interface. If the plugin also
|
||||||
|
/// implements <see cref="IPluginDevelopmentDeviceFactory"/>, additional checks for development versions are
|
||||||
|
/// performed.</param>
|
||||||
|
/// <param name="loadedAssembly">The assembly associated with the plugin being loaded. This is used for logging and tracking purposes.</param>
|
||||||
|
static void LoadCustomPlugin(IPluginDeviceFactory pluginDeviceFactory, LoadedAssembly loadedAssembly)
|
||||||
{
|
{
|
||||||
var developmentPlugin = plugin as IPluginDevelopmentDeviceFactory;
|
var passed = pluginDeviceFactory is IPluginDevelopmentDeviceFactory developmentPlugin ? Global.IsRunningDevelopmentVersion
|
||||||
|
(developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
|
||||||
var passed = developmentPlugin != null ? Global.IsRunningDevelopmentVersion
|
: Global.IsRunningMinimumVersionOrHigher(pluginDeviceFactory.MinimumEssentialsFrameworkVersion);
|
||||||
(developmentPlugin.DevelopmentEssentialsFrameworkVersions, developmentPlugin.MinimumEssentialsFrameworkVersion)
|
|
||||||
: Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion);
|
|
||||||
|
|
||||||
if (!passed)
|
if (!passed)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information,
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
"\r\n********************\r\n\tPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n********************",
|
"\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;
|
return;
|
||||||
}
|
}
|
||||||
else
|
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);
|
Debug.LogMessage(LogEventLevel.Information, "Loading plugin factory: {0}", loadedAssembly.Name);
|
||||||
plugin.LoadTypeFactories();
|
|
||||||
|
|
||||||
if(!EssentialsPluginAssemblies.Contains(loadedAssembly))
|
LoadDeviceFactories(pluginDeviceFactory);
|
||||||
|
|
||||||
|
if (!EssentialsPluginAssemblies.Contains(loadedAssembly))
|
||||||
EssentialsPluginAssemblies.Add(loadedAssembly);
|
EssentialsPluginAssemblies.Add(loadedAssembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads a a custom plugin via the legacy method
|
/// Loads device factories from the specified plugin device factory and registers them for use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type"></param>
|
/// <remarks>This method retrieves metadata from the provided <paramref name="deviceFactory"/>, including
|
||||||
/// <param name="loadPlugin"></param>
|
/// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
|
||||||
static void LoadCustomLegacyPlugin(Type type, MethodInfo loadPlugin, LoadedAssembly loadedAssembly)
|
/// names are converted to lowercase for registration.</remarks>
|
||||||
|
/// <param name="deviceFactory">The plugin device factory that provides the device types, descriptions, and factory methods to be registered.</param>
|
||||||
|
private static void LoadDeviceFactories(IPluginDeviceFactory deviceFactory)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "LoadPlugin method found in {0}", type.Name);
|
foreach (var typeName in deviceFactory.TypeNames)
|
||||||
|
|
||||||
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static);
|
|
||||||
|
|
||||||
var minimumVersion = fields.FirstOrDefault(p => p.Name.Equals("MinimumEssentialsFrameworkVersion"));
|
|
||||||
if (minimumVersion != null)
|
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "MinimumEssentialsFrameworkVersion found");
|
string description = deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0
|
||||||
|
? descriptionAttribute[0].Description
|
||||||
|
: "No description available";
|
||||||
|
|
||||||
var minimumVersionString = minimumVersion.GetValue(null) as string;
|
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(minimumVersionString))
|
|
||||||
{
|
|
||||||
var passed = Global.IsRunningMinimumVersionOrHigher(minimumVersionString);
|
|
||||||
|
|
||||||
if (!passed)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Plugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin", minimumVersionString);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Passed plugin passed dependency check (required version {0})", minimumVersionString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "MinimumEssentialsFrameworkVersion found but not set. Loading plugin, but your mileage may vary.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "MinimumEssentialsFrameworkVersion not found. Loading plugin, but your mileage may vary.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading legacy plugin: {0}", loadedAssembly.Name);
|
|
||||||
loadPlugin.Invoke(null, null);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// LoadPlugins method
|
/// LoadPlugins method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -567,13 +567,30 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class LoadedAssembly
|
public class LoadedAssembly
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the assembly
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("name")]
|
[JsonProperty("name")]
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the version of the assembly
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("version")]
|
[JsonProperty("version")]
|
||||||
public string Version { get; private set; }
|
public string Version { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the assembly
|
||||||
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Assembly Assembly { get; private set; }
|
public Assembly Assembly { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the LoadedAssembly class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the assembly</param>
|
||||||
|
/// <param name="version">The version of the assembly</param>
|
||||||
|
/// <param name="assembly">The assembly</param>
|
||||||
public LoadedAssembly(string name, string version, Assembly assembly)
|
public LoadedAssembly(string name, string version, Assembly assembly)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
|
||||||
@@ -28,6 +25,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// For rooms with multiple displays
|
/// For rooms with multiple displays
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Will be removed in a future version")]
|
||||||
public interface IHasMultipleDisplays
|
public interface IHasMultipleDisplays
|
||||||
{
|
{
|
||||||
Dictionary<eSourceListItemDestinationTypes, IRoutingSink> Displays { get; }
|
Dictionary<eSourceListItemDestinationTypes, IRoutingSink> Displays { get; }
|
||||||
@@ -40,7 +38,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
{
|
{
|
||||||
void RunRouteAction(string routeKey, string sourceListKey);
|
void RunRouteAction(string routeKey, string sourceListKey);
|
||||||
|
|
||||||
void RunRouteAction(string routeKey, string sourceListKey, Action successCallback);
|
void RunRouteAction(string routeKey, string sourceListKey, Action successCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -50,7 +48,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
{
|
{
|
||||||
void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo);
|
void RunDirectRoute(string sourceKey, string destinationKey, eRoutingSignalType type = eRoutingSignalType.AudioVideo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes a room with matrix routing
|
/// Describes a room with matrix routing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -139,7 +137,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
bool HasEnvironmentalControlDevices { get; }
|
bool HasEnvironmentalControlDevices { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IRoomOccupancy:IKeyed
|
public interface IRoomOccupancy : IKeyed
|
||||||
{
|
{
|
||||||
IOccupancyStatusProvider RoomOccupancy { get; }
|
IOccupancyStatusProvider RoomOccupancy { get; }
|
||||||
bool OccupancyStatusProviderIsRemote { get; }
|
bool OccupancyStatusProviderIsRemote { get; }
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Devices.Common
|
|||||||
{
|
{
|
||||||
var assy = Assembly.GetExecutingAssembly();
|
var assy = Assembly.GetExecutingAssembly();
|
||||||
PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
|
PluginLoader.SetEssentialsAssembly(assy.GetName().Name, assy);
|
||||||
|
|
||||||
var types = assy.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
|
var types = assy.GetTypes().Where(ct => typeof(IDeviceFactory).IsAssignableFrom(ct) && !ct.IsInterface && !ct.IsAbstract);
|
||||||
|
|
||||||
if (types != null)
|
if (types != null)
|
||||||
@@ -29,7 +29,7 @@ namespace PepperDash.Essentials.Devices.Common
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||||
factory.LoadTypeFactories();
|
LoadDeviceFactories(factory);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -38,5 +38,25 @@ namespace PepperDash.Essentials.Devices.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads device factories from the specified plugin device factory and registers them for use.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This method retrieves metadata from the provided <paramref name="deviceFactory"/>, including
|
||||||
|
/// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
|
||||||
|
/// names are converted to lowercase for registration.</remarks>
|
||||||
|
/// <param name="deviceFactory">The plugin device factory that provides the device types, descriptions, and factory methods to be registered.</param>
|
||||||
|
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);
|
||||||
|
string description = (deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0)
|
||||||
|
? descriptionAttribute[0].Description
|
||||||
|
: "No description available";
|
||||||
|
|
||||||
|
Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using PepperDash.Core;
|
using System;
|
||||||
using PepperDash.Essentials.Core;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Essentials.Core;
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
@@ -30,7 +30,7 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||||
|
|
||||||
factory.LoadTypeFactories();
|
LoadDeviceFactories(factory);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -38,5 +38,24 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads device factories from the specified plugin device factory and registers them for use.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This method retrieves metadata from the provided <paramref name="deviceFactory"/>, including
|
||||||
|
/// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
|
||||||
|
/// names are converted to lowercase for registration.</remarks>
|
||||||
|
/// <param name="deviceFactory">The plugin device factory that provides the device types, descriptions, and factory methods to be registered.</param>
|
||||||
|
private static void LoadDeviceFactories(IDeviceFactory deviceFactory)
|
||||||
|
{
|
||||||
|
foreach (var typeName in deviceFactory.TypeNames)
|
||||||
|
{
|
||||||
|
string description = (deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0)
|
||||||
|
? descriptionAttribute[0].Description
|
||||||
|
: "No description available"; // Default value if no DescriptionAttribute is found
|
||||||
|
|
||||||
|
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using System.Reflection;
|
|
||||||
using Crestron.SimplSharpPro;
|
using Crestron.SimplSharpPro;
|
||||||
using Crestron.SimplSharpPro.CrestronThread;
|
using Crestron.SimplSharpPro.CrestronThread;
|
||||||
using Crestron.SimplSharpPro.Diagnostics;
|
using Crestron.SimplSharpPro.Diagnostics;
|
||||||
@@ -9,12 +11,9 @@ using PepperDash.Core;
|
|||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
using PepperDash.Essentials.Core.Bridges;
|
using PepperDash.Essentials.Core.Bridges;
|
||||||
using PepperDash.Essentials.Core.Config;
|
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.Routing;
|
||||||
|
using PepperDash.Essentials.Core.Web;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
@@ -46,22 +45,22 @@ namespace PepperDash.Essentials
|
|||||||
// AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
|
// 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")
|
if (assemblyName == "PepperDash_Core")
|
||||||
{
|
{
|
||||||
return System.Reflection.Assembly.LoadFrom("PepperDashCore.dll");
|
return Assembly.LoadFrom("PepperDashCore.dll");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assemblyName == "PepperDash_Essentials_Core")
|
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")
|
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;
|
return null;
|
||||||
@@ -79,7 +78,7 @@ namespace PepperDash.Essentials
|
|||||||
if (preventInitializationComplete)
|
if (preventInitializationComplete)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "******************* InitializeSystem() Entering **********************");
|
Debug.LogMessage(LogEventLevel.Debug, "******************* InitializeSystem() Entering **********************");
|
||||||
|
|
||||||
_startTimer = new CTimer(StartSystem, preventInitializationComplete, StartupTime);
|
_startTimer = new CTimer(StartSystem, preventInitializationComplete, StartupTime);
|
||||||
_initializeEvent = new CEvent(true, false);
|
_initializeEvent = new CEvent(true, false);
|
||||||
DeviceManager.AllDevicesRegistered += (o, a) =>
|
DeviceManager.AllDevicesRegistered += (o, a) =>
|
||||||
@@ -88,7 +87,7 @@ namespace PepperDash.Essentials
|
|||||||
};
|
};
|
||||||
_initializeEvent.Wait(30000);
|
_initializeEvent.Wait(30000);
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "******************* InitializeSystem() Exiting **********************");
|
Debug.LogMessage(LogEventLevel.Debug, "******************* InitializeSystem() Exiting **********************");
|
||||||
|
|
||||||
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
|
SystemMonitor.ProgramInitialization.ProgramInitializationComplete = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -99,7 +98,7 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
private void StartSystem(object preventInitialization)
|
private void StartSystem(object preventInitialization)
|
||||||
{
|
{
|
||||||
Debug.SetErrorLogMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose);
|
Debug.SetErrorLogMinimumDebugLevel(LogEventLevel.Verbose);
|
||||||
|
|
||||||
DeterminePlatform();
|
DeterminePlatform();
|
||||||
|
|
||||||
@@ -201,8 +200,8 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
userFolder = "User";
|
userFolder = "User";
|
||||||
nvramFolder = "Nvram";
|
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{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");
|
//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
|
if (Directory.Exists(Global.ApplicationDirectoryPathPrefix + dirSeparator + userFolder
|
||||||
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
|
+ 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
|
filePathPrefix = directoryPrefix + dirSeparator + userFolder
|
||||||
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
|
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
|
||||||
}
|
}
|
||||||
@@ -220,7 +219,7 @@ namespace PepperDash.Essentials
|
|||||||
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
|
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber)))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "{nvramFolder:l}/program{applicationNumber} directory found", nvramFolder, InitialParametersClass.ApplicationNumber);
|
Debug.LogMessage(LogEventLevel.Information, "{nvramFolder:l}/program{applicationNumber} directory found", nvramFolder, InitialParametersClass.ApplicationNumber);
|
||||||
|
|
||||||
filePathPrefix = directoryPrefix + dirSeparator + nvramFolder
|
filePathPrefix = directoryPrefix + dirSeparator + nvramFolder
|
||||||
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
|
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
|
||||||
}
|
}
|
||||||
@@ -228,7 +227,7 @@ namespace PepperDash.Essentials
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
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
|
filePathPrefix = directoryPrefix + dirSeparator + userFolder
|
||||||
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
|
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
|
||||||
}
|
}
|
||||||
@@ -236,7 +235,7 @@ namespace PepperDash.Essentials
|
|||||||
else // Handles Linux OS (Virtual Control)
|
else // Handles Linux OS (Virtual Control)
|
||||||
{
|
{
|
||||||
//Debug.SetDebugLevel(2);
|
//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/
|
// Set path to User/
|
||||||
filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator;
|
filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator;
|
||||||
@@ -246,7 +245,7 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
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();
|
PluginLoader.AddProgramAssemblies();
|
||||||
|
|
||||||
_ = new Core.DeviceFactory();
|
_ = new Core.DeviceFactory();
|
||||||
_ = new Devices.Common.DeviceFactory();
|
// _ = new Devices.Common.DeviceFactory();
|
||||||
_ = new DeviceFactory();
|
// _ = new DeviceFactory();
|
||||||
|
|
||||||
_ = new ProcessorExtensionDeviceFactory();
|
// _ = new ProcessorExtensionDeviceFactory();
|
||||||
_ = new MobileControlFactory();
|
// _ = new MobileControlFactory();
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials load from configuration");
|
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials load from configuration");
|
||||||
|
|
||||||
@@ -313,7 +312,7 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifies filesystem is set up. IR, SGD, and programX folders
|
/// Verifies filesystem is set up. IR, SGD, and programX folders
|
||||||
@@ -333,46 +332,46 @@ namespace PepperDash.Essentials
|
|||||||
Directory.Create(irDir);
|
Directory.Create(irDir);
|
||||||
|
|
||||||
var sgdDir = Global.FilePathPrefix + "sgd";
|
var sgdDir = Global.FilePathPrefix + "sgd";
|
||||||
if (!Directory.Exists(sgdDir))
|
if (!Directory.Exists(sgdDir))
|
||||||
Directory.Create(sgdDir);
|
Directory.Create(sgdDir);
|
||||||
|
|
||||||
var pluginDir = Global.FilePathPrefix + "plugins";
|
var pluginDir = Global.FilePathPrefix + "plugins";
|
||||||
if (!Directory.Exists(pluginDir))
|
if (!Directory.Exists(pluginDir))
|
||||||
Directory.Create(pluginDir);
|
Directory.Create(pluginDir);
|
||||||
|
|
||||||
var joinmapDir = Global.FilePathPrefix + "joinmaps";
|
var joinmapDir = Global.FilePathPrefix + "joinmaps";
|
||||||
if(!Directory.Exists(joinmapDir))
|
if (!Directory.Exists(joinmapDir))
|
||||||
Directory.Create(joinmapDir);
|
Directory.Create(joinmapDir);
|
||||||
|
|
||||||
return configExists;
|
return configExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TearDown method
|
/// TearDown method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void TearDown()
|
public void TearDown()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Tearing down existing system");
|
Debug.LogMessage(LogEventLevel.Information, "Tearing down existing system");
|
||||||
DeviceManager.DeactivateAll();
|
DeviceManager.DeactivateAll();
|
||||||
|
|
||||||
TieLineCollection.Default.Clear();
|
TieLineCollection.Default.Clear();
|
||||||
|
|
||||||
foreach (var key in DeviceManager.GetDevices())
|
foreach (var key in DeviceManager.GetDevices())
|
||||||
DeviceManager.RemoveDevice(key);
|
DeviceManager.RemoveDevice(key);
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Tear down COMPLETE");
|
Debug.LogMessage(LogEventLevel.Information, "Tear down COMPLETE");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Load()
|
void Load()
|
||||||
{
|
{
|
||||||
LoadDevices();
|
LoadDevices();
|
||||||
LoadRooms();
|
LoadRooms();
|
||||||
LoadLogoServer();
|
LoadLogoServer();
|
||||||
|
|
||||||
DeviceManager.ActivateAll();
|
DeviceManager.ActivateAll();
|
||||||
|
|
||||||
LoadTieLines();
|
LoadTieLines();
|
||||||
|
|
||||||
@@ -381,8 +380,8 @@ namespace PepperDash.Essentials
|
|||||||
if (mobileControl == null) return;
|
if (mobileControl == null) return;
|
||||||
|
|
||||||
mobileControl.LinkSystemMonitorToAppServer();*/
|
mobileControl.LinkSystemMonitorToAppServer();*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// LoadDevices method
|
/// LoadDevices method
|
||||||
@@ -414,8 +413,8 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
var prompt = Global.ControlSystem.ControllerPrompt;
|
var prompt = Global.ControlSystem.ControllerPrompt;
|
||||||
|
|
||||||
var typeMatch = String.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) ||
|
var typeMatch = string.Equals(devConf.Type, prompt, StringComparison.OrdinalIgnoreCase) ||
|
||||||
String.Equals(devConf.Type, prompt.Replace("-", ""), StringComparison.OrdinalIgnoreCase);
|
string.Equals(devConf.Type, prompt.Replace("-", ""), StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
if (!typeMatch)
|
if (!typeMatch)
|
||||||
Debug.LogMessage(LogEventLevel.Information,
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
@@ -430,14 +429,14 @@ namespace PepperDash.Essentials
|
|||||||
if (newDev == null)
|
if (newDev == null)
|
||||||
newDev = Core.DeviceFactory.GetDevice(devConf);
|
newDev = Core.DeviceFactory.GetDevice(devConf);
|
||||||
|
|
||||||
if (newDev != null)
|
if (newDev != null)
|
||||||
DeviceManager.AddDevice(newDev);
|
DeviceManager.AddDevice(newDev);
|
||||||
else
|
else
|
||||||
Debug.LogMessage(LogEventLevel.Information, "ERROR: Cannot load unknown device type '{deviceType:l}', key '{deviceKey:l}'.", devConf.Type, devConf.Key);
|
Debug.LogMessage(LogEventLevel.Information, "ERROR: Cannot load unknown device type '{deviceType:l}', key '{deviceKey:l}'.", devConf.Type, devConf.Key);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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.");
|
Debug.LogMessage(LogEventLevel.Information, "All Devices Loaded.");
|
||||||
@@ -475,27 +474,28 @@ namespace PepperDash.Essentials
|
|||||||
/// LoadRooms method
|
/// LoadRooms method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void LoadRooms()
|
public void LoadRooms()
|
||||||
{
|
{
|
||||||
if (ConfigReader.ConfigObject.Rooms == null)
|
if (ConfigReader.ConfigObject.Rooms == null)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Notice: Configuration contains no rooms - Is this intentional? This may be a valid configuration.");
|
Debug.LogMessage(LogEventLevel.Information, "Notice: Configuration contains no rooms - Is this intentional? This may be a valid configuration.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
|
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var room = Core.DeviceFactory.GetDevice(roomConfig);
|
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);
|
Debug.LogWarning("ERROR: Cannot load unknown room type '{roomType:l}', key '{roomKey:l}'.", roomConfig.Type, roomConfig.Key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceManager.AddDevice(room);
|
DeviceManager.AddDevice(room);
|
||||||
} catch (Exception ex)
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(ex, "Exception loading room {roomKey}:{roomType}", null, roomConfig.Key, roomConfig.Type);
|
Debug.LogMessage(ex, "Exception loading room {roomKey}:{roomType}", null, roomConfig.Key, roomConfig.Type);
|
||||||
continue;
|
continue;
|
||||||
@@ -564,7 +564,7 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
catch
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
|
||||||
using Crestron.SimplSharpPro;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
using PepperDash.Essentials.Core.Config;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
@@ -39,14 +32,33 @@ namespace PepperDash.Essentials
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||||
factory.LoadTypeFactories();
|
LoadDeviceFactories(factory);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads device factories from the specified plugin device factory and registers them for use.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This method retrieves metadata from the provided <paramref name="deviceFactory"/>, including
|
||||||
|
/// type names, descriptions, and configuration snippets, and registers the factory for each device type. The type
|
||||||
|
/// names are converted to lowercase for registration.</remarks>
|
||||||
|
/// <param name="deviceFactory">The plugin device factory that provides the device types, descriptions, and factory methods to be registered.</param>
|
||||||
|
private static void LoadDeviceFactories(IDeviceFactory deviceFactory)
|
||||||
|
{
|
||||||
|
foreach (var typeName in deviceFactory.TypeNames)
|
||||||
|
{
|
||||||
|
string description = (deviceFactory.FactoryType.GetCustomAttributes(typeof(DescriptionAttribute), true) is DescriptionAttribute[] descriptionAttribute && descriptionAttribute.Length > 0)
|
||||||
|
? descriptionAttribute[0].Description
|
||||||
|
: "No description available";
|
||||||
|
|
||||||
|
Core.DeviceFactory.AddFactoryForType(typeName.ToLower(), description, deviceFactory.FactoryType, deviceFactory.BuildDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user