Compare commits

..

3 Commits

11 changed files with 193 additions and 384 deletions

View File

@@ -82,6 +82,10 @@ namespace PepperDash.Core
/// <summary>
/// InfinetEX control
/// </summary>
InfinetEx
InfinetEx,
/// <summary>
/// TCP/IP Server
/// </summary>
TcpServer
}
}

View File

@@ -2,29 +2,25 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.EthernetCommunication;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core.Config;
using Serilog.Events;
//using PepperDash.Essentials.Devices.Common.Cameras;
namespace PepperDash.Essentials.Core.Bridges
{
/// <summary>
/// Base class for bridge API variants
/// </summary>
[Obsolete("Will be removed in v3.0.0")]
public abstract class BridgeApi : EssentialsDevice
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="key">Device key</param>
protected BridgeApi(string key) :
base(key)
{
@@ -33,36 +29,23 @@ namespace PepperDash.Essentials.Core.Bridges
}
/// <summary>
/// Class to link devices and rooms to an EISC Instance
/// Represents a EiscApiAdvanced
/// </summary>
public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor
{
/// <summary>
/// Gets the PropertiesConfig
/// </summary>
public EiscApiPropertiesConfig PropertiesConfig { get; private set; }
/// <summary>
/// Gets the JoinMaps dictionary
/// </summary>
public Dictionary<string, JoinMapBaseAdvanced> JoinMaps { get; private set; }
/// <summary>
/// Gets the EISC instance
/// </summary>
public BasicTriList Eisc { get; private set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="dc">Device configuration</param>
/// <param name="eisc">EISC instance</param>
public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) :
base(dc.Key)
{
JoinMaps = new Dictionary<string, JoinMapBaseAdvanced>();
PropertiesConfig = dc.Properties.ToObject<EiscApiPropertiesConfig>();
//PropertiesConfig = JsonConvert.DeserializeObject<EiscApiPropertiesConfig>(dc.Properties.ToString());
Eisc = eisc;
@@ -77,7 +60,8 @@ namespace PepperDash.Essentials.Core.Bridges
/// <summary>
/// CustomActivate method
/// </summary>
/// </summary>
/// <inheritdoc />
public override bool CustomActivate()
{
CommunicationMonitor.Start();
@@ -99,7 +83,7 @@ namespace PepperDash.Essentials.Core.Bridges
if (PropertiesConfig.Devices == null)
{
this.LogDebug("No devices linked to this bridge");
Debug.LogMessage(LogEventLevel.Debug, this, "No devices linked to this bridge");
return;
}
@@ -120,7 +104,9 @@ namespace PepperDash.Essentials.Core.Bridges
continue;
}
this.LogWarning("{deviceKey} is not compatible with this bridge type. Please update the device.", device.Key);
Debug.LogMessage(LogEventLevel.Information, this,
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
device.Key);
}
}
@@ -135,31 +121,34 @@ namespace PepperDash.Essentials.Core.Bridges
if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success)
{
this.LogVerbose("Registration result: {registerResult}", registerResult);
Debug.LogMessage(LogEventLevel.Verbose, this, "Registration result: {0}", registerResult);
return;
}
this.LogDebug("EISC registration successful");
Debug.LogMessage(LogEventLevel.Debug, this, "EISC registration successful");
}
/// <summary>
/// Link rooms to this EISC. Rooms MUST implement IBridgeAdvanced
/// LinkRooms method
/// </summary>
public void LinkRooms()
{
this.LogDebug("Linking Rooms...");
Debug.LogMessage(LogEventLevel.Debug, this, "Linking Rooms...");
if (PropertiesConfig.Rooms == null)
{
this.LogDebug("No rooms linked to this bridge.");
Debug.LogMessage(LogEventLevel.Debug, this, "No rooms linked to this bridge.");
return;
}
foreach (var room in PropertiesConfig.Rooms)
{
if (!(DeviceManager.GetDeviceForKey(room.RoomKey) is IBridgeAdvanced rm))
var rm = DeviceManager.GetDeviceForKey(room.RoomKey) as IBridgeAdvanced;
if (rm == null)
{
this.LogDebug("Room {roomKey} does not implement IBridgeAdvanced. Skipping...", room.RoomKey);
Debug.LogMessage(LogEventLevel.Debug, this,
"Room {0} does not implement IBridgeAdvanced. Skipping...", room.RoomKey);
continue;
}
@@ -170,8 +159,11 @@ namespace PepperDash.Essentials.Core.Bridges
/// <summary>
/// Adds a join map
/// </summary>
/// <param name="deviceKey">The key of the device to add the join map for</param>
/// <param name="joinMap">The join map to add</param>
/// <param name="deviceKey"></param>
/// <param name="joinMap"></param>
/// <summary>
/// AddJoinMap method
/// </summary>
public void AddJoinMap(string deviceKey, JoinMapBaseAdvanced joinMap)
{
if (!JoinMaps.ContainsKey(deviceKey))
@@ -180,13 +172,14 @@ namespace PepperDash.Essentials.Core.Bridges
}
else
{
this.LogWarning("Unable to add join map with key '{deviceKey}'. Key already exists in JoinMaps dictionary", deviceKey);
Debug.LogMessage(LogEventLevel.Verbose, this, "Unable to add join map with key '{0}'. Key already exists in JoinMaps dictionary", deviceKey);
}
}
/// <summary>
/// PrintJoinMaps method
/// </summary>
/// </summary>
/// <inheritdoc />
public virtual void PrintJoinMaps()
{
CrestronConsole.ConsoleCommandResponse("Join Maps for EISC IPID: {0}\r\n", Eisc.ID.ToString("X"));
@@ -197,17 +190,17 @@ namespace PepperDash.Essentials.Core.Bridges
joinMap.Value.PrintJoinMapInfo();
}
}
/// <summary>
/// MarkdownForBridge method
/// </summary>
/// </summary>
/// <inheritdoc />
public virtual void MarkdownForBridge(string bridgeKey)
{
this.LogInformation("Writing Joinmaps to files for EISC IPID: {eiscId}", Eisc.ID.ToString("X"));
Debug.LogMessage(LogEventLevel.Information, this, "Writing Joinmaps to files for EISC IPID: {0}", Eisc.ID.ToString("X"));
foreach (var joinMap in JoinMaps)
{
this.LogInformation("Generating markdown for device '{deviceKey}':", joinMap.Key);
Debug.LogMessage(LogEventLevel.Information, "Generating markdown for device '{0}':", joinMap.Key);
joinMap.Value.MarkdownJoinMapInfo(joinMap.Key, bridgeKey);
}
}
@@ -215,45 +208,53 @@ namespace PepperDash.Essentials.Core.Bridges
/// <summary>
/// Prints the join map for a device by key
/// </summary>
/// <param name="deviceKey">The key of the device to print the join map for</param>
/// <param name="deviceKey"></param>
/// <summary>
/// PrintJoinMapForDevice method
/// </summary>
public void PrintJoinMapForDevice(string deviceKey)
{
var joinMap = JoinMaps[deviceKey];
if (joinMap == null)
{
this.LogInformation("Unable to find joinMap for device with key: '{deviceKey}'", deviceKey);
Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey);
return;
}
this.LogInformation("Join map for device '{deviceKey}' on EISC '{eiscKey}':", deviceKey, Key);
Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
joinMap.PrintJoinMapInfo();
}
/// <summary>
/// Prints the join map for a device by key in Markdown format
/// Prints the join map for a device by key
/// </summary>
/// <param name="deviceKey"></param>
/// <summary>
/// MarkdownJoinMapForDevice method
/// </summary>
/// <param name="deviceKey">The key of the device to print the join map for</param>
/// <param name="bridgeKey">The key of the bridge to use for the Markdown output</param>
public void MarkdownJoinMapForDevice(string deviceKey, string bridgeKey)
{
var joinMap = JoinMaps[deviceKey];
if (joinMap == null)
{
this.LogInformation("Unable to find joinMap for device with key: '{deviceKey}'", deviceKey);
Debug.LogMessage(LogEventLevel.Information, this, "Unable to find joinMap for device with key: '{0}'", deviceKey);
return;
}
this.LogInformation("Join map for device '{deviceKey}' on EISC '{eiscKey}':", deviceKey, Key);
Debug.LogMessage(LogEventLevel.Information, "Join map for device '{0}' on EISC '{1}':", deviceKey, Key);
joinMap.MarkdownJoinMapInfo(deviceKey, bridgeKey);
}
/// <summary>
/// Used for debugging to trigger an action based on a join number and type
/// </summary>
/// <param name="join">The join number to execute the action for</param>
/// <param name="type">The type of join (digital, analog, serial)</param>
/// <param name="state">The state to pass to the action</param>
/// <param name="join"></param>
/// <param name="type"></param>
/// <param name="state"></param>
/// <summary>
/// ExecuteJoinAction method
/// </summary>
public void ExecuteJoinAction(uint join, string type, object state)
{
try
@@ -262,87 +263,78 @@ namespace PepperDash.Essentials.Core.Bridges
{
case "digital":
{
if (Eisc.BooleanOutput[join].UserObject is Action<bool> userObject)
var uo = Eisc.BooleanOutput[join].UserObject as Action<bool>;
if (uo != null)
{
this.LogVerbose("Executing Boolean Action");
userObject(Convert.ToBoolean(state));
Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString());
uo(Convert.ToBoolean(state));
}
else
this.LogVerbose("User Object is null. Nothing to Execute");
Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute");
break;
}
case "analog":
{
if (Eisc.UShortOutput[join].UserObject is Action<ushort> userObject)
var uo = Eisc.BooleanOutput[join].UserObject as Action<ushort>;
if (uo != null)
{
this.LogVerbose("Executing Analog Action");
userObject(Convert.ToUInt16(state));
Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString());
uo(Convert.ToUInt16(state));
}
else
this.LogVerbose("User Object is null. Nothing to Execute");
break;
Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute"); break;
}
case "serial":
{
if (Eisc.StringOutput[join].UserObject is Action<string> userObject)
var uo = Eisc.BooleanOutput[join].UserObject as Action<string>;
if (uo != null)
{
this.LogVerbose("Executing Serial Action");
userObject(Convert.ToString(state));
Debug.LogMessage(LogEventLevel.Verbose, this, "Executing Action: {0}", uo.ToString());
uo(Convert.ToString(state));
}
else
this.LogVerbose("User Object is null. Nothing to Execute");
Debug.LogMessage(LogEventLevel.Verbose, this, "User Action is null. Nothing to Execute");
break;
}
default:
{
this.LogVerbose("Unknown join type. Use digital/serial/analog");
Debug.LogMessage(LogEventLevel.Verbose, "Unknown join type. Use digital/serial/analog");
break;
}
}
}
catch (Exception e)
{
this.LogError("ExecuteJoinAction error: {message}", e.Message);
this.LogDebug(e, "Stack Trace: ");
Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e);
}
}
/// <summary>
/// Handle incoming sig changes
/// Handles incoming sig changes
/// </summary>
/// <param name="currentDevice">BasicTriList device that triggered the event</param>
/// <param name="args">Event arguments containing the signal information</param>
/// <param name="currentDevice"></param>
/// <param name="args"></param>
protected void Eisc_SigChange(object currentDevice, SigEventArgs args)
{
try
{
this.LogVerbose("EiscApiAdvanced change: {type} {number}={value}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue);
var userObject = args.Sig.UserObject;
Debug.LogMessage(LogEventLevel.Verbose, this, "EiscApiAdvanced change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue);
var uo = args.Sig.UserObject;
if (userObject == null) return;
if (uo == null) return;
if (userObject is Action<bool>)
{
this.LogDebug("Executing Boolean Action");
(userObject as Action<bool>)(args.Sig.BoolValue);
}
else if (userObject is Action<ushort>)
{
this.LogDebug("Executing Analog Action");
(userObject as Action<ushort>)(args.Sig.UShortValue);
}
else if (userObject is Action<string>)
{
this.LogDebug("Executing Serial Action");
(userObject as Action<string>)(args.Sig.StringValue);
}
Debug.LogMessage(LogEventLevel.Debug, this, "Executing Action: {0}", uo.ToString());
if (uo is Action<bool>)
(uo as Action<bool>)(args.Sig.BoolValue);
else if (uo is Action<ushort>)
(uo as Action<ushort>)(args.Sig.UShortValue);
else if (uo is Action<string>)
(uo as Action<string>)(args.Sig.StringValue);
}
catch (Exception e)
{
this.LogError("Eisc_SigChange handler error: {message}", e.Message);
this.LogDebug(e, "Stack Trace: ");
Debug.LogMessage(LogEventLevel.Verbose, this, "Error in Eisc_SigChange handler: {0}", e);
}
}
@@ -431,33 +423,22 @@ namespace PepperDash.Essentials.Core.Bridges
}
/// <summary>
/// Factory class for EiscApiAdvanced devices
/// Represents a EiscApiAdvancedFactory
/// </summary>
/// <remarks>
/// Supported types:
/// eiscapiadv - Create a standard EISC client over TCP/IP
/// eiscapiadvanced - Create a standard EISC client over TCP/IP
/// eiscapiadvancedserver - Create an EISC server
/// eiscapiadvancedclient - Create an EISC client
/// vceiscapiadv - Create a VC-4 EISC client
/// vceiscapiadvanced - Create a VC-4 EISC client
/// eiscapiadvudp - Create a standard EISC client over UDP
/// eiscapiadvancedudp - Create a standard EISC client over UDP
/// </remarks>
public class EiscApiAdvancedFactory : EssentialsDeviceFactory<EiscApiAdvanced>
{
/// <summary>
/// Constructor
/// </summary>
public EiscApiAdvancedFactory()
{
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced", "eiscapiadvudp", "eiscapiadvancedudp" };
TypeNames = new List<string> { "eiscapiadv", "eiscapiadvanced", "eiscapiadvancedserver", "eiscapiadvancedclient", "vceiscapiadv", "vceiscapiadvanced" };
}
/// <summary>
/// BuildDevice method
/// </summary>
/// <inheritdoc />
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.LogDebug("Attempting to create new EiscApiAdvanced Device");
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EiscApiAdvanced Device");
var controlProperties = CommFactory.GetControlPropertiesConfig(dc);
@@ -465,13 +446,6 @@ namespace PepperDash.Essentials.Core.Bridges
switch (dc.Type.ToLower())
{
case "eiscapiadvudp":
case "eiscapiadvancedudp":
{
eisc = new EthernetIntersystemCommunications(controlProperties.IpIdInt,
controlProperties.TcpSshProperties.Address, Global.ControlSystem);
break;
}
case "eiscapiadv":
case "eiscapiadvanced":
{
@@ -494,7 +468,7 @@ namespace PepperDash.Essentials.Core.Bridges
{
if (string.IsNullOrEmpty(controlProperties.RoomId))
{
Debug.LogInformation("Unable to build VC-4 EISC Client for device {deviceKey}. Room ID is missing or empty", dc.Key);
Debug.LogMessage(LogEventLevel.Information, "Unable to build VC-4 EISC Client for device {0}. Room ID is missing or empty", dc.Key);
eisc = null;
break;
}

View File

@@ -104,6 +104,12 @@ namespace PepperDash.Essentials.Core
comm = secureTcp;
break;
}
case eControlMethod.TcpServer:
{
var tcpServer = new GenericTcpIpServer(deviceConfig.Key + "-tcpServer", c.Address, c.Port, c.BufferSize);
comm = tcpServer;
break;
}
default:
break;
}

View File

@@ -77,6 +77,9 @@ namespace PepperDash.Essentials.Core
/// A name that will override the source's name on the UI
/// </summary>
[JsonProperty("name")]
/// <summary>
/// Gets or sets the Name
/// </summary>
public string Name { get; set; }
/// <summary>

View File

@@ -14,14 +14,13 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
namespace PepperDash.Essentials.Core.Fusion
{
/// <summary>
/// Represents a EssentialsHuddleSpaceFusionSystemControllerBase
/// </summary>
public class IEssentialsRoomFusionController : EssentialsDevice, IOccupancyStatusProvider, IFusionHelpRequest, IHasFeedback
public class IEssentialsRoomFusionController : EssentialsDevice, IOccupancyStatusProvider, IFusionHelpRequest
{
private IEssentialsRoomFusionControllerPropertiesConfig _config;
@@ -88,17 +87,15 @@ namespace PepperDash.Essentials.Core.Fusion
/// <inheritdoc />
public StringFeedback HelpRequestStatusFeedback { get; private set; }
private Timer _helpRequestTimeoutTimer;
/// <summary>
/// Gets the DefaultHelpRequestTimeoutMs
/// </summary>
public int HelpRequestTimeoutMs => _config.HelpRequestTimeoutMs;
#region System Info Sigs
/// <summary>
/// Gets whether to use a timer for help requests
/// </summary>
public bool UseHelpRequestTimer => _config.UseTimeoutForHelpRequests;
//StringSigData SystemName;
//StringSigData Model;
//StringSigData SerialNumber;
//StringSigData Uptime;
#endregion
#region Processor Info Sigs
@@ -243,19 +240,6 @@ namespace PepperDash.Essentials.Core.Fusion
this.LogDebug("Occupancy setup complete");
HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.OutputSig.StringValue);
HelpRequestSentFeedback = new BoolFeedback("HelpRequestSent", () => _helpRequestSent);
HelpRequestStatusFeedback = new StringFeedback("HelpRequestStatus", () => _helpRequestStatus.ToString());
Feedbacks.Add(HelpRequestResponseFeedback);
Feedbacks.Add(HelpRequestSentFeedback);
Feedbacks.Add(HelpRequestStatusFeedback);
if (RoomOccupancyRemoteStringFeedback != null)
Feedbacks.Add(RoomOccupancyRemoteStringFeedback);
if (RoomIsOccupiedFeedback != null)
Feedbacks.Add(RoomIsOccupiedFeedback);
}
catch (Exception e)
{
@@ -319,6 +303,10 @@ namespace PepperDash.Essentials.Core.Fusion
FusionRVI.GenerateFileForAllFusionDevices();
HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.OutputSig.StringValue);
HelpRequestSentFeedback = new BoolFeedback("HelpRequestSent", () => _helpRequestSent);
HelpRequestStatusFeedback = new StringFeedback("HelpRequestStatus", () => _helpRequestStatus.ToString());
}
/// <summary>
@@ -351,11 +339,6 @@ namespace PepperDash.Essentials.Core.Fusion
#endregion
/// <inheritdoc />
public FeedbackCollection<Feedback> Feedbacks { get; private set; } = new FeedbackCollection<Feedback>();
/// <summary>
/// ScheduleChange event
/// </summary>
@@ -1789,7 +1772,7 @@ namespace PepperDash.Essentials.Core.Fusion
{
if (args.EventId == FusionEventIds.HelpMessageReceivedEventId)
{
this.LogInformation("Help message received from Fusion for room '{0}'",
this.LogInformation( "Help message received from Fusion for room '{0}'",
Room.Name);
this.LogDebug("Help message content: {0}", FusionRoom.Help.OutputSig.StringValue);
@@ -1808,7 +1791,7 @@ namespace PepperDash.Essentials.Core.Fusion
break;
case "Please call the helpdesk.":
// this.LogInformation("Please call the helpdesk.");
_helpRequestStatus = eFusionHelpResponse.CallHelpDesk;
// _helpRequestStatus = eFusionHelpResponse.CallHelpDesk;
break;
case "Please wait, I will reschedule your meeting to a different room.":
// this.LogInformation("Please wait, I will reschedule your meeting to a different room.",
@@ -1835,21 +1818,13 @@ namespace PepperDash.Essentials.Core.Fusion
_helpRequestStatus = eFusionHelpResponse.None;
}
if (_helpRequestStatus == eFusionHelpResponse.None)
if(_helpRequestStatus == eFusionHelpResponse.None)
{
_helpRequestSent = false;
HelpRequestSentFeedback.FireUpdate();
}
HelpRequestStatusFeedback.FireUpdate();
if (_helpRequestTimeoutTimer != null)
{
_helpRequestTimeoutTimer.Stop();
_helpRequestTimeoutTimer.Elapsed -= OnTimedEvent;
_helpRequestTimeoutTimer.Dispose();
_helpRequestTimeoutTimer = null;
}
}
@@ -1920,34 +1895,10 @@ namespace PepperDash.Essentials.Core.Fusion
_helpRequestSent = true;
HelpRequestSentFeedback.FireUpdate();
if (UseHelpRequestTimer)
{
if (_helpRequestTimeoutTimer == null)
{
_helpRequestTimeoutTimer = new Timer(HelpRequestTimeoutMs);
_helpRequestTimeoutTimer.AutoReset = false;
_helpRequestTimeoutTimer.Enabled = true;
_helpRequestTimeoutTimer.Elapsed += OnTimedEvent;
}
_helpRequestTimeoutTimer.Interval = HelpRequestTimeoutMs;
_helpRequestTimeoutTimer.Start();
this.LogDebug("Help request timeout timer started for room '{0}' with timeout of {1} ms.",
Room.Name, HelpRequestTimeoutMs);
}
_helpRequestStatus = eFusionHelpResponse.HelpRequested;
HelpRequestStatusFeedback.FireUpdate();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
this.LogInformation("Help request timeout reached for room '{0}'. Cancelling help request.", Room.Name);
CancelHelpRequest();
}
/// <inheritdoc />
public void CancelHelpRequest()
{
@@ -1958,16 +1909,7 @@ namespace PepperDash.Essentials.Core.Fusion
HelpRequestSentFeedback.FireUpdate();
_helpRequestStatus = eFusionHelpResponse.None;
HelpRequestStatusFeedback.FireUpdate();
Debug.LogMessage(LogEventLevel.Information, this, "Help request cancelled for room '{0}'", Room.Name);
}
if (_helpRequestTimeoutTimer != null)
{
_helpRequestTimeoutTimer.Stop();
_helpRequestTimeoutTimer.Elapsed -= OnTimedEvent;
_helpRequestTimeoutTimer.Dispose();
_helpRequestTimeoutTimer = null;
this.LogDebug("Help request timeout timer stopped for room '{0}'.", Room.Name);
Debug.LogMessage(LogEventLevel.Information, this, "Help request cancelled in Fusion for room '{0}'", Room.Name);
}
}

View File

@@ -56,16 +56,4 @@ public class IEssentialsRoomFusionControllerPropertiesConfig
/// </summary>
[JsonProperty("use24HourTimeFormat")]
public bool Use24HourTimeFormat { get; set; } = false;
/// <summary>
/// Gets or sets whether to use a timeout for help requests
/// </summary>
[JsonProperty("useTimeoutForHelpRequests")]
public bool UseTimeoutForHelpRequests { get; set; } = false;
/// <summary>
/// Gets or sets the timeout duration for help requests in milliseconds
/// </summary>
[JsonProperty("helpRequestTimeoutMs")]
public int HelpRequestTimeoutMs { get; set; } = 30000;
}

View File

@@ -105,21 +105,12 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsRoomPropertiesConfig
{
/// <summary>
/// Gets or sets the Addresses
/// </summary>
[JsonProperty("addresses")]
public EssentialsRoomAddressPropertiesConfig Addresses { get; set; }
/// <summary>
/// Gets or sets the Description
/// </summary>
[JsonProperty("description")]
public string Description { get; set; }
/// <summary>
/// Gets or sets the Emergency
/// </summary>
[JsonProperty("emergency")]
public EssentialsRoomEmergencyConfig Emergency { get; set; }
@@ -235,11 +226,11 @@ namespace PepperDash.Essentials.Room.Config
/// Indicates if this room represents a combination of other rooms
/// </summary>
[JsonProperty("isRoomCombinationScenario")]
/// <summary>
/// Gets or sets the IsRoomCombinationScenario
/// </summary>
public bool IsRoomCombinationScenario { get; set; }
/// <summary>
/// Constructor
/// </summary>
public EssentialsRoomPropertiesConfig()
{
LogoLight = new EssentialsLogoPropertiesConfig();
@@ -252,10 +243,10 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsRoomUiBehaviorConfig
{
[JsonProperty("disableActivityButtonsWhileWarmingCooling")]
/// <summary>
/// Gets or sets the DisableActivityButtonsWhileWarmingCooling
/// </summary>
[JsonProperty("disableActivityButtonsWhileWarmingCooling")]
public bool DisableActivityButtonsWhileWarmingCooling { get; set; }
}
@@ -264,86 +255,74 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig
{
[JsonProperty("defaultAudioKey")]
/// <summary>
/// Gets or sets the DefaultAudioKey
/// </summary>
[JsonProperty("defaultAudioKey")]
public string DefaultAudioKey { get; set; }
/// <summary>
/// Gets or sets the DefaultOnDspPresetKey
/// </summary>
[JsonProperty("defaultOnDspPresetKey")]
public string DefaultOnDspPresetKey { get; set; }
/// <summary>
/// Gets or sets the DefaultOffDspPresetKey
/// </summary>
[JsonProperty("defaultOffDspPresetKey")]
public string DefaultOffDspPresetKey { get; set; }
[JsonProperty("sourceListKey")]
/// <summary>
/// Gets or sets the SourceListKey
/// </summary>
/// </summary>
[JsonProperty("sourceListKey")]
public string SourceListKey { get; set; }
[JsonProperty("destinationListKey")]
/// <summary>
/// Gets or sets the DestinationListKey
/// </summary>
[JsonProperty("destinationListKey")]
public string DestinationListKey { get; set; }
[JsonProperty("audioControlPointListKey")]
/// <summary>
/// Gets or sets the AudioControlPointListKey
/// </summary>
[JsonProperty("audioControlPointListKey")]
public string AudioControlPointListKey { get; set; }
[JsonProperty("cameraListKey")]
/// <summary>
/// Gets or sets the CameraListKey
/// </summary>
[JsonProperty("cameraListKey")]
public string CameraListKey { get; set; }
[JsonProperty("defaultSourceItem")]
/// <summary>
/// Gets or sets the DefaultSourceItem
/// </summary>
[JsonProperty("defaultSourceItem")]
public string DefaultSourceItem { get; set; }
/// <summary>
/// Indicates if the room supports advanced sharing
/// </summary>
[JsonProperty("supportsAdvancedSharing")]
/// <summary>
/// Gets or sets the SupportsAdvancedSharing
/// </summary>
public bool SupportsAdvancedSharing { get; set; }
/// <summary>
/// Indicates if non-tech users can change the share mode
/// </summary>
[JsonProperty("userCanChangeShareMode")]
/// <summary>
/// Gets or sets the UserCanChangeShareMode
/// </summary>
public bool UserCanChangeShareMode { get; set; }
[JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)]
/// <summary>
/// Gets or sets the MatrixRoutingKey
/// </summary>
[JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)]
public string MatrixRoutingKey { get; set; }
}
/// <summary>
/// Represents a EssentialsConferenceRoomPropertiesConfig
/// </summary>
public class EssentialsConferenceRoomPropertiesConfig : EssentialsAvRoomPropertiesConfig
{
[JsonProperty("videoCodecKey")]
/// <summary>
/// Gets or sets the VideoCodecKey
/// </summary>
[JsonProperty("videoCodecKey")]
public string VideoCodecKey { get; set; }
[JsonProperty("audioCodecKey")]
/// <summary>
/// Gets or sets the AudioCodecKey
/// </summary>
[JsonProperty("audioCodecKey")]
public string AudioCodecKey { get; set; }
}
@@ -358,15 +337,12 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public bool Enabled { get; set; }
[JsonProperty("deviceKeys")]
/// <summary>
/// Gets or sets the DeviceKeys
/// </summary>
[JsonProperty("deviceKeys")]
public List<string> DeviceKeys { get; set; }
/// <summary>
/// Constructor
/// </summary>
public EssentialsEnvironmentPropertiesConfig()
{
DeviceKeys = new List<string>();
@@ -379,9 +355,6 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsRoomFusionConfig
{
/// <summary>
/// Gets the the IpId as a UInt16
/// </summary>
public uint IpIdInt
{
get
@@ -398,16 +371,16 @@ namespace PepperDash.Essentials.Room.Config
}
}
[JsonProperty("ipId")]
/// <summary>
/// Gets or sets the IpId
/// </summary>
[JsonProperty("ipId")]
public string IpId { get; set; }
[JsonProperty("joinMapKey")]
/// <summary>
/// Gets or sets the JoinMapKey
/// </summary>
[JsonProperty("joinMapKey")]
public string JoinMapKey { get; set; }
}
@@ -417,16 +390,16 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsRoomMicrophonePrivacyConfig
{
[JsonProperty("deviceKey")]
/// <summary>
/// Gets or sets the DeviceKey
/// </summary>
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("behaviour")]
/// <summary>
/// Gets or sets the Behaviour
/// </summary>
[JsonProperty("behaviour")]
public string Behaviour { get; set; }
}
@@ -435,15 +408,12 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsHelpPropertiesConfig
{
[JsonProperty("message")]
/// <summary>
/// Gets or sets the Message
/// </summary>
[JsonProperty("message")]
public string Message { get; set; }
/// <summary>
/// Gets or sets the ShowCallButton
/// </summary>
[JsonProperty("showCallButton")]
public bool ShowCallButton { get; set; }
@@ -451,11 +421,11 @@ namespace PepperDash.Essentials.Room.Config
/// Defaults to "Call Help Desk"
/// </summary>
[JsonProperty("callButtonText")]
/// <summary>
/// Gets or sets the CallButtonText
/// </summary>
public string CallButtonText { get; set; }
/// <summary>
/// Constructor
/// </summary>
public EssentialsHelpPropertiesConfig()
{
CallButtonText = "Call Help Desk";
@@ -467,28 +437,22 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsOneButtonMeetingPropertiesConfig
{
[JsonProperty("enable")]
/// <summary>
/// Gets or sets the Enable
/// </summary>
[JsonProperty("enable")]
public bool Enable { get; set; }
}
/// <summary>
/// Represents a EssentialsRoomAddressPropertiesConfig
/// </summary>
public class EssentialsRoomAddressPropertiesConfig
{
/// <summary>
/// Gets or sets the PhoneNumber
/// </summary>
[JsonProperty("phoneNumber")]
public string PhoneNumber { get; set; }
[JsonProperty("sipAddress")]
/// <summary>
/// Gets or sets the SipAddress
/// </summary>
[JsonProperty("sipAddress")]
public string SipAddress { get; set; }
}
@@ -498,18 +462,14 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsLogoPropertiesConfig
{
[JsonProperty("type")]
/// <summary>
/// Gets or sets the Type
/// </summary>
[JsonProperty("type")]
public string Type { get; set; }
/// <summary>
/// Gets or sets the Url
/// </summary>
[JsonProperty("url")]
public string Url { get; set; }
/// <summary>
/// GetLogoUrlLight method
/// </summary>
@@ -542,28 +502,22 @@ namespace PepperDash.Essentials.Room.Config
/// </summary>
public class EssentialsRoomOccSensorConfig
{
[JsonProperty("deviceKey")]
/// <summary>
/// Gets or sets the DeviceKey
/// </summary>
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
/// <summary>
/// Gets or sets the TimeoutMinutes
/// </summary>
[JsonProperty("timeoutMinutes")]
public int TimeoutMinutes { get; set; }
}
/// <summary>
/// Represents a EssentialsRoomTechConfig
/// </summary>
public class EssentialsRoomTechConfig
{
[JsonProperty("password")]
/// <summary>
/// Gets or sets the Password
/// </summary>
[JsonProperty("password")]
public string Password { get; set; }
}
}

View File

@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Crestron.SimplSharpPro.Keypads;
using Crestron.SimplSharpPro.Keypads;
using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Debug = PepperDash.Core.Debug;
@@ -115,7 +115,7 @@ namespace PepperDash.Essentials.Core
public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort)
{
// if it's a single signal type, find the route
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) &&
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo) &&
!(signalType.HasFlag(eRoutingSignalType.Video) && signalType.HasFlag(eRoutingSignalType.SecondaryAudio)))
{
var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, signalType);
@@ -134,15 +134,14 @@ namespace PepperDash.Essentials.Core
}
// otherwise, audioVideo needs to be handled as two steps.
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {destinationKey} to {sourceKey} of type {type}", destination, source.Key, signalType);
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key);
RouteDescriptor audioRouteDescriptor;
if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio))
{
audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio);
}
else
} else
{
audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio);
}
@@ -200,13 +199,13 @@ namespace PepperDash.Essentials.Core
Source = source,
SourcePort = sourcePort,
SignalType = signalType
};
};
var coolingDevice = destination as IWarmingCooling;
//We already have a route request for this device, and it's a cooling device and is cooling
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRouteRequest) && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{
{
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
@@ -220,7 +219,7 @@ namespace PepperDash.Essentials.Core
//New Request
if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
{
{
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
RouteRequests.Add(destination.Key, routeRequest);
@@ -240,9 +239,9 @@ namespace PepperDash.Essentials.Core
Debug.LogMessage(LogEventLevel.Information, "Device: {destination} is NOT cooling down. Removing stored route request and routing to source key: {sourceKey}", null, destination.Key, routeRequest.Source.Key);
}
routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination, destinationPort?.Key ?? string.Empty, false));
routeRequestQueue.Enqueue(new ReleaseRouteQueueItem(ReleaseRouteInternal, destination,destinationPort?.Key ?? string.Empty, false));
routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest));
routeRequestQueue.Enqueue(new RouteRequestQueueItem(RunRouteRequest, routeRequest));
}
/// <summary>
@@ -273,8 +272,7 @@ namespace PepperDash.Essentials.Core
audioOrSingleRoute.ExecuteRoutes();
videoRoute?.ExecuteRoutes();
}
catch (Exception ex)
} catch(Exception ex)
{
Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request);
}
@@ -307,10 +305,9 @@ namespace PepperDash.Essentials.Core
Debug.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key);
current.ReleaseRoutes(clearRoute);
}
}
catch (Exception ex)
} catch (Exception ex)
{
Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'", null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'",null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey);
}
}

View File

@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Generic
@@ -12,17 +9,8 @@ namespace PepperDash.Essentials.Devices.Common.Generic
/// <summary>
/// Represents a GenericSink
/// </summary>
public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputPort, ICurrentSources
public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputPort
{
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, SourceListItem> CurrentSources { get; private set; }
/// <inheritdoc/>
public Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; private set; }
/// <inheritdoc />
public event EventHandler CurrentSourcesChanged;
/// <summary>
/// Initializes a new instance of the GenericSink class
/// </summary>
@@ -35,49 +23,6 @@ namespace PepperDash.Essentials.Devices.Common.Generic
var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo | eRoutingSignalType.SecondaryAudio, eRoutingPortConnectionType.Hdmi, null, this);
InputPorts.Add(inputPort);
CurrentSources = new Dictionary<eRoutingSignalType, SourceListItem>
{
{ eRoutingSignalType.Audio, null },
{ eRoutingSignalType.Video, null },
};
CurrentSourceKeys = new Dictionary<eRoutingSignalType, string>
{
{ eRoutingSignalType.Audio, string.Empty },
{ eRoutingSignalType.Video, string.Empty },
};
}
/// <inheritdoc />
public 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)
{
CurrentSources[signalType] = sourceListItem;
CurrentSourceKeys[signalType] = sourceListKey;
}
/// <summary>
@@ -128,7 +73,7 @@ namespace PepperDash.Essentials.Devices.Common.Generic
/// <inheritdoc />
public void ExecuteSwitch(object inputSelector)
{
this.LogDebug("GenericSink Executing Switch to: {inputSelector}", inputSelector);
throw new System.NotImplementedException();
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
@@ -40,14 +39,10 @@ namespace PepperDash.Essentials.AppServer.Messengers
sourceDevice.CurrentSourcesChanged += (sender, e) =>
{
// need to copy the dictionaries to avoid enumeration issues
var currentSourceKeys = sourceDevice.CurrentSourceKeys.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
var currentSources = sourceDevice.CurrentSources.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
PostStatusMessage(JToken.FromObject(new
{
currentSourceKeys,
currentSources,
currentSourceKeys = sourceDevice.CurrentSourceKeys,
currentSources = sourceDevice.CurrentSources
}));
};
}

View File

@@ -130,33 +130,34 @@ namespace PepperDash.Essentials.AppServer.Messengers
feedback.MuteFeedback.OutputChange += (sender, args) =>
{
var message = new VolumeStateMessage
{
Volume = new Volume
{
Muted = args.BoolValue
}
};
PostStatusMessage(JToken.FromObject(message));
PostStatusMessage(JToken.FromObject(
new
{
volume = new
{
muted = args.BoolValue
}
})
);
};
feedback.VolumeLevelFeedback.OutputChange += (sender, args) =>
{
var message = new VolumeStateMessage
var rawValue = "";
if (feedback is IBasicVolumeWithFeedbackAdvanced volumeAdvanced)
{
Volume = new Volume
rawValue = volumeAdvanced.RawVolumeLevel.ToString();
}
var message = new
{
volume = new
{
Level = args.IntValue,
level = args.IntValue,
rawValue
}
};
if (device is IBasicVolumeWithFeedbackAdvanced volumeAdvanced)
{
message.Volume.RawValue = volumeAdvanced.RawVolumeLevel.ToString();
message.Volume.Units = volumeAdvanced.Units;
}
PostStatusMessage(JToken.FromObject(message));
};
}