Compare commits

..

19 Commits

Author SHA1 Message Date
Nick Genovese
0107422507 refactor: remove unused assembly resolution logic from ControlSystem 2025-08-11 16:24:44 -04:00
Andrew Welker
bb4b2f88b6 Merge pull request #1304 from PepperDash/temp-to-dev
Temp to dev
2025-08-05 16:39:38 -05:00
Andrew Welker
a41aba1904 Merge pull request #1300 from PepperDash/temp-to-dev
Temp to dev
2025-07-28 11:54:11 -05:00
Neil Dorin
b47f1d6b77 Merge pull request #1293 from PepperDash/to-dev 2025-07-23 07:53:44 -06:00
Andrew Welker
fda4a5a816 Merge pull request #1282 from PepperDash/main
Update Dev
2025-07-04 10:45:35 -05:00
Andrew Welker
9f70e3c721 Merge pull request #1276 from PepperDash/temp-to-dev
Temp to dev
2025-06-26 14:16:36 -04:00
Andrew Welker
ec6aeb17f6 Merge pull request #1271 from PepperDash/temp-to-dev
Temp to dev
2025-05-19 16:52:45 -05:00
Neil Dorin
91dc655103 Merge pull request #1269 from PepperDash/camera-preset-fix 2025-05-14 09:42:11 -06:00
Andrew Welker
bf31fb10eb fix: use correct join for preset select 2025-05-14 10:39:42 -05:00
Neil Dorin
5e21bad596 Merge pull request #1266 from PepperDash/temp-to-dev 2025-05-02 12:23:51 -06:00
Neil Dorin
2368f0c8cc Merge pull request #1262 from PepperDash/temp-to-dev 2025-04-28 11:37:01 -06:00
Neil Dorin
be58a0bc29 Merge pull request #1260 from PepperDash/temp-to-dev 2025-04-24 09:32:32 -06:00
Neil Dorin
8406f69e0d Merge pull request #1257 from PepperDash/temp-to-dev 2025-04-18 11:46:18 -06:00
Andrew Welker
116d83394a Merge pull request #1255 from PepperDash/temp-to-dev
Temp to dev
2025-04-14 11:15:27 -05:00
Neil Dorin
9b8e452eb4 Merge pull request #1251 from PepperDash/temp-to-dev 2025-04-11 14:00:02 -06:00
Neil Dorin
c9d86bd5dd Merge pull request #1248 from PepperDash/temp-to-dev 2025-04-11 11:55:35 -06:00
Neil Dorin
b2b257020f Merge pull request #1246 from PepperDash/temp-to-dev 2025-04-08 13:48:10 -06:00
Neil Dorin
6f58e18d14 Merge pull request #1244 from PepperDash/temp-to-dev
Temp to dev
2025-04-04 10:30:10 -06:00
Neil Dorin
60fc0298ec Merge pull request #1242 from PepperDash/temp-to-dev
Temp to dev
2025-04-02 11:14:45 -06:00
15 changed files with 147 additions and 591 deletions

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>2.12.1-local</Version>
<Version>2.4.0-local</Version>
<InformationalVersion>$(Version)</InformationalVersion>
<Authors>PepperDash Technology</Authors>
<Company>PepperDash Technology</Company>

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
@@ -20,6 +19,7 @@ using Serilog.Templates;
namespace PepperDash.Core
{
/// <summary>
/// Contains debug commands for use in various situations
/// </summary>
public static class Debug
{
@@ -272,9 +272,6 @@ namespace PepperDash.Core
if (result != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
CrestronConsole.Print($"Unable to retrieve stored log level for {levelStoreKey}.\r\nError: {result}.\r\nSetting level to {LogEventLevel.Information}\r\n");
CrestronDataStoreStatic.SetLocalIntValue(levelStoreKey, (int)LogEventLevel.Information);
return LogEventLevel.Information;
}
@@ -349,13 +346,13 @@ namespace PepperDash.Core
if (levelString.Trim() == "?")
{
CrestronConsole.ConsoleCommandResponse(
"Used to set the minimum level of debug messages to be printed to the console:\r\n" +
$"{_logLevels[0]} = 0\r\n" +
$"{_logLevels[1]} = 1\r\n" +
$"{_logLevels[2]} = 2\r\n" +
$"{_logLevels[3]} = 3\r\n" +
$"{_logLevels[4]} = 4\r\n" +
$"{_logLevels[5]} = 5");
$@"Used to set the minimum level of debug messages to be printed to the console:
{_logLevels[0]} = 0
{_logLevels[1]} = 1
{_logLevels[2]} = 2
{_logLevels[3]} = 3
{_logLevels[4]} = 4
{_logLevels[5]} = 5");
return;
}
@@ -376,7 +373,7 @@ namespace PepperDash.Core
return;
}
if (Enum.TryParse<LogEventLevel>(levelString, true, out var levelEnum))
if (Enum.TryParse<LogEventLevel>(levelString, out var levelEnum))
{
SetDebugLevel(levelEnum);
return;

View File

@@ -1,5 +1,5 @@
using System;
using Serilog.Events;
using Serilog.Events;
using System;
using Log = PepperDash.Core.Debug;
namespace PepperDash.Core.Logging
@@ -11,7 +11,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogException(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogMessage(ex, message, device: device, args);
Log.LogMessage(ex, message, device, args);
}
/// <summary>
@@ -19,7 +19,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogVerbose(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogVerbose(ex, device, message, args);
Log.LogMessage(LogEventLevel.Verbose, ex, message, device, args);
}
/// <summary>
@@ -27,7 +27,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogVerbose(this IKeyed device, string message, params object[] args)
{
Log.LogVerbose(device, message, args);
Log.LogMessage(LogEventLevel.Verbose, device, message, args);
}
/// <summary>
@@ -35,7 +35,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogDebug(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogDebug(ex, device, message, args);
Log.LogMessage(LogEventLevel.Debug, ex, message, device, args);
}
/// <summary>
@@ -43,7 +43,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogDebug(this IKeyed device, string message, params object[] args)
{
Log.LogDebug(device, message, args);
Log.LogMessage(LogEventLevel.Debug, device, message, args);
}
/// <summary>
@@ -51,7 +51,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogInformation(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogInformation(ex, device, message, args);
Log.LogMessage(LogEventLevel.Information, ex, message, device, args);
}
/// <summary>
@@ -59,7 +59,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogInformation(this IKeyed device, string message, params object[] args)
{
Log.LogInformation(device, message, args);
Log.LogMessage(LogEventLevel.Information, device, message, args);
}
/// <summary>
@@ -67,7 +67,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogWarning(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogWarning(ex, device, message, args);
Log.LogMessage(LogEventLevel.Warning, ex, message, device, args);
}
/// <summary>
@@ -75,7 +75,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogWarning(this IKeyed device, string message, params object[] args)
{
Log.LogWarning(device, message, args);
Log.LogMessage(LogEventLevel.Warning, device, message, args);
}
/// <summary>
@@ -83,7 +83,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogError(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogError(ex, device, message, args);
Log.LogMessage(LogEventLevel.Error, ex, message, device, args);
}
/// <summary>
@@ -91,7 +91,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogError(this IKeyed device, string message, params object[] args)
{
Log.LogError(device, message, args);
Log.LogMessage(LogEventLevel.Error, device, message, args);
}
/// <summary>
@@ -99,7 +99,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogFatal(this IKeyed device, Exception ex, string message, params object[] args)
{
Log.LogFatal(ex, device, message, args);
Log.LogMessage(LogEventLevel.Fatal, ex, message, device, args);
}
/// <summary>
@@ -107,7 +107,7 @@ namespace PepperDash.Core.Logging
/// </summary>
public static void LogFatal(this IKeyed device, string message, params object[] args)
{
Log.LogFatal(device, message, args);
Log.LogMessage(LogEventLevel.Fatal, device, message, args);
}
}
}

View File

@@ -1,23 +0,0 @@
using System;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core.Config
{
/// <summary>
/// Represents the base properties for a streaming device.
/// </summary>
public class BaseStreamingDeviceProperties
{
/// <summary>
/// The multicast video address for the streaming device.
/// </summary>
[JsonProperty("multicastVideoAddress", NullValueHandling = NullValueHandling.Ignore)]
public string MulticastVideoAddress { get; set; }
/// <summary>
/// The multicast audio address for the streaming device.
/// </summary>
[JsonProperty("multicastAudioAddress", NullValueHandling = NullValueHandling.Ignore)]
public string MulticastAudioAddress { get; set; }
}
}

View File

@@ -475,9 +475,9 @@ namespace PepperDash.Essentials.Core
if (String.IsNullOrEmpty(s) || s.Contains("?"))
{
CrestronConsole.ConsoleCommandResponse(
"SETDEVICESTREAMDEBUG [{deviceKey}] [OFF |TX | RX | BOTH] [timeOutInMinutes]\r\n" +
" {deviceKey} [OFF | TX | RX | BOTH] - Device to set stream debugging on, and which setting to use\r\n" +
" timeOutInMinutes - Set timeout for stream debugging. Default is 30 minutes");
@"SETDEVICESTREAMDEBUG [{deviceKey}] [OFF |TX | RX | BOTH] [timeOutInMinutes]
{deviceKey} [OFF | TX | RX | BOTH] - Device to set stream debugging on, and which setting to use
timeOutInMinutes - Set timeout for stream debugging. Default is 30 minutes");
return;
}

View File

@@ -244,20 +244,6 @@ namespace PepperDash.Essentials.Core
/// </summary>
[JsonProperty("type")]
public eRoutingSignalType Type { get; set; }
/// <summary>
/// Key for a destination list item. If BOTH SourceListItemKey AND DestinationListItemKey are defined,
/// then the direct route method should be used.
/// </summary>
[JsonProperty("destinationListItemKey", NullValueHandling = NullValueHandling.Ignore)]
public string DestinationListItemKey { get; set; }
/// <summary>
/// Key for a source list item. If BOTH SourceListItemKey AND DestinationListItemKey are defined,
/// then the direct route method should be used.
/// </summary>
[JsonProperty("sourceListItemKey", NullValueHandling = NullValueHandling.Ignore)]
public string SourceListItemKey { get; set; }
}
/// <summary>

View File

@@ -135,7 +135,7 @@ namespace PepperDash.Essentials.Core
{
if (FactoryMethods.ContainsKey(typeName))
{
Debug.LogInformation("Unable to add type: '{typeName}'. Already exists in DeviceFactory", typeName);
Debug.LogInformation("Unable to add type: '{typeName}'. Already exists in DeviceFactory", typeName);
return;
}
@@ -217,8 +217,7 @@ namespace PepperDash.Essentials.Core
}
catch (Exception ex)
{
Debug.LogError(ex, "Exception occurred while creating device {key}: {message}", dc.Key, ex.Message);
Debug.LogDebug(ex, "Exception details: {stackTrace}", ex.StackTrace);
Debug.LogError(ex, "Exception occurred while creating device {0}: {1}", null, dc.Key, ex.Message);
return null;
}
}
@@ -250,9 +249,9 @@ namespace PepperDash.Essentials.Core
}
CrestronConsole.ConsoleCommandResponse(
"Type: '{0}'\r\n" +
" Type: '{1}'\r\n" +
" Description: {2}{3}", type.Key, Type, description, CrestronEnvironment.NewLine);
@"Type: '{0}'
Type: '{1}'
Description: {2}{3}", type.Key, Type, description, CrestronEnvironment.NewLine);
}
}

View File

@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Routing
{
@@ -25,19 +25,5 @@ namespace PepperDash.Essentials.Core.Routing
/// </summary>
Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; }
/// <summary>
/// Event raised when the current sources change.
/// </summary>
event EventHandler CurrentSourcesChanged;
/// <summary>
/// Sets the current source for a specific signal type.
/// This method updates the current source for the specified signal type and notifies any subscribers of the change.
/// </summary>
/// <param name="signalType">The signal type to update.</param>
/// <param name="sourceListKey">The key for the source list.</param>
/// <param name="sourceListItem">The source list item to set as the current source.</param>
void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem);
}
}

View File

@@ -22,38 +22,38 @@ namespace PepperDash.Essentials.Core.Config
/// The key of the source device.
/// </summary>
public string SourceKey { get; set; }
/// <summary>
/// The key of the source card (if applicable, e.g., in a modular chassis).
/// </summary>
/// <summary>
/// The key of the source card (if applicable, e.g., in a modular chassis).
/// </summary>
public string SourceCard { get; set; }
/// <summary>
/// The key of the source output port, used for routing configurations.
/// </summary>
/// <summary>
/// The key of the source output port, used for routing configurations.
/// </summary>
public string SourcePort { get; set; }
/// <summary>
/// Gets or sets the DestinationKey
/// </summary>
/// <summary>
/// Gets or sets the DestinationKey
/// </summary>
public string DestinationKey { get; set; }
/// <summary>
/// Gets or sets the DestinationCard
/// </summary>
/// <summary>
/// Gets or sets the DestinationCard
/// </summary>
public string DestinationCard { get; set; }
/// <summary>
/// Gets or sets the DestinationPort
/// </summary>
/// <summary>
/// Gets or sets the DestinationPort
/// </summary>
public string DestinationPort { get; set; }
/// <summary>
/// Optional override for the signal type of the tie line. If set, this overrides the destination port's type for routing calculations.
/// </summary>
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eRoutingSignalType? OverrideType { get; set; }
/// <summary>
/// Optional override for the signal type of the tie line. If set, this overrides the destination port's type for routing calculations.
/// </summary>
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eRoutingSignalType? OverrideType { get; set; }
/// <summary>
/// Returns the appropriate tie line for either a card-based device or
@@ -62,39 +62,40 @@ namespace PepperDash.Essentials.Core.Config
/// <returns>null if config data does not match ports, cards or devices</returns>
public TieLine GetTieLine()
{
Debug.LogInformation("Build TieLine: {config}", ToString());
Debug.LogMessage(LogEventLevel.Information, "Build TieLine: {0}",null, this);
// Get the source device
if (!(DeviceManager.GetDeviceForKey(SourceKey) is IRoutingOutputs sourceDev))
var sourceDev = DeviceManager.GetDeviceForKey(SourceKey) as IRoutingOutputs;
if (sourceDev == null)
{
LogError("Routable source not found");
return null;
}
// Get the destination device
if (!(DeviceManager.GetDeviceForKey(DestinationKey) is IRoutingInputs destDev))
var destDev = DeviceManager.GetDeviceForKey(DestinationKey) as IRoutingInputs;
if (destDev == null)
{
LogError("Routable destination not found");
return null;
}
//Get the source port
var sourceOutputPort = sourceDev.OutputPorts[SourcePort];
//Get the source port
var sourceOutputPort = sourceDev.OutputPorts[SourcePort];
if (sourceOutputPort == null)
if (sourceOutputPort == null)
{
LogError("Source does not contain port");
return null;
}
//Get the Destination port
var destinationInputPort = destDev.InputPorts[DestinationPort];
//Get the Destination port
var destinationInputPort = destDev.InputPorts[DestinationPort];
if (destinationInputPort == null)
{
LogError("Destination does not contain port");
return null;
}
if (destinationInputPort == null)
{
LogError("Destination does not contain port");
return null;
}
return new TieLine(sourceOutputPort, destinationInputPort, OverrideType);
}
@@ -103,9 +104,9 @@ namespace PepperDash.Essentials.Core.Config
/// Logs an error message related to creating this tie line configuration.
/// </summary>
/// <param name="msg">The specific error message.</param>
private void LogError(string msg)
void LogError(string msg)
{
Debug.LogError("Cannot create tie line: {message}", msg);
Debug.LogMessage(LogEventLevel.Error, "WARNING: Cannot create tie line: {message}:\r {tieLineConfig}",null, msg, this);
}
/// <summary>
@@ -114,7 +115,8 @@ namespace PepperDash.Essentials.Core.Config
/// <returns>A string describing the source and destination of the configured tie line.</returns>
public override string ToString()
{
return $"{SourceKey}.{SourceCard}.{SourcePort} --> {DestinationKey}.{DestinationCard}.{DestinationPort}";
return string.Format("{0}.{1}.{2} --> {3}.{4}.{5}", SourceKey, SourceCard, SourcePort,
DestinationKey, DestinationCard, DestinationPort);
}
}
}

View File

@@ -5,7 +5,6 @@ using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
@@ -53,9 +52,9 @@ namespace PepperDash.Essentials.Devices.Common.Displays
/// </summary>
public event SourceInfoChangeHandler CurrentSourceChange;
/// <summary>
/// Gets or sets the CurrentSourceInfoKey
/// </summary>
/// <summary>
/// Gets or sets the CurrentSourceInfoKey
/// </summary>
public string CurrentSourceInfoKey { get; set; }
/// <summary>
@@ -90,32 +89,29 @@ namespace PepperDash.Essentials.Devices.Common.Displays
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; private set; }
/// <inheritdoc />
public event EventHandler CurrentSourcesChanged;
/// <summary>
/// Gets feedback indicating whether the display is currently cooling down after being powered off.
/// </summary>
public BoolFeedback IsCoolingDownFeedback { get; protected set; }
/// <summary>
/// Gets or sets the IsWarmingUpFeedback
/// </summary>
/// <summary>
/// Gets or sets the IsWarmingUpFeedback
/// </summary>
public BoolFeedback IsWarmingUpFeedback { get; private set; }
/// <summary>
/// Gets or sets the UsageTracker
/// </summary>
/// <summary>
/// Gets or sets the UsageTracker
/// </summary>
public UsageTracking UsageTracker { get; set; }
/// <summary>
/// Gets or sets the WarmupTime
/// </summary>
/// <summary>
/// Gets or sets the WarmupTime
/// </summary>
public uint WarmupTime { get; set; }
/// <summary>
/// Gets or sets the CooldownTime
/// </summary>
/// <summary>
/// Gets or sets the CooldownTime
/// </summary>
public uint CooldownTime { get; set; }
/// <summary>
@@ -193,7 +189,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays
/// <summary>
/// Gets the collection of feedback objects for this display device.
/// </summary>
/// <inheritdoc />
/// <inheritdoc />
public virtual FeedbackCollection<Feedback> Feedbacks
{
get
@@ -382,53 +378,6 @@ namespace PepperDash.Essentials.Devices.Common.Displays
volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]);
}
/// <inheritdoc />
public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
{
foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType)))
{
var flagValue = Convert.ToInt32(type);
// Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag).
// (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set.
if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0)
{
this.LogDebug("Skipping {type}", type);
continue;
}
this.LogDebug("setting {type}", type);
if (signalType.HasFlag(type))
{
UpdateCurrentSources(type, sourceListKey, sourceListItem);
}
}
// Raise the CurrentSourcesChanged event
CurrentSourcesChanged?.Invoke(this, EventArgs.Empty);
}
private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
{
if (CurrentSources.ContainsKey(signalType))
{
CurrentSources[signalType] = sourceListItem;
}
else
{
CurrentSources.Add(signalType, sourceListItem);
}
// Update the current source key for the specified signal type
if (CurrentSourceKeys.ContainsKey(signalType))
{
CurrentSourceKeys[signalType] = sourceListKey;
}
else
{
CurrentSourceKeys.Add(signalType, sourceListKey);
}
}
}
/// <summary>

View File

@@ -1,221 +0,0 @@
using System;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.Codec;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides a messaging bridge for devices that implement call status interfaces
/// without requiring VideoCodecBase inheritance
/// </summary>
public class CallStatusMessenger : MessengerBase
{
/// <summary>
/// Device with dialer capabilities
/// </summary>
protected IHasDialer Dialer { get; private set; }
/// <summary>
/// Device with content sharing capabilities (optional)
/// </summary>
protected IHasContentSharing ContentSharing { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="key"></param>
/// <param name="dialer"></param>
/// <param name="messagePath"></param>
public CallStatusMessenger(string key, IHasDialer dialer, string messagePath)
: base(key, messagePath, dialer as IKeyName)
{
Dialer = dialer ?? throw new ArgumentNullException(nameof(dialer));
dialer.CallStatusChange += Dialer_CallStatusChange;
// Check for optional content sharing interface
if (dialer is IHasContentSharing contentSharing)
{
ContentSharing = contentSharing;
contentSharing.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange;
contentSharing.SharingSourceFeedback.OutputChange += SharingSourceFeedback_OutputChange;
}
}
/// <summary>
/// Handles call status changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Dialer_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{
try
{
SendFullStatus();
}
catch (Exception ex)
{
this.LogError(ex, "Error handling call status change: {error}", ex.Message);
}
}
/// <summary>
/// Handles content sharing status changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SharingContentIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PostStatusMessage(JToken.FromObject(new
{
sharingContentIsOn = e.BoolValue
}));
}
/// <summary>
/// Handles sharing source changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SharingSourceFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
PostStatusMessage(JToken.FromObject(new
{
sharingSource = e.StringValue
}));
}
/// <summary>
/// Gets active calls from the dialer
/// </summary>
/// <returns></returns>
private object GetActiveCalls()
{
// Try to get active calls if the dialer has an ActiveCalls property
var dialerType = Dialer.GetType();
var activeCallsProperty = dialerType.GetProperty("ActiveCalls");
if (activeCallsProperty != null && activeCallsProperty.PropertyType == typeof(System.Collections.Generic.List<CodecActiveCallItem>))
{
var activeCalls = activeCallsProperty.GetValue(Dialer) as System.Collections.Generic.List<CodecActiveCallItem>;
return activeCalls ?? new System.Collections.Generic.List<CodecActiveCallItem>();
}
// Return basic call status if no ActiveCalls property
return new { isInCall = Dialer.IsInCall };
}
/// <summary>
/// Sends full status message
/// </summary>
public void SendFullStatus()
{
var status = new
{
isInCall = Dialer.IsInCall,
calls = GetActiveCalls()
};
// Add content sharing status if available
if (ContentSharing != null)
{
var statusWithSharing = new
{
isInCall = Dialer.IsInCall,
calls = GetActiveCalls(),
sharingContentIsOn = ContentSharing.SharingContentIsOnFeedback.BoolValue,
sharingSource = ContentSharing.SharingSourceFeedback.StringValue
};
PostStatusMessage(JToken.FromObject(statusWithSharing));
}
else
{
PostStatusMessage(JToken.FromObject(status));
}
}
/// <summary>
/// Registers actions for call control
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus());
// Basic call control actions
AddAction("/dial", (id, content) =>
{
var msg = content.ToObject<MobileControlSimpleContent<string>>();
Dialer.Dial(msg.Value);
});
AddAction("/endAllCalls", (id, content) => Dialer.EndAllCalls());
AddAction("/dtmf", (id, content) =>
{
var msg = content.ToObject<MobileControlSimpleContent<string>>();
Dialer.SendDtmf(msg.Value);
});
// Call-specific actions (if active calls are available)
AddAction("/endCallById", (id, content) =>
{
var msg = content.ToObject<MobileControlSimpleContent<string>>();
var call = GetCallWithId(msg.Value);
if (call != null)
Dialer.EndCall(call);
});
AddAction("/acceptById", (id, content) =>
{
var msg = content.ToObject<MobileControlSimpleContent<string>>();
var call = GetCallWithId(msg.Value);
if (call != null)
Dialer.AcceptCall(call);
});
AddAction("/rejectById", (id, content) =>
{
var msg = content.ToObject<MobileControlSimpleContent<string>>();
var call = GetCallWithId(msg.Value);
if (call != null)
Dialer.RejectCall(call);
});
// Content sharing actions if available
if (ContentSharing != null)
{
AddAction("/startSharing", (id, content) => ContentSharing.StartSharing());
AddAction("/stopSharing", (id, content) => ContentSharing.StopSharing());
}
}
/// <summary>
/// Finds a call by ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private CodecActiveCallItem GetCallWithId(string id)
{
// Try to get call using reflection for ActiveCalls property
var dialerType = Dialer.GetType();
var activeCallsProperty = dialerType.GetProperty("ActiveCalls");
if (activeCallsProperty != null && activeCallsProperty.PropertyType == typeof(System.Collections.Generic.List<CodecActiveCallItem>))
{
var activeCalls = activeCallsProperty.GetValue(Dialer) as System.Collections.Generic.List<CodecActiveCallItem>;
if (activeCalls != null)
{
return activeCalls.FirstOrDefault(c => c.Id.Equals(id));
}
}
return null;
}
}
}

View File

@@ -1,77 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Represents a IHasCurrentSourceInfoMessenger
/// </summary>
public class CurrentSourcesMessenger : MessengerBase
{
private readonly ICurrentSources sourceDevice;
/// <summary>
/// Initializes a new instance of the <see cref="CurrentSourcesMessenger"/> class.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="messagePath">The message path.</param>
/// <param name="device">The device.</param>
public CurrentSourcesMessenger(string key, string messagePath, ICurrentSources device) : base(key, messagePath, device as IKeyName)
{
sourceDevice = device;
}
/// <summary>
/// Registers the actions for the messenger.
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) =>
{
var message = new CurrentSourcesStateMessage
{
CurrentSourceKeys = sourceDevice.CurrentSourceKeys,
CurrentSources = sourceDevice.CurrentSources
};
PostStatusMessage(message);
});
sourceDevice.CurrentSourcesChanged += (sender, e) =>
{
PostStatusMessage(JToken.FromObject(new
{
currentSourceKeys = sourceDevice.CurrentSourceKeys,
currentSources = sourceDevice.CurrentSources
}));
};
}
}
/// <summary>
/// Represents a CurrentSourcesStateMessage
/// </summary>
public class CurrentSourcesStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the CurrentSourceKey
/// </summary>
[JsonProperty("currentSourceKeys", NullValueHandling = NullValueHandling.Ignore)]
public Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; set; }
/// <summary>
/// Gets or sets the CurrentSource
/// </summary>
[JsonProperty("currentSources")]
public Dictionary<eRoutingSignalType, SourceListItem> CurrentSources { get; set; }
}
}

View File

@@ -54,18 +54,16 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// </summary>
public class CurrentSourceStateMessage : DeviceStateMessageBase
{
[JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)]
/// <summary>
/// Gets or sets the CurrentSourceKey
/// </summary>
[JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)]
public string CurrentSourceKey { get; set; }
[JsonProperty("currentSource")]
/// <summary>
/// Gets or sets the CurrentSource
/// </summary>
[JsonProperty("currentSource")]
public SourceListItem CurrentSource { get; set; }
}
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Crestron.SimplSharp;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Net.Http;
using Crestron.SimplSharp.WebScripting;
@@ -27,7 +21,6 @@ using PepperDash.Essentials.Core.Shades;
using PepperDash.Essentials.Core.Web;
using PepperDash.Essentials.Devices.Common.AudioCodec;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.Displays;
using PepperDash.Essentials.Devices.Common.Lighting;
using PepperDash.Essentials.Devices.Common.SoftCodec;
@@ -37,6 +30,12 @@ using PepperDash.Essentials.RoomBridges;
using PepperDash.Essentials.Services;
using PepperDash.Essentials.WebApiHandlers;
using PepperDash.Essentials.WebSocketServer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WebSocketSharp;
namespace PepperDash.Essentials
@@ -561,21 +560,6 @@ namespace PepperDash.Essentials
messengerAdded = true;
}
else if (device is IHasDialer dialer && !messengerAdded)
{
this.LogVerbose(
"Adding CallStatusMessenger for {deviceKey}", device.Key);
var messenger = new CallStatusMessenger(
$"{device.Key}-callStatus-{Key}",
dialer,
$"/device/{device.Key}"
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is AudioCodecBase audioCodec)
{
@@ -598,7 +582,7 @@ namespace PepperDash.Essentials
{
this.LogVerbose(
"Adding ISetTopBoxControlMessenger for {deviceKey}"
);
);
var messenger = new ISetTopBoxControlsMessenger(
$"{device.Key}-stb-{Key}",
@@ -615,7 +599,7 @@ namespace PepperDash.Essentials
{
this.LogVerbose(
"Adding IChannelMessenger for {deviceKey}", device.Key
);
);
var messenger = new IChannelMessenger(
$"{device.Key}-channel-{Key}",
@@ -630,7 +614,7 @@ namespace PepperDash.Essentials
if (device is IColor colorDevice)
{
this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key);
this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key);
var messenger = new IColorMessenger(
$"{device.Key}-color-{Key}",
@@ -645,7 +629,7 @@ namespace PepperDash.Essentials
if (device is IDPad dPadDevice)
{
this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key);
this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key);
var messenger = new IDPadMessenger(
$"{device.Key}-dPad-{Key}",
@@ -660,7 +644,7 @@ namespace PepperDash.Essentials
if (device is INumericKeypad nkDevice)
{
this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key);
this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key);
var messenger = new INumericKeypadMessenger(
$"{device.Key}-numericKeypad-{Key}",
@@ -675,7 +659,7 @@ namespace PepperDash.Essentials
if (device is IHasPowerControl pcDevice)
{
this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key);
this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key);
var messenger = new IHasPowerMessenger(
$"{device.Key}-powerControl-{Key}",
@@ -709,7 +693,7 @@ namespace PepperDash.Essentials
{
this.LogVerbose(
"Adding ITransportMessenger for {deviceKey}", device.Key
);
);
var messenger = new ITransportMessenger(
$"{device.Key}-transport-{Key}",
@@ -737,17 +721,6 @@ namespace PepperDash.Essentials
messengerAdded = true;
}
if (device is ICurrentSources currentSources)
{
this.LogVerbose("Adding CurrentSourcesMessenger for {deviceKey}", device.Key);
var messenger = new CurrentSourcesMessenger($"{device.Key}-currentSources-{Key}", $"/device/{device.Key}", currentSources);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is ISwitchedOutput switchedDevice)
{
this.LogVerbose(
@@ -1652,14 +1625,15 @@ namespace PepperDash.Essentials
if (Config.EnableApiServer)
{
CrestronConsole.ConsoleCommandResponse(
"Mobile Control Edge Server API Information:\r\n\r\n" +
"\tServer address: {0}\r\n" +
"\tSystem Name: {1}\r\n" +
"\tSystem URL: {2}\r\n" +
"\tSystem UUID: {3}\r\n" +
"\tSystem User code: {4}\r\n" +
"\tConnected?: {5}\r\n" +
"\tSeconds Since Last Ack: {6}\r\n",
@"Mobile Control Edge Server API Information:
Server address: {0}
System Name: {1}
System URL: {2}
System UUID: {3}
System User code: {4}
Connected?: {5}
Seconds Since Last Ack: {6}",
url,
name,
ConfigReader.ConfigObject.SystemUrl,
@@ -1672,8 +1646,10 @@ namespace PepperDash.Essentials
else
{
CrestronConsole.ConsoleCommandResponse(
"\r\nMobile Control Edge Server API Information:\r\n" +
" Not Enabled in Config.\r\n"
@"
Mobile Control Edge Server API Information:
Not Enabled in Config.
"
);
}
@@ -1684,17 +1660,21 @@ namespace PepperDash.Essentials
)
{
CrestronConsole.ConsoleCommandResponse(
"\r\nMobile Control Direct Server Information:\r\n" +
" User App URL: {0}\r\n" +
" Server port: {1}\r\n",
@"
Mobile Control Direct Server Information:
User App URL: {0}
Server port: {1}
",
string.Format("{0}[insert_client_token]", _directServer.UserAppUrlPrefix),
_directServer.Port
);
CrestronConsole.ConsoleCommandResponse(
"\r\n UI Client Info:\r\n" +
" Tokens Defined: {0}\r\n" +
" Clients Connected: {1}\r\n",
@"
UI Client Info:
Tokens Defined: {0}
Clients Connected: {1}
",
_directServer.UiClients.Count,
_directServer.ConnectedUiClientsCount
);
@@ -1712,13 +1692,15 @@ namespace PepperDash.Essentials
}
CrestronConsole.ConsoleCommandResponse(
"\r\nClient {0}:\r\n" +
"Room Key: {1}\r\n" +
"Touchpanel Key: {6}\r\n" +
"Token: {2}\r\n" +
"Client URL: {3}\r\n" +
"Connected: {4}\r\n" +
"Duration: {5}\r\n",
@"
Client {0}:
Room Key: {1}
Touchpanel Key: {6}
Token: {2}
Client URL: {3}
Connected: {4}
Duration: {5}
",
clientNo,
clientContext.Value.Token.RoomKey,
clientContext.Key,
@@ -1733,8 +1715,9 @@ namespace PepperDash.Essentials
else
{
CrestronConsole.ConsoleCommandResponse(
"\r\nMobile Control Direct Server Information:\r\n" +
" Not Enabled in Config.\r\n"
@"
Mobile Control Direct Server Infromation:
Not Enabled in Config."
);
}
}
@@ -2326,7 +2309,7 @@ namespace PepperDash.Essentials
{
this.LogInformation("-- Warning: Incoming message has no registered handler {type}", message.Type);
break;
}
}
foreach (var handler in handlers)
{

View File

@@ -41,29 +41,6 @@ namespace PepperDash.Essentials
SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true;
Debug.SetErrorLogMinimumDebugLevel(CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? LogEventLevel.Warning : LogEventLevel.Verbose);
// AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
}
private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{
var assemblyName = new AssemblyName(args.Name).Name;
if (assemblyName == "PepperDash_Core")
{
return Assembly.LoadFrom("PepperDashCore.dll");
}
if (assemblyName == "PepperDash_Essentials_Core")
{
return Assembly.LoadFrom("PepperDash.Essentials.Core.dll");
}
if (assemblyName == "Essentials Devices Common")
{
return Assembly.LoadFrom("PepperDash.Essentials.Devices.Common.dll");
}
return null;
}
/// <summary>