diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 1e7c0909..ce6c0eed 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -23,23 +23,32 @@ $(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz - - + + + + + - + - - + + + + + - + - - + + + + + - + diff --git a/src/PepperDash.Core/Comm/GenericUdpServer.cs b/src/PepperDash.Core/Comm/GenericUdpServer.cs index 61bebf8d..52ac627a 100644 --- a/src/PepperDash.Core/Comm/GenericUdpServer.cs +++ b/src/PepperDash.Core/Comm/GenericUdpServer.cs @@ -131,14 +131,14 @@ namespace PepperDash.Core /// /// /// - /// - public GenericUdpServer(string key, string address, int port, int buffefSize) + /// + public GenericUdpServer(string key, string address, int port, int bufferSize) : base(key) { StreamDebugging = new CommunicationStreamDebugging(key); Hostname = address; Port = port; - BufferSize = buffefSize; + BufferSize = bufferSize; CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); @@ -194,7 +194,21 @@ namespace PepperDash.Core { if (Server == null) { - Server = new UDPServer(); + try + { + var address = IPAddress.Parse(Hostname); + + Server = new UDPServer(address, Port, BufferSize); + + } + catch (Exception ex) + { + this.LogError("Error parsing IP Address '{ipAddress}': message: {message}", Hostname, ex.Message); + this.LogInformation("Creating UDPServer with default buffersize"); + + Server = new UDPServer(); + } + } if (string.IsNullOrEmpty(Hostname)) diff --git a/src/PepperDash.Core/Logging/Debug.cs b/src/PepperDash.Core/Logging/Debug.cs index 37b0f14a..62a95f2c 100644 --- a/src/PepperDash.Core/Logging/Debug.cs +++ b/src/PepperDash.Core/Logging/Debug.cs @@ -40,20 +40,20 @@ namespace PepperDash.Core private static ILogger _logger; - private static readonly LoggingLevelSwitch _consoleLoggingLevelSwitch; + private static readonly LoggingLevelSwitch _consoleLogLevelSwitch; - private static readonly LoggingLevelSwitch _websocketLoggingLevelSwitch; + private static readonly LoggingLevelSwitch _websocketLogLevelSwitch; private static readonly LoggingLevelSwitch _errorLogLevelSwitch; - private static readonly LoggingLevelSwitch _fileLevelSwitch; + private static readonly LoggingLevelSwitch _fileLogLevelSwitch; /// /// Gets the minimum log level for the websocket sink. /// public static LogEventLevel WebsocketMinimumLogLevel { - get { return _websocketLoggingLevelSwitch.MinimumLevel; } + get { return _websocketLogLevelSwitch.MinimumLevel; } } private static readonly DebugWebsocketSink _websocketSink; @@ -138,13 +138,13 @@ namespace PepperDash.Core var defaultFileLogLevel = GetStoredLogEventLevel(FileLevelStoreKey); - _consoleLoggingLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultConsoleLevel); + _consoleLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultConsoleLevel); - _websocketLoggingLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultWebsocketLevel); + _websocketLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultWebsocketLevel); _errorLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultErrorLogLevel); - _fileLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultFileLogLevel); + _fileLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultFileLogLevel); _websocketSink = new DebugWebsocketSink(new JsonFormatter(renderMessage: true)); @@ -162,14 +162,14 @@ namespace PepperDash.Core .MinimumLevel.Verbose() .Enrich.FromLogContext() .Enrich.With(new CrestronEnricher()) - .WriteTo.Sink(new DebugConsoleSink(new ExpressionTemplate("[{@t:yyyy-MM-dd HH:mm:ss.fff}][{@l:u4}][{App}]{#if Key is not null}[{Key}]{#end} {@m}{#if @x is not null}\r\n{@x}{#end}")), levelSwitch: _consoleLoggingLevelSwitch) - .WriteTo.Sink(_websocketSink, levelSwitch: _websocketLoggingLevelSwitch) + .WriteTo.Sink(new DebugConsoleSink(new ExpressionTemplate("[{@t:yyyy-MM-dd HH:mm:ss.fff}][{@l:u4}][{App}]{#if Key is not null}[{Key}]{#end} {@m}{#if @x is not null}\r\n{@x}{#end}")), levelSwitch: _consoleLogLevelSwitch) + .WriteTo.Sink(_websocketSink, levelSwitch: _websocketLogLevelSwitch) .WriteTo.Sink(new DebugErrorLogSink(new ExpressionTemplate(errorLogTemplate)), levelSwitch: _errorLogLevelSwitch) .WriteTo.File(new RenderedCompactJsonFormatter(), logFilePath, rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Debug, retainedFileCountLimit: CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? 30 : 60, - levelSwitch: _fileLevelSwitch + levelSwitch: _fileLogLevelSwitch ); try @@ -237,10 +237,13 @@ namespace PepperDash.Core if (DoNotLoadConfigOnNextBoot) CrestronConsole.PrintLine(string.Format("Program {0} will not load config after next boot. Use console command go:{0} to load the config manually", InitialParametersClass.ApplicationNumber)); - _consoleLoggingLevelSwitch.MinimumLevelChanged += (sender, args) => + _errorLogLevelSwitch.MinimumLevelChanged += (sender, args) => { - LogMessage(LogEventLevel.Information, "Console debug level set to {minimumLevel}", _consoleLoggingLevelSwitch.MinimumLevel); + LogMessage(LogEventLevel.Information, "Error log debug level set to {minimumLevel}", _errorLogLevelSwitch.MinimumLevel); }; + + // Set initial error log level based on platform && stored level. If appliance, use stored level, otherwise default to verbose + SetErrorLogMinimumDebugLevel(CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? _errorLogLevelSwitch.MinimumLevel : LogEventLevel.Verbose); } /// @@ -273,9 +276,9 @@ namespace PepperDash.Core { 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); + CrestronDataStoreStatic.SetLocalIntValue(levelStoreKey, levelStoreKey == ErrorLogLevelStoreKey ? (int)LogEventLevel.Warning : (int)LogEventLevel.Information); - return LogEventLevel.Information; + return levelStoreKey == ErrorLogLevelStoreKey ? LogEventLevel.Warning : LogEventLevel.Information; } if (logLevel < 0 || logLevel > 5) @@ -284,6 +287,8 @@ namespace PepperDash.Core return LogEventLevel.Information; } + CrestronConsole.PrintLine($"Stored log level for {levelStoreKey} is {logLevel}"); + return (LogEventLevel)logLevel; } catch (Exception ex) @@ -349,7 +354,11 @@ 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" + + "Used to set the minimum level of debug messages:\r\n" + + "Usage: appdebug:P [sink] [level]\r\n" + + " sink: console (default), errorlog, file, all\r\n" + + " all: sets all sinks to the specified level\r\n" + + " level: 0-5 or LogEventLevel name\r\n" + $"{_logLevels[0]} = 0\r\n" + $"{_logLevels[1]} = 1\r\n" + $"{_logLevels[2]} = 2\r\n" + @@ -361,32 +370,88 @@ namespace PepperDash.Core if (string.IsNullOrEmpty(levelString.Trim())) { - CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", _consoleLoggingLevelSwitch.MinimumLevel); + CrestronConsole.ConsoleCommandResponse("Console log level = {0}\r\n", _consoleLogLevelSwitch.MinimumLevel); + CrestronConsole.ConsoleCommandResponse("File log level = {0}\r\n", _fileLogLevelSwitch.MinimumLevel); + CrestronConsole.ConsoleCommandResponse("Error log level = {0}\r\n", _errorLogLevelSwitch.MinimumLevel); return; } - if (int.TryParse(levelString, out var levelInt)) + // Parse tokens: first token is sink (defaults to console), second token is level + var tokens = levelString.Trim().Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + + string sinkName; + string levelToken; + + if (tokens.Length == 1) + { + // Single token - assume it's a level for console sink + sinkName = "console"; + levelToken = tokens[0]; + } + else if (tokens.Length == 2) + { + // Two tokens - first is sink, second is level + sinkName = tokens[0].ToLowerInvariant(); + levelToken = tokens[1]; + } + else + { + CrestronConsole.ConsoleCommandResponse("Usage: appdebug:P [sink] [level]"); + return; + } + + // Parse the level using the same logic as before + LogEventLevel level; + + if (int.TryParse(levelToken, out var levelInt)) { if (levelInt < 0 || levelInt > 5) { - CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelString} to valid log level. If using a number, value must be between 0-5"); + CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelToken} to valid log level. If using a number, value must be between 0-5"); return; } - SetDebugLevel((uint)levelInt); - return; - } - if (Enum.TryParse(levelString, true, out var levelEnum)) + if (!_logLevels.TryGetValue((uint)levelInt, out level)) + { + level = LogEventLevel.Information; + CrestronConsole.ConsoleCommandResponse($"{levelInt} not valid. Setting level to {level}"); + } + } + else if (Enum.TryParse(levelToken, true, out level)) { - SetDebugLevel(levelEnum); + // Successfully parsed as LogEventLevel enum + } + else + { + CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelToken} to valid log level"); return; } - CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelString} to valid log level"); + // Set the level for the specified sink + switch (sinkName) + { + case "console": + SetDebugLevel(level); + break; + case "errorlog": + SetErrorLogMinimumDebugLevel(level); + break; + case "file": + SetFileMinimumDebugLevel(level); + break; + case "all": + SetDebugLevel(level); + SetErrorLogMinimumDebugLevel(level); + SetFileMinimumDebugLevel(level); + break; + default: + CrestronConsole.ConsoleCommandResponse($"Error: Unknown sink '{sinkName}'. Valid sinks: console, errorlog, file"); + break; + } } catch { - CrestronConsole.ConsoleCommandResponse("Usage: appdebug:P [0-5]"); + CrestronConsole.ConsoleCommandResponse("Usage: appdebug:P [sink] [level]"); } } @@ -416,10 +481,10 @@ namespace PepperDash.Core /// public static void SetDebugLevel(LogEventLevel level) { - _consoleLoggingLevelSwitch.MinimumLevel = level; + _consoleLogLevelSwitch.MinimumLevel = level; - CrestronConsole.ConsoleCommandResponse("[Application {0}], Debug level set to {1}\r\n", - InitialParametersClass.ApplicationNumber, _consoleLoggingLevelSwitch.MinimumLevel); + CrestronConsole.ConsoleCommandResponse("[Application {0}] Debug level set to {1}\r\n", + InitialParametersClass.ApplicationNumber, _consoleLogLevelSwitch.MinimumLevel); CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int)level}"); @@ -436,14 +501,14 @@ namespace PepperDash.Core /// public static void SetWebSocketMinimumDebugLevel(LogEventLevel level) { - _websocketLoggingLevelSwitch.MinimumLevel = level; + _websocketLogLevelSwitch.MinimumLevel = level; var err = CrestronDataStoreStatic.SetLocalUintValue(WebSocketLevelStoreKey, (uint)level); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) LogMessage(LogEventLevel.Information, "Error saving websocket debug level setting: {erro}", err); - LogMessage(LogEventLevel.Information, "Websocket debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel); + LogMessage(LogEventLevel.Information, "Websocket debug level set to {0}", _websocketLogLevelSwitch.MinimumLevel); } /// @@ -453,12 +518,17 @@ namespace PepperDash.Core { _errorLogLevelSwitch.MinimumLevel = level; - var err = CrestronDataStoreStatic.SetLocalUintValue(ErrorLogLevelStoreKey, (uint)level); + CrestronConsole.ConsoleCommandResponse("[Application {0}] Error log level set to {1}\r\n", + InitialParametersClass.ApplicationNumber, _errorLogLevelSwitch.MinimumLevel); + + CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int)level}"); + + var err = CrestronDataStoreStatic.SetLocalIntValue(ErrorLogLevelStoreKey, (int)level); + + CrestronConsole.ConsoleCommandResponse($"Store result: {err}:{(int)level}"); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) - LogMessage(LogEventLevel.Information, "Error saving Error Log debug level setting: {error}", err); - - LogMessage(LogEventLevel.Information, "Error log debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel); + CrestronConsole.PrintLine($"Error saving error log debug level setting: {err}"); } /// @@ -466,14 +536,19 @@ namespace PepperDash.Core /// public static void SetFileMinimumDebugLevel(LogEventLevel level) { - _errorLogLevelSwitch.MinimumLevel = level; + _fileLogLevelSwitch.MinimumLevel = level; - var err = CrestronDataStoreStatic.SetLocalUintValue(ErrorLogLevelStoreKey, (uint)level); + CrestronConsole.ConsoleCommandResponse("[Application {0}] File log level set to {1}\r\n", + InitialParametersClass.ApplicationNumber, _fileLogLevelSwitch.MinimumLevel); + + CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int)level}"); + + var err = CrestronDataStoreStatic.SetLocalIntValue(FileLevelStoreKey, (int)level); + + CrestronConsole.ConsoleCommandResponse($"Store result: {err}:{(int)level}"); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) - LogMessage(LogEventLevel.Information, "Error saving File debug level setting: {error}", err); - - LogMessage(LogEventLevel.Information, "File debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel); + CrestronConsole.PrintLine($"Error saving file debug level setting: {err}"); } /// diff --git a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs index 1dc843a1..92ac2b9c 100644 --- a/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs +++ b/src/PepperDash.Essentials.Core/Bridges/BridgeBase.cs @@ -2,14 +2,12 @@ using System; using System.Collections.Generic; -using Crestron.SimplSharp; 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.Essentials.Core.Config; using Serilog.Events; @@ -355,22 +353,22 @@ namespace PepperDash.Essentials.Core.Bridges /// public class EiscApiPropertiesConfig { - [JsonProperty("control")] /// /// Gets or sets the Control /// + [JsonProperty("control")] public EssentialsControlPropertiesConfig Control { get; set; } - [JsonProperty("devices")] /// /// Gets or sets the Devices /// + [JsonProperty("devices")] public List Devices { get; set; } - [JsonProperty("rooms")] /// /// Gets or sets the Rooms /// + [JsonProperty("rooms")] public List Rooms { get; set; } @@ -379,22 +377,22 @@ namespace PepperDash.Essentials.Core.Bridges /// public class ApiDevicePropertiesConfig { - [JsonProperty("deviceKey")] /// /// Gets or sets the DeviceKey /// + [JsonProperty("deviceKey")] public string DeviceKey { get; set; } - [JsonProperty("joinStart")] /// /// Gets or sets the JoinStart /// + [JsonProperty("joinStart")] public uint JoinStart { get; set; } - [JsonProperty("joinMapKey")] /// /// Gets or sets the JoinMapKey /// + [JsonProperty("joinMapKey")] public string JoinMapKey { get; set; } } @@ -403,22 +401,22 @@ namespace PepperDash.Essentials.Core.Bridges /// public class ApiRoomPropertiesConfig { - [JsonProperty("roomKey")] /// /// Gets or sets the RoomKey /// + [JsonProperty("roomKey")] public string RoomKey { get; set; } - [JsonProperty("joinStart")] /// /// Gets or sets the JoinStart /// + [JsonProperty("joinStart")] public uint JoinStart { get; set; } - [JsonProperty("joinMapKey")] /// /// Gets or sets the JoinMapKey /// + [JsonProperty("joinMapKey")] public string JoinMapKey { get; set; } } diff --git a/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs b/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs index 651f17aa..23063773 100644 --- a/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs +++ b/src/PepperDash.Essentials.Core/Config/DeviceConfig.cs @@ -18,41 +18,41 @@ namespace PepperDash.Essentials.Core.Config /// public class DeviceConfig { - [JsonProperty("key")] /// /// Gets or sets the Key /// + [JsonProperty("key")] public string Key { get; set; } - [JsonProperty("uid")] /// /// Gets or sets the Uid /// + [JsonProperty("uid")] public int Uid { get; set; } - [JsonProperty("name")] /// /// Gets or sets the Name /// + [JsonProperty("name")] public string Name { get; set; } - [JsonProperty("group")] /// /// Gets or sets the Group /// + [JsonProperty("group")] public string Group { get; set; } - [JsonProperty("type")] /// /// Gets or sets the Type /// + [JsonProperty("type")] public string Type { get; set; } - [JsonProperty("properties")] - [JsonConverter(typeof(DevicePropertiesConverter))] /// /// Gets or sets the Properties /// + [JsonProperty("properties")] + [JsonConverter(typeof(DevicePropertiesConverter))] public JToken Properties { get; set; } public DeviceConfig(DeviceConfig dc) @@ -68,7 +68,7 @@ namespace PepperDash.Essentials.Core.Config //Properties = JToken.FromObject(dc.Properties); } - public DeviceConfig() {} + public DeviceConfig() { } } /// diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs index 8463ae96..6f858144 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericDigitalInputDevice.cs @@ -2,59 +2,54 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; +using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; -using Serilog.Events; namespace PepperDash.Essentials.Core.CrestronIO { - [Description("Wrapper class for Digital Input")] + /// /// Represents a GenericDigitalInputDevice /// - public class GenericDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput + /// [Description("Wrapper class for Digital Input")] + public class GenericDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IHasFeedback { - /// - /// Gets or sets the InputPort - /// - public DigitalInput InputPort { get; private set; } + private DigitalInput inputPort; /// /// Gets or sets the InputStateFeedback /// public BoolFeedback InputStateFeedback { get; private set; } - Func InputStateFeedbackFunc - { - get - { - return () => InputPort.State; - } - } - + /// + public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); + /// + /// Initializes a new instance of the class. + /// + /// key for device + /// name for device + /// function to call after activation. Should return the DigitalInput + /// config for device public GenericDigitalInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { - InputStateFeedback = new BoolFeedback(InputStateFeedbackFunc); + InputStateFeedback = new BoolFeedback("inputState", () => inputPort.State); AddPostActivationAction(() => { - InputPort = postActivationFunc(config); + inputPort = postActivationFunc(config); - InputPort.Register(); - - InputPort.StateChange += InputPort_StateChange; + inputPort.Register(); + inputPort.StateChange += InputPort_StateChange; }); } @@ -71,41 +66,31 @@ namespace PepperDash.Essentials.Core.CrestronIO private static DigitalInput GetDigitalInput(IOPortConfig dc) { - IDigitalInputPorts ioPortDevice; if (dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsDigitalInput) { - Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Processor does not support Digital Inputs"); + Debug.LogError("GetDigitalInput: Processor does not support Digital Inputs"); return null; } - ioPortDevice = Global.ControlSystem; + + return Global.ControlSystem.DigitalInputPorts[dc.PortNumber]; } - else + + if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IDigitalInputPorts ioPortDevice)) { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IDigitalInputPorts; - if (ioPortDev == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device {0} is not a valid device", dc.PortDeviceKey); - return null; - } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device '0' is not a valid IDigitalInputPorts Device", dc.PortDeviceKey); + Debug.LogError("GetDigitalInput: Device {key} is not a valid device", dc.PortDeviceKey); return null; } if (dc.PortNumber > ioPortDevice.NumberOfDigitalInputPorts) { - Debug.LogMessage(LogEventLevel.Information, "GetDigitalInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + Debug.LogError("GetDigitalInput: Device {key} does not contain a digital input port {port}", dc.PortDeviceKey, dc.PortNumber); + return null; } return ioPortDevice.DigitalInputPorts[dc.PortNumber]; - - } #endregion @@ -131,20 +116,20 @@ namespace PepperDash.Essentials.Core.CrestronIO } else { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } try { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + this.LogDebug("Linking to Trilist '{0}'", trilist.ID.ToString("X")); // Link feedback for input state InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState.JoinNumber]); } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + this.LogError("Unable to link device {key}. {message}", Key, e.Message); + this.LogDebug(e, "Stack Trace: "); } } @@ -153,22 +138,22 @@ namespace PepperDash.Essentials.Core.CrestronIO #region Factory /// - /// Represents a GenericDigitalInputDeviceFactory + /// Factory for creating GenericDigitalInputDevice devices /// public class GenericDigitalInputDeviceFactory : EssentialsDeviceFactory { + /// + /// Constructor for GenericDigitalInputDeviceFactory + /// public GenericDigitalInputDeviceFactory() { TypeNames = new List() { "digitalinput" }; } - /// - /// BuildDevice method - /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Digital Input Device"); + Debug.LogDebug("Factory Attempting to create new Generic Digital Input Device"); var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs index c87a688c..ad5507d0 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportAnalogInputDevice.cs @@ -2,66 +2,64 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; - -using PepperDash.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Bridges; - - using Newtonsoft.Json; -using Serilog.Events; +using PepperDash.Core; +using PepperDash.Core.Logging; +using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Represents a generic digital input deviced tied to a versiport /// - public class GenericVersiportAnalogInputDevice : EssentialsBridgeableDevice, IAnalogInput + public class GenericVersiportAnalogInputDevice : EssentialsBridgeableDevice, IAnalogInput, IHasFeedback { - public Versiport InputPort { get; private set; } + private Versiport inputPort; + /// public IntFeedback InputValueFeedback { get; private set; } + + /// + /// Get the InputMinimumChangeFeedback + /// + /// + /// Updates when the analog input minimum change value changes + /// public IntFeedback InputMinimumChangeFeedback { get; private set; } - Func InputValueFeedbackFunc - { - get - { - return () => InputPort.AnalogIn; - } - } - - Func InputMinimumChangeFeedbackFunc - { - get { return () => InputPort.AnalogMinChange; } - } + /// + public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); + /// + /// Initializes a new instance of the class. + /// + /// key for the device + /// name for the device + /// function to call after activation + /// IO port configuration public GenericVersiportAnalogInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { - InputValueFeedback = new IntFeedback(InputValueFeedbackFunc); - InputMinimumChangeFeedback = new IntFeedback(InputMinimumChangeFeedbackFunc); + InputValueFeedback = new IntFeedback("inputValue", () => inputPort.AnalogIn); + InputMinimumChangeFeedback = new IntFeedback("inputMinimumChange", () => inputPort.AnalogMinChange); AddPostActivationAction(() => { - InputPort = postActivationFunc(config); + inputPort = postActivationFunc(config); - InputPort.Register(); + inputPort.Register(); - InputPort.SetVersiportConfiguration(eVersiportConfiguration.AnalogInput); - InputPort.AnalogMinChange = (ushort)(config.MinimumChange > 0 ? config.MinimumChange : 655); + inputPort.SetVersiportConfiguration(eVersiportConfiguration.AnalogInput); + inputPort.AnalogMinChange = (ushort)(config.MinimumChange > 0 ? config.MinimumChange : 655); if (config.DisablePullUpResistor) - InputPort.DisablePullUpResistor = true; + inputPort.DisablePullUpResistor = true; - InputPort.VersiportChange += InputPort_VersiportChange; - - Debug.LogMessage(LogEventLevel.Debug, this, "Created GenericVersiportAnalogInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor); + inputPort.VersiportChange += InputPort_VersiportChange; + this.LogDebug("Created GenericVersiportAnalogInputDevice on port {port}. DisablePullUpResistor: {pullUpResistorDisabled}", config.PortNumber, inputPort.DisablePullUpResistor); }); } @@ -69,20 +67,17 @@ namespace PepperDash.Essentials.Core.CrestronIO /// /// Set minimum voltage change for device to update voltage changed method /// - /// valid values range from 0 - 65535, representing the full 100% range of the processor voltage source. Check processor documentation for details - /// - /// SetMinimumChange method - /// + /// valid values range from 0 - 65535, representing the full 100% range of the processor voltage source. Check processor documentation for details public void SetMinimumChange(ushort value) { - InputPort.AnalogMinChange = value; + inputPort.AnalogMinChange = value; } void InputPort_VersiportChange(Versiport port, VersiportEventArgs args) { - Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event); + this.LogDebug("Versiport change: {event}", args.Event); - if(args.Event == eVersiportEvent.AnalogInChange) + if (args.Event == eVersiportEvent.AnalogInChange) InputValueFeedback.FireUpdate(); if (args.Event == eVersiportEvent.AnalogMinChangeChange) InputMinimumChangeFeedback.FireUpdate(); @@ -91,9 +86,6 @@ namespace PepperDash.Essentials.Core.CrestronIO #region Bridge Linking - /// - /// LinkToApi method - /// /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { @@ -110,12 +102,12 @@ namespace PepperDash.Essentials.Core.CrestronIO } else { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } try { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + this.LogDebug("Linking to Trilist '{trilistId}'", trilist.ID.ToString("X")); // Link feedback for input state InputValueFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputValue.JoinNumber]); @@ -125,8 +117,8 @@ namespace PepperDash.Essentials.Core.CrestronIO } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + this.LogError("Unable to link device {key}: {message}", Key, e.Message); + this.LogDebug(e, "Stack Trace: "); } trilist.OnlineStatusChange += (d, args) => @@ -138,11 +130,6 @@ namespace PepperDash.Essentials.Core.CrestronIO } - void trilist_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) - { - throw new NotImplementedException(); - } - #endregion @@ -151,70 +138,55 @@ namespace PepperDash.Essentials.Core.CrestronIO /// public static Versiport GetVersiportDigitalInput(IOPortConfig dc) { - - IIOPorts ioPortDevice; - if (dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsVersiport) { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Processor does not support Versiports"); + Debug.LogError("GetVersiportAnalogInput: Processor does not support Versiports"); return null; } - ioPortDevice = Global.ControlSystem; + return Global.ControlSystem.VersiPorts[dc.PortNumber]; } - else + + if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IIOPorts ioPortDevice)) { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; - if (ioPortDev == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} is not a valid device", dc.PortDeviceKey); - return null; - } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey); + Debug.LogError("GetVersiportAnalogInput: Device {key} is not a valid device", dc.PortDeviceKey); return null; } if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + Debug.LogError("GetVersiportAnalogInput: Device {key} does not contain a port {port}", dc.PortDeviceKey, dc.PortNumber); return null; } - if(!ioPortDevice.VersiPorts[dc.PortNumber].SupportsAnalogInput) + if (!ioPortDevice.VersiPorts[dc.PortNumber].SupportsAnalogInput) { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportAnalogInput: Device {0} does not support AnalogInput on port {1}", dc.PortDeviceKey, dc.PortNumber); + Debug.LogError("GetVersiportAnalogInput: Device {key} does not support AnalogInput on port {port}", dc.PortDeviceKey, dc.PortNumber); return null; } - return ioPortDevice.VersiPorts[dc.PortNumber]; - - } } /// - /// Represents a GenericVersiportAbalogInputDeviceFactory + /// Factory for creating GenericVersiportAnalogInputDevice devices /// - public class GenericVersiportAbalogInputDeviceFactory : EssentialsDeviceFactory + public class GenericVersiportAnalogInputDeviceFactory : EssentialsDeviceFactory { - public GenericVersiportAbalogInputDeviceFactory() + /// + /// Constructor for GenericVersiportAnalogInputDeviceFactory + /// + public GenericVersiportAnalogInputDeviceFactory() { TypeNames = new List() { "versiportanaloginput" }; } - /// - /// BuildDevice method - /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); + Debug.LogDebug("Factory Attempting to create new Generic Versiport Device"); var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs index f94137c3..e2c4474a 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs @@ -2,78 +2,82 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; - -using PepperDash.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Bridges; - - using Newtonsoft.Json; -using Serilog.Events; +using PepperDash.Core; +using PepperDash.Core.Logging; +using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core.CrestronIO { /// /// Represents a generic digital input deviced tied to a versiport /// - public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IPartitionStateProvider + public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IPartitionStateProvider, IHasFeedback { - public Versiport InputPort { get; private set; } + private Versiport inputPort; + /// + /// Gets or sets the InputStateFeedback + /// public BoolFeedback InputStateFeedback { get; private set; } - Func InputStateFeedbackFunc - { - get - { - return () => InputPort.DigitalIn; - } - } + /// + public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); /// /// Gets or sets the PartitionPresentFeedback /// public BoolFeedback PartitionPresentFeedback { get; } - public bool PartitionPresent => !InputStateFeedbackFunc(); + /// + /// Get partition state + /// + public bool PartitionPresent => !inputPort.DigitalIn; + /// + /// Initializes a new instance of the class. + /// + /// key for device + /// name for device + /// function to call after activation. Should return the Versiport + /// config for device public GenericVersiportDigitalInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { - InputStateFeedback = new BoolFeedback(InputStateFeedbackFunc); - PartitionPresentFeedback = new BoolFeedback(() => !InputStateFeedbackFunc()); + InputStateFeedback = new BoolFeedback("inputState", () => inputPort.DigitalIn); + PartitionPresentFeedback = new BoolFeedback("partitionPresent", () => !inputPort.DigitalIn); AddPostActivationAction(() => { - InputPort = postActivationFunc(config); + inputPort = postActivationFunc(config); - InputPort.Register(); + inputPort.Register(); - InputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); + inputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); if (config.DisablePullUpResistor) - InputPort.DisablePullUpResistor = true; + inputPort.DisablePullUpResistor = true; - InputPort.VersiportChange += InputPort_VersiportChange; + inputPort.VersiportChange += InputPort_VersiportChange; InputStateFeedback.FireUpdate(); PartitionPresentFeedback.FireUpdate(); - Debug.LogMessage(LogEventLevel.Debug, this, "Created GenericVersiportDigitalInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor); + this.LogDebug("Created GenericVersiportDigitalInputDevice for port {port}. DisablePullUpResistor: {pullUpResistorDisable}", config.PortNumber, inputPort.DisablePullUpResistor); }); + Feedbacks.Add(InputStateFeedback); + Feedbacks.Add(PartitionPresentFeedback); } void InputPort_VersiportChange(Versiport port, VersiportEventArgs args) { - Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event); + this.LogDebug("Versiport change: {0}", args.Event); - if(args.Event == eVersiportEvent.DigitalInChange) + if (args.Event == eVersiportEvent.DigitalInChange) { InputStateFeedback.FireUpdate(); PartitionPresentFeedback.FireUpdate(); @@ -102,20 +106,20 @@ namespace PepperDash.Essentials.Core.CrestronIO } else { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } try { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + this.LogDebug("Linking to Trilist '{0}'", trilist.ID.ToString("X")); // Link feedback for input state InputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.InputState.JoinNumber]); } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + this.LogError("Unable to link device {key}. Input is null. {message}", Key, e.Message); + this.LogDebug(e, "Stack Trace: "); } } @@ -127,63 +131,50 @@ namespace PepperDash.Essentials.Core.CrestronIO /// public static Versiport GetVersiportDigitalInput(IOPortConfig dc) { - - IIOPorts ioPortDevice; - if (dc.PortDeviceKey.Equals("processor")) { if (!Global.ControlSystem.SupportsVersiport) { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Processor does not support Versiports"); + Debug.LogError("GetVersiportDigitalInput: Processor does not support Versiports"); return null; } - ioPortDevice = Global.ControlSystem; + return Global.ControlSystem.VersiPorts[dc.PortNumber]; } - else + + if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IIOPorts ioPortDevice)) { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; - if (ioPortDev == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device {0} is not a valid device", dc.PortDeviceKey); - return null; - } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device '0' is not a valid IIOPorts Device", dc.PortDeviceKey); + Debug.LogError("GetVersiportDigitalInput: Device {key} is not a valid device", dc.PortDeviceKey); return null; } if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalInput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + Debug.LogError("GetVersiportDigitalInput: Device {key} does not contain versiport {port}", dc.PortDeviceKey, dc.PortNumber); + return null; } return ioPortDevice.VersiPorts[dc.PortNumber]; - - } } /// - /// Represents a GenericVersiportDigitalInputDeviceFactory + /// Factory class for GenericVersiportDigitalInputDevice /// public class GenericVersiportDigitalInputDeviceFactory : EssentialsDeviceFactory { + /// + /// Constructor for GenericVersiportDigitalInputDeviceFactory + /// public GenericVersiportDigitalInputDeviceFactory() { TypeNames = new List() { "versiportinput" }; } - /// - /// BuildDevice method - /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); + Debug.LogDebug("Factory Attempting to create new Generic Versiport Device"); var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs index 7a823c9a..ee3f0320 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportOutputDevice.cs @@ -2,18 +2,13 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; - -using PepperDash.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Bridges; - - using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Core.Logging; +using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; using Serilog.Events; namespace PepperDash.Essentials.Core.CrestronIO @@ -21,76 +16,68 @@ namespace PepperDash.Essentials.Core.CrestronIO /// /// Represents a generic digital input deviced tied to a versiport /// - public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput + public class GenericVersiportDigitalOutputDevice : EssentialsBridgeableDevice, IDigitalOutput, IHasFeedback { - public Versiport OutputPort { get; private set; } + private Versiport outputPort; + /// + /// Gets or sets the OutputStateFeedback + /// public BoolFeedback OutputStateFeedback { get; private set; } - Func OutputStateFeedbackFunc - { - get - { - return () => OutputPort.DigitalOut; - } - } + /// + public FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); + /// + /// Initializes a new instance of the class. + /// public GenericVersiportDigitalOutputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { - OutputStateFeedback = new BoolFeedback(OutputStateFeedbackFunc); + OutputStateFeedback = new BoolFeedback("outputState", () => outputPort.DigitalOut); AddPostActivationAction(() => { - OutputPort = postActivationFunc(config); + outputPort = postActivationFunc(config); - OutputPort.Register(); + outputPort.Register(); - if (!OutputPort.SupportsDigitalOutput) + if (!outputPort.SupportsDigitalOutput) { - Debug.LogMessage(LogEventLevel.Information, this, "Device does not support configuration as a Digital Output"); + this.LogError("Device does not support configuration as a Digital Output"); return; } - OutputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalOutput); + outputPort.SetVersiportConfiguration(eVersiportConfiguration.DigitalOutput); - OutputPort.VersiportChange += OutputPort_VersiportChange; + outputPort.VersiportChange += OutputPort_VersiportChange; }); - } void OutputPort_VersiportChange(Versiport port, VersiportEventArgs args) { - Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event); + this.LogDebug("Versiport change: {event}", args.Event); - if(args.Event == eVersiportEvent.DigitalOutChange) + if (args.Event == eVersiportEvent.DigitalOutChange) OutputStateFeedback.FireUpdate(); } /// /// Set value of the versiport digital output /// - /// value to set the output to - /// - /// SetOutput method - /// + /// value to set the output to public void SetOutput(bool state) { - if (OutputPort.SupportsDigitalOutput) - { - Debug.LogMessage(LogEventLevel.Information, this, "Passed the Check"); - - OutputPort.DigitalOut = state; - - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Versiport does not support Digital Output Mode"); - } + if (!outputPort.SupportsDigitalOutput) + { + this.LogError("Versiport does not support Digital Output Mode"); + return; + } + outputPort.DigitalOut = state; } #region Bridge Linking @@ -114,12 +101,12 @@ namespace PepperDash.Essentials.Core.CrestronIO } else { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device."); } try { - Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + this.LogDebug("Linking to Trilist '{0}'", trilist.ID.ToString("X")); // Link feedback for input state OutputStateFeedback.LinkInputSig(trilist.BooleanInput[joinMap.OutputState.JoinNumber]); @@ -127,8 +114,8 @@ namespace PepperDash.Essentials.Core.CrestronIO } catch (Exception e) { - Debug.LogMessage(LogEventLevel.Debug, this, "Unable to link device '{0}'. Input is null", Key); - Debug.LogMessage(LogEventLevel.Debug, this, "Error: {0}", e); + this.LogError("Unable to link device: {message}", e.Message); + this.LogDebug(e, "Stack Trace: "); } } @@ -140,41 +127,28 @@ namespace PepperDash.Essentials.Core.CrestronIO /// public static Versiport GetVersiportDigitalOutput(IOPortConfig dc) { - - IIOPorts ioPortDevice; - - if (dc.PortDeviceKey.Equals("processor")) + if (dc.PortDeviceKey.Equals("processor")) + { + if (!Global.ControlSystem.SupportsVersiport) { - if (!Global.ControlSystem.SupportsVersiport) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Processor does not support Versiports"); - return null; - } - ioPortDevice = Global.ControlSystem; - } - else - { - var ioPortDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IIOPorts; - if (ioPortDev == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device {0} is not a valid device", dc.PortDeviceKey); - return null; - } - ioPortDevice = ioPortDev; - } - if (ioPortDevice == null) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device '0' is not a valid IOPorts Device", dc.PortDeviceKey); + Debug.LogError("GetVersiportDigitalOutput: Processor does not support Versiports"); return null; } + return Global.ControlSystem.VersiPorts[dc.PortNumber]; + } - if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) - { - Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOuptut: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); - } - var port = ioPortDevice.VersiPorts[dc.PortNumber]; - return port; + if (!(DeviceManager.GetDeviceForKey(dc.PortDeviceKey) is IIOPorts ioPortDevice)) + { + Debug.LogError("GetVersiportDigitalOutput: Device {key} is not a valid device", dc.PortDeviceKey); + return null; + } + if (dc.PortNumber > ioPortDevice.NumberOfVersiPorts) + { + Debug.LogMessage(LogEventLevel.Information, "GetVersiportDigitalOutput: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); + return null; + } + return ioPortDevice.VersiPorts[dc.PortNumber]; } } @@ -184,18 +158,18 @@ namespace PepperDash.Essentials.Core.CrestronIO /// public class GenericVersiportDigitalOutputDeviceFactory : EssentialsDeviceFactory { + /// + /// Initialize a new instance of the class. + /// public GenericVersiportDigitalOutputDeviceFactory() { TypeNames = new List() { "versiportoutput" }; } - /// - /// BuildDevice method - /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Versiport Device"); + Debug.LogDebug("Factory Attempting to create new Generic Versiport Device"); var props = JsonConvert.DeserializeObject(dc.Properties.ToString()); diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs b/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs index c647834e..426834ed 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IAnalogInput.cs @@ -12,6 +12,12 @@ namespace PepperDash.Essentials.Core.CrestronIO /// public interface IAnalogInput { + /// + /// Get the InputValueFeedback. + /// + /// + /// Updates when the analog input value changes + /// IntFeedback InputValueFeedback { get; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs b/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs index 52db6300..8641df69 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/IOPortConfig.cs @@ -14,25 +14,28 @@ namespace PepperDash.Essentials.Core.CrestronIO /// public class IOPortConfig { - [JsonProperty("portDeviceKey")] /// /// Gets or sets the PortDeviceKey /// + [JsonProperty("portDeviceKey")] public string PortDeviceKey { get; set; } - [JsonProperty("portNumber")] + /// /// Gets or sets the PortNumber /// + [JsonProperty("portNumber")] public uint PortNumber { get; set; } - [JsonProperty("disablePullUpResistor")] + /// /// Gets or sets the DisablePullUpResistor /// + [JsonProperty("disablePullUpResistor")] public bool DisablePullUpResistor { get; set; } - [JsonProperty("minimumChange")] + /// /// Gets or sets the MinimumChange /// + [JsonProperty("minimumChange")] public int MinimumChange { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ICustomMobileControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ICustomMobileControl.cs new file mode 100644 index 00000000..3ae19216 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/ICustomMobileControl.cs @@ -0,0 +1,11 @@ +using PepperDash.Core; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + /// + /// Use this interface on a device or room if it uses custom Mobile Control messengers + /// + public interface ICustomMobileControl : IKeyed + { + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs index 09420b7e..0b1760fa 100644 --- a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControl.cs @@ -1,155 +1,72 @@ using System; -using System.Collections.ObjectModel; -using Crestron.SimplSharpPro; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { - /// - /// Use this interface on a device or room if it uses custom Mobile Control messengers - /// - public interface ICustomMobileControl : IKeyed - { - } - - /*/// - /// Describes a MobileControlSystemController - /// - public interface IMobileControl : IKeyed - { - void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent); - - void LinkSystemMonitorToAppServer(); - }*/ /// /// Defines the contract for IMobileControl /// public interface IMobileControl : IKeyed { + /// + /// Gets the Host + /// string Host { get; } + /// + /// Gets the Client App URL + /// string ClientAppUrl { get; } + /// + /// Gets the System UUID + /// string SystemUuid { get; } + /// + /// Gets the ApiOnlineAndAuthorized feedback + /// BoolFeedback ApiOnlineAndAuthorized { get; } + /// + /// Sends the message object to the AppServer + /// + /// Message to send void SendMessageObject(IMobileControlMessage o); + /// + /// Adds an action for a messenger + /// + /// Messenger type. Must implement IMobileControlMessenger + /// messenger to register + /// action to add void AddAction(T messenger, Action action) where T : IMobileControlMessenger; + /// + /// Removes an action for a messenger + /// + /// key for action void RemoveAction(string key); + /// + /// Adds a device messenger + /// + /// Messenger to add void AddDeviceMessenger(IMobileControlMessenger messenger); + /// + /// Check if a device messenger exists + /// + /// Messenger key to find bool CheckForDeviceMessenger(string key); + /// + /// Get a Room Messenger by key + /// + /// messenger key to find + /// Messenger if found, null otherwise IMobileControlRoomMessenger GetRoomMessenger(string key); - - } - - /// - /// Defines the contract for IMobileControlMessenger - /// - public interface IMobileControlMessenger : IKeyed - { - IMobileControl AppServerController { get; } - string MessagePath { get; } - - string DeviceKey { get; } - void RegisterWithAppServer(IMobileControl appServerController); - } - - public interface IMobileControlMessage - { - [JsonProperty("type")] - string Type { get; } - - [JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)] - string ClientId { get; } - - [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] - JToken Content { get; } - - } - - /// - /// Defines the contract for IMobileControlRoomMessenger - /// - public interface IMobileControlRoomMessenger : IKeyed - { - event EventHandler UserCodeChanged; - - event EventHandler UserPromptedForCode; - - event EventHandler ClientJoined; - - event EventHandler AppUrlChanged; - - string UserCode { get; } - - string QrCodeUrl { get; } - - string QrCodeChecksum { get; } - - string McServerUrl { get; } - - string RoomName { get; } - - string AppUrl { get; } - - void UpdateAppUrl(string url); - } - - /// - /// Defines the contract for IMobileControlAction - /// - public interface IMobileControlAction - { - IMobileControlMessenger Messenger { get; } - - Action Action { get; } - } - - /// - /// Defines the contract for IMobileControlTouchpanelController - /// - public interface IMobileControlTouchpanelController : IKeyed - { - /// - /// The default room key for the controller - /// - string DefaultRoomKey { get; } - - /// - /// Sets the application URL for the controller - /// - /// The application URL - void SetAppUrl(string url); - - /// - /// Indicates whether the controller uses a direct server connection - /// - bool UseDirectServer { get; } - - /// - /// Indicates whether the controller is a Zoom Room controller - /// - bool ZoomRoomController { get; } - } - - /// - /// Describes a MobileControl Crestron Touchpanel Controller - /// This interface extends the IMobileControlTouchpanelController to include connected IP information - /// - public interface IMobileControlCrestronTouchpanelController : IMobileControlTouchpanelController - { - /// - /// Gets a collection of connected IP information for the touchpanel controller - /// - ReadOnlyCollection ConnectedIps { get; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlAction.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlAction.cs new file mode 100644 index 00000000..982deaae --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlAction.cs @@ -0,0 +1,15 @@ +using System; +using Newtonsoft.Json.Linq; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + /// + /// Defines the contract for IMobileControlAction + /// + public interface IMobileControlAction + { + IMobileControlMessenger Messenger { get; } + + Action Action { get; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlCrestronTouchpanelController.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlCrestronTouchpanelController.cs new file mode 100644 index 00000000..9878fcbd --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlCrestronTouchpanelController.cs @@ -0,0 +1,17 @@ +using System.Collections.ObjectModel; +using Crestron.SimplSharpPro; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + /// + /// Describes a MobileControl Crestron Touchpanel Controller + /// This interface extends the IMobileControlTouchpanelController to include connected IP information + /// + public interface IMobileControlCrestronTouchpanelController : IMobileControlTouchpanelController + { + /// + /// Gets a collection of connected IP information for the touchpanel controller + /// + ReadOnlyCollection ConnectedIps { get; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessage.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessage.cs new file mode 100644 index 00000000..41645da2 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessage.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + public interface IMobileControlMessage + { + [JsonProperty("type")] + string Type { get; } + + [JsonProperty("clientId", NullValueHandling = NullValueHandling.Ignore)] + string ClientId { get; } + + [JsonProperty("content", NullValueHandling = NullValueHandling.Ignore)] + JToken Content { get; } + + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessenger.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessenger.cs new file mode 100644 index 00000000..178289e4 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessenger.cs @@ -0,0 +1,31 @@ +using PepperDash.Core; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + /// + /// Defines the contract for IMobileControlMessenger + /// + public interface IMobileControlMessenger : IKeyed + { + /// + /// Parent controller for this messenger + /// + IMobileControl AppServerController { get; } + + /// + /// Path to listen for messages + /// + string MessagePath { get; } + + /// + /// Key of the device this messenger is associated with + /// + string DeviceKey { get; } + + /// + /// Register this messenger with the AppServerController + /// + /// + void RegisterWithAppServer(IMobileControl appServerController); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessengerWithSubscriptions.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessengerWithSubscriptions.cs new file mode 100644 index 00000000..887f1789 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlMessengerWithSubscriptions.cs @@ -0,0 +1,23 @@ +using PepperDash.Core; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + /// + /// Defines the contract for IMobileControlMessenger + /// + public interface IMobileControlMessengerWithSubscriptions : IMobileControlMessenger + { + /// + /// Unsubscribe a client from this messenger + /// + /// + void UnsubscribeClient(string clientId); + + /// + /// Register this messenger with the AppServerController + /// + /// parent for this messenger + /// Enable messenger subscriptions + void RegisterWithAppServer(IMobileControl appServerController, bool enableMessengerSubscriptions); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlRoomMessenger.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlRoomMessenger.cs new file mode 100644 index 00000000..6f4d9a17 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlRoomMessenger.cs @@ -0,0 +1,33 @@ +using System; +using PepperDash.Core; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + /// + /// Defines the contract for IMobileControlRoomMessenger + /// + public interface IMobileControlRoomMessenger : IKeyed + { + event EventHandler UserCodeChanged; + + event EventHandler UserPromptedForCode; + + event EventHandler ClientJoined; + + event EventHandler AppUrlChanged; + + string UserCode { get; } + + string QrCodeUrl { get; } + + string QrCodeChecksum { get; } + + string McServerUrl { get; } + + string RoomName { get; } + + string AppUrl { get; } + + void UpdateAppUrl(string url); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlTouchpanelController.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlTouchpanelController.cs new file mode 100644 index 00000000..e0d5f05d --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IMobileControlTouchpanelController.cs @@ -0,0 +1,31 @@ +using PepperDash.Core; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + /// + /// Defines the contract for IMobileControlTouchpanelController + /// + public interface IMobileControlTouchpanelController : IKeyed + { + /// + /// The default room key for the controller + /// + string DefaultRoomKey { get; } + + /// + /// Sets the application URL for the controller + /// + /// The application URL + void SetAppUrl(string url); + + /// + /// Indicates whether the controller uses a direct server connection + /// + bool UseDirectServer { get; } + + /// + /// Indicates whether the controller is a Zoom Room controller + /// + bool ZoomRoomController { get; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs b/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs index ab698d85..1c9709b8 100644 --- a/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs +++ b/src/PepperDash.Essentials.Core/Devices/DeviceManager.cs @@ -202,7 +202,7 @@ namespace PepperDash.Essentials.Core private static void ListDevices(string s) { - CrestronConsole.ConsoleCommandResponse($"{Devices.Count} Devices registered with Device Manager:"); + CrestronConsole.ConsoleCommandResponse($"{Devices.Count} Devices registered with Device Manager:\r\n"); var sorted = Devices.Values.ToList(); sorted.Sort((a, b) => a.Key.CompareTo(b.Key)); @@ -210,7 +210,7 @@ namespace PepperDash.Essentials.Core foreach (var d in sorted) { var name = d is IKeyName ? (d as IKeyName).Name : "---"; - CrestronConsole.ConsoleCommandResponse($" [{d.Key}] {name}"); + CrestronConsole.ConsoleCommandResponse($" [{d.Key}] {name}\r\n"); } } @@ -219,28 +219,17 @@ namespace PepperDash.Essentials.Core var dev = GetDeviceForKey(devKey); if (dev == null) { - Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey); + CrestronConsole.ConsoleCommandResponse($"Device '{devKey}' not found\r\n"); return; } if (!(dev is IHasFeedback statusDev)) { - Debug.LogMessage(LogEventLevel.Information, "Device '{0}' does not have visible feedbacks", devKey); + CrestronConsole.ConsoleCommandResponse($"Device '{devKey}' does not have visible feedbacks\r\n"); return; } statusDev.DumpFeedbacksToConsole(true); } - //static void ListDeviceCommands(string devKey) - //{ - // var dev = GetDeviceForKey(devKey); - // if (dev == null) - // { - // Debug.LogMessage(LogEventLevel.Information, "Device '{0}' not found", devKey); - // return; - // } - // Debug.LogMessage(LogEventLevel.Information, "This needs to be reworked. Stay tuned.", devKey); - //} - private static void ListDeviceCommStatuses(string input) { @@ -250,12 +239,6 @@ namespace PepperDash.Essentials.Core } } - - //static void DoDeviceCommand(string command) - //{ - // Debug.LogMessage(LogEventLevel.Information, "Not yet implemented. Stay tuned"); - //} - /// /// AddDevice method /// diff --git a/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs index 3ac326bf..9c1a6a94 100644 --- a/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs +++ b/src/PepperDash.Essentials.Core/Devices/EssentialsDeviceFactory.cs @@ -18,7 +18,7 @@ namespace PepperDash.Essentials.Core public List TypeNames { get; protected set; } /// - /// The method that will build the device + /// Build the device using the configuration /// /// The device config /// An instance of the device diff --git a/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs b/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs index 91620c63..330538e0 100644 --- a/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs +++ b/src/PepperDash.Essentials.Core/Devices/IHasFeedbacks.cs @@ -1,65 +1,90 @@ using System; using System.Linq; - +using Crestron.SimplSharp; using PepperDash.Core; using Serilog.Events; namespace PepperDash.Essentials.Core { - /// - /// Defines the contract for IHasFeedback - /// + /// + /// Defines the contract for IHasFeedback + /// public interface IHasFeedback : IKeyed { /// - /// This method shall return a list of all Output objects on a device, + /// This method returns a list of all Output objects on a device, /// including all "aggregate" devices. /// FeedbackCollection Feedbacks { get; } } - + /// + /// Extension methods for IHasFeedback + /// public static class IHasFeedbackExtensions { + /// + /// Gets the feedback type name for sorting purposes + /// + /// The feedback to get the type name for + /// A string representing the feedback type + private static string GetFeedbackTypeName(Feedback feedback) + { + if (feedback is BoolFeedback) + return "boolean"; + else if (feedback is IntFeedback) + return "integer"; + else if (feedback is StringFeedback) + return "string"; + else + return feedback.GetType().Name; + } + + /// + /// Dumps the feedbacks to the console + /// + /// + /// public static void DumpFeedbacksToConsole(this IHasFeedback source, bool getCurrentStates) { - Type t = source.GetType(); - // get the properties and set them into a new collection of NameType wrappers - var props = t.GetProperties().Select(p => new PropertyNameType(p, t)); - var feedbacks = source.Feedbacks; - if (feedbacks != null) + + if (feedbacks == null || feedbacks.Count == 0) { - Debug.LogMessage(LogEventLevel.Information, source, "\n\nAvailable feedbacks:"); - foreach (var f in feedbacks) - { - string val = ""; - string type = ""; - if (getCurrentStates) - { - if (f is BoolFeedback) - { - val = f.BoolValue.ToString(); - type = "boolean"; - } - else if (f is IntFeedback) - { - val = f.IntValue.ToString(); - type = "integer"; - } - else if (f is StringFeedback) - { - val = f.StringValue; - type = "string"; - } - } - Debug.LogMessage(LogEventLevel.Information, "{0,-12} {1, -25} {2}", type, - (string.IsNullOrEmpty(f.Key) ? "-no key-" : f.Key), val); - } + CrestronConsole.ConsoleCommandResponse("No available feedbacks\r\n"); + return; + } + + CrestronConsole.ConsoleCommandResponse("Available feedbacks:\r\n"); + + // Sort feedbacks by type first, then by key + var sortedFeedbacks = feedbacks.OrderBy(f => GetFeedbackTypeName(f)).ThenBy(f => string.IsNullOrEmpty(f.Key) ? "" : f.Key); + + foreach (var feedback in sortedFeedbacks) + { + string value = ""; + string type = ""; + if (getCurrentStates) + { + if (feedback is BoolFeedback) + { + value = feedback.BoolValue.ToString(); + type = "boolean"; + } + else if (feedback is IntFeedback) + { + value = feedback.IntValue.ToString(); + type = "integer"; + } + else if (feedback is StringFeedback) + { + value = feedback.StringValue; + type = "string"; + } + } + CrestronConsole.ConsoleCommandResponse($" {type,-12} {(string.IsNullOrEmpty(feedback.Key) ? "-no key-" : feedback.Key),-25} {value}\r\n"); } - else - Debug.LogMessage(LogEventLevel.Information, source, "No available outputs:"); } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index fec7e380..868f3992 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -103,6 +103,12 @@ namespace PepperDash.Essentials.Core [JsonProperty("name")] public string Name { get; set; } + /// + /// Gets or sets a value indicating whether to hide this scenario in the UI. + /// + [JsonProperty("hideInUi", NullValueHandling = NullValueHandling.Ignore)] + public bool HideInUi { get; set; } + /// /// Gets or sets the collection of partition states. /// diff --git a/src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs b/src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs index 50d6d84e..34d0a0a0 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/IEssentialsRoomCombiner.cs @@ -109,6 +109,12 @@ namespace PepperDash.Essentials.Core [JsonProperty("isActive")] bool IsActive { get; } + /// + /// Gets a value indicating whether this scenario should be hidden in the UI. + /// + [JsonProperty("hideInUi")] + bool HideInUi { get; } + /// /// Activates this room combination scenario /// diff --git a/src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs b/src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs index b6bd2547..aa0bdcaa 100644 --- a/src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs +++ b/src/PepperDash.Essentials.Core/Room/Combining/RoomCombinationScenario.cs @@ -14,18 +14,40 @@ namespace PepperDash.Essentials.Core { private RoomCombinationScenarioConfig _config; + /// + /// Gets or sets the key associated with the object. + /// [JsonProperty("key")] public string Key { get; set; } + /// + /// Gets or sets the name associated with the object. + /// [JsonProperty("name")] public string Name { get; set; } - [JsonProperty("partitionStates")] + /// + /// Gets a value indicating whether to hide this scenario in the UI. + /// + /// + [JsonProperty("hideInUi")] + + public bool HideInUi + { + get { return _config.HideInUi; } + } + /// /// Gets or sets the PartitionStates /// + /// + [JsonProperty("partitionStates")] + public List PartitionStates { get; private set; } + /// + /// Determines which UI devices get mapped to which room in this scenario. The Key should be the key of the UI device and the Value should be the key of the room to map to + /// [JsonProperty("uiMap")] public Dictionary UiMap { get; set; } diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs index 40810a89..b5584f93 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs @@ -9,11 +9,11 @@ using Serilog.Events; namespace PepperDash.Essentials.Room.Config { - /// - /// Represents a EssentialsRoomConfigHelper - /// - public class EssentialsRoomConfigHelper - { + /// + /// Represents a EssentialsRoomConfigHelper + /// + public class EssentialsRoomConfigHelper + { /// /// GetEmergency method /// @@ -31,100 +31,100 @@ namespace PepperDash.Essentials.Room.Config return null; } - /// - /// - /// - /// - /// - /// - /// - /// GetMicrophonePrivacy method - /// - public static MicrophonePrivacyController GetMicrophonePrivacy( - EssentialsRoomPropertiesConfig props, IPrivacy room) - { - var microphonePrivacy = props.MicrophonePrivacy; - if (microphonePrivacy == null) - { - Debug.LogMessage(LogEventLevel.Information, "Cannot create microphone privacy with null properties"); - return null; - } - // Get the MicrophonePrivacy device from the device manager - var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as MicrophonePrivacyController); - // Set this room as the IPrivacy device - if (mP == null) - { - Debug.LogMessage(LogEventLevel.Information, "ERROR: Selected device {0} is not MicrophonePrivacyController", props.MicrophonePrivacy.DeviceKey); - return null; - } - mP.SetPrivacyDevice(room); + /// + /// + /// + /// + /// + /// + /// + /// GetMicrophonePrivacy method + /// + public static MicrophonePrivacyController GetMicrophonePrivacy( + EssentialsRoomPropertiesConfig props, IPrivacy room) + { + var microphonePrivacy = props.MicrophonePrivacy; + if (microphonePrivacy == null) + { + Debug.LogMessage(LogEventLevel.Information, "Cannot create microphone privacy with null properties"); + return null; + } + // Get the MicrophonePrivacy device from the device manager + var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as MicrophonePrivacyController); + // Set this room as the IPrivacy device + if (mP == null) + { + Debug.LogMessage(LogEventLevel.Information, "ERROR: Selected device {0} is not MicrophonePrivacyController", props.MicrophonePrivacy.DeviceKey); + return null; + } + mP.SetPrivacyDevice(room); - var behaviour = props.MicrophonePrivacy.Behaviour.ToLower(); + var behaviour = props.MicrophonePrivacy.Behaviour.ToLower(); - if (behaviour == null) - { - Debug.LogMessage(LogEventLevel.Information, "WARNING: No behaviour defined for MicrophonePrivacyController"); - return null; - } - if (behaviour == "trackroomstate") - { - // Tie LED enable to room power state + if (behaviour == null) + { + Debug.LogMessage(LogEventLevel.Information, "WARNING: No behaviour defined for MicrophonePrivacyController"); + return null; + } + if (behaviour == "trackroomstate") + { + // Tie LED enable to room power state var essRoom = room as IEssentialsRoom; essRoom.OnFeedback.OutputChange += (o, a) => - { + { if (essRoom.OnFeedback.BoolValue) - mP.EnableLeds = true; - else - mP.EnableLeds = false; - }; + mP.EnableLeds = true; + else + mP.EnableLeds = false; + }; mP.EnableLeds = essRoom.OnFeedback.BoolValue; - } - else if (behaviour == "trackcallstate") - { - // Tie LED enable to room power state + } + else if (behaviour == "trackcallstate") + { + // Tie LED enable to room power state var inCallRoom = room as IHasInCallFeedback; inCallRoom.InCallFeedback.OutputChange += (o, a) => - { + { if (inCallRoom.InCallFeedback.BoolValue) - mP.EnableLeds = true; - else - mP.EnableLeds = false; - }; + mP.EnableLeds = true; + else + mP.EnableLeds = false; + }; mP.EnableLeds = inCallRoom.InCallFeedback.BoolValue; - } + } - return mP; - } - - } + return mP; + } - /// - /// Represents a EssentialsRoomPropertiesConfig - /// - public class EssentialsRoomPropertiesConfig - { - [JsonProperty("addresses")] - public EssentialsRoomAddressPropertiesConfig Addresses { get; set; } + } - [JsonProperty("description")] - public string Description { get; set; } + /// + /// Represents a EssentialsRoomPropertiesConfig + /// + public class EssentialsRoomPropertiesConfig + { + [JsonProperty("addresses")] + public EssentialsRoomAddressPropertiesConfig Addresses { get; set; } - [JsonProperty("emergency")] - public EssentialsRoomEmergencyConfig Emergency { get; set; } + [JsonProperty("description")] + public string Description { get; set; } - [JsonProperty("help")] - /// - /// Gets or sets the Help - /// - public EssentialsHelpPropertiesConfig Help { get; set; } + [JsonProperty("emergency")] + public EssentialsRoomEmergencyConfig Emergency { get; set; } - [JsonProperty("helpMessage")] - /// - /// Gets or sets the HelpMessage - /// - public string HelpMessage { get; set; } + /// + /// Gets or sets the Help + /// + [JsonProperty("help")] + public EssentialsHelpPropertiesConfig Help { get; set; } + + /// + /// Gets or sets the HelpMessage + /// + [JsonProperty("helpMessage")] + public string HelpMessage { get; set; } /// /// Read this value to get the help message. It checks for the old and new config format. @@ -133,94 +133,94 @@ namespace PepperDash.Essentials.Room.Config { get { - if(Help != null && !string.IsNullOrEmpty(Help.Message)) + if (Help != null && !string.IsNullOrEmpty(Help.Message)) { return Help.Message; } else { - return HelpMessage; + return HelpMessage; } } } - [JsonProperty("environment")] - /// - /// Gets or sets the Environment - /// - public EssentialsEnvironmentPropertiesConfig Environment { get; set; } + /// + /// Gets or sets the Environment + /// + [JsonProperty("environment")] + public EssentialsEnvironmentPropertiesConfig Environment { get; set; } - [JsonProperty("logo")] - /// - /// Gets or sets the LogoLight - /// - public EssentialsLogoPropertiesConfig LogoLight { get; set; } + /// + /// Gets or sets the LogoLight + /// + [JsonProperty("logo")] + public EssentialsLogoPropertiesConfig LogoLight { get; set; } - [JsonProperty("logoDark")] /// /// Gets or sets the LogoDark /// + [JsonProperty("logoDark")] public EssentialsLogoPropertiesConfig LogoDark { get; set; } - - [JsonProperty("microphonePrivacy")] - /// - /// Gets or sets the MicrophonePrivacy - /// - public EssentialsRoomMicrophonePrivacyConfig MicrophonePrivacy { get; set; } - [JsonProperty("occupancy")] - /// - /// Gets or sets the Occupancy - /// - public EssentialsRoomOccSensorConfig Occupancy { get; set; } + /// + /// Gets or sets the MicrophonePrivacy + /// + [JsonProperty("microphonePrivacy")] + public EssentialsRoomMicrophonePrivacyConfig MicrophonePrivacy { get; set; } - [JsonProperty("oneButtonMeeting")] - /// - /// Gets or sets the OneButtonMeeting - /// - public EssentialsOneButtonMeetingPropertiesConfig OneButtonMeeting { get; set; } + /// + /// Gets or sets the Occupancy + /// + [JsonProperty("occupancy")] + public EssentialsRoomOccSensorConfig Occupancy { get; set; } - [JsonProperty("shutdownVacancySeconds")] - /// - /// Gets or sets the ShutdownVacancySeconds - /// - public int ShutdownVacancySeconds { get; set; } + /// + /// Gets or sets the OneButtonMeeting + /// + [JsonProperty("oneButtonMeeting")] + public EssentialsOneButtonMeetingPropertiesConfig OneButtonMeeting { get; set; } - [JsonProperty("shutdownPromptSeconds")] - /// - /// Gets or sets the ShutdownPromptSeconds - /// - public int ShutdownPromptSeconds { get; set; } + /// + /// Gets or sets the ShutdownVacancySeconds + /// + [JsonProperty("shutdownVacancySeconds")] + public int ShutdownVacancySeconds { get; set; } - [JsonProperty("tech")] - /// - /// Gets or sets the Tech - /// - public EssentialsRoomTechConfig Tech { get; set; } + /// + /// Gets or sets the ShutdownPromptSeconds + /// + [JsonProperty("shutdownPromptSeconds")] + public int ShutdownPromptSeconds { get; set; } - [JsonProperty("volumes")] - /// - /// Gets or sets the Volumes - /// - public EssentialsRoomVolumesConfig Volumes { get; set; } + /// + /// Gets or sets the Tech + /// + [JsonProperty("tech")] + public EssentialsRoomTechConfig Tech { get; set; } + + /// + /// Gets or sets the Volumes + /// + [JsonProperty("volumes")] + public EssentialsRoomVolumesConfig Volumes { get; set; } - [JsonProperty("fusion")] /// /// Gets or sets the Fusion /// + [JsonProperty("fusion")] public EssentialsRoomFusionConfig Fusion { get; set; } - [JsonProperty("essentialsRoomUiBehaviorConfig", NullValueHandling=NullValueHandling.Ignore)] /// /// Gets or sets the UiBehavior /// + [JsonProperty("essentialsRoomUiBehaviorConfig", NullValueHandling = NullValueHandling.Ignore)] public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } - [JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")] - /// - /// Gets or sets the ZeroVolumeWhenSwtichingVolumeDevices - /// - public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; } + /// + /// Gets or sets the ZeroVolumeWhenSwtichingVolumeDevices + /// + [JsonProperty("zeroVolumeWhenSwtichingVolumeDevices")] + public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; } /// /// Indicates if this room represents a combination of other rooms @@ -236,7 +236,7 @@ namespace PepperDash.Essentials.Room.Config LogoLight = new EssentialsLogoPropertiesConfig(); LogoDark = new EssentialsLogoPropertiesConfig(); } - } + } /// /// Represents a EssentialsRoomUiBehaviorConfig @@ -327,15 +327,15 @@ namespace PepperDash.Essentials.Room.Config } - /// - /// Represents a EssentialsEnvironmentPropertiesConfig - /// - public class EssentialsEnvironmentPropertiesConfig - { - /// - /// Gets or sets the Enabled - /// - public bool Enabled { get; set; } + /// + /// Represents a EssentialsEnvironmentPropertiesConfig + /// + public class EssentialsEnvironmentPropertiesConfig + { + /// + /// Gets or sets the Enabled + /// + public bool Enabled { get; set; } [JsonProperty("deviceKeys")] /// @@ -348,7 +348,7 @@ namespace PepperDash.Essentials.Room.Config DeviceKeys = new List(); } - } + } /// /// Represents a EssentialsRoomFusionConfig @@ -359,7 +359,7 @@ namespace PepperDash.Essentials.Room.Config { get { - try + try { return Convert.ToUInt32(IpId, 16); } @@ -367,7 +367,7 @@ namespace PepperDash.Essentials.Room.Config { throw new FormatException(string.Format("ERROR:Unable to convert IP ID: {0} to hex. Error:\n{1}", IpId)); } - + } } @@ -390,17 +390,17 @@ namespace PepperDash.Essentials.Room.Config /// public class EssentialsRoomMicrophonePrivacyConfig { - [JsonProperty("deviceKey")] - /// - /// Gets or sets the DeviceKey - /// - public string DeviceKey { get; set; } + [JsonProperty("deviceKey")] + /// + /// Gets or sets the DeviceKey + /// + public string DeviceKey { get; set; } - [JsonProperty("behaviour")] - /// - /// Gets or sets the Behaviour - /// - public string Behaviour { get; set; } + [JsonProperty("behaviour")] + /// + /// Gets or sets the Behaviour + /// + public string Behaviour { get; set; } } /// @@ -408,23 +408,23 @@ namespace PepperDash.Essentials.Room.Config /// public class EssentialsHelpPropertiesConfig { - [JsonProperty("message")] - /// - /// Gets or sets the Message - /// - public string Message { get; set; } + [JsonProperty("message")] + /// + /// Gets or sets the Message + /// + public string Message { get; set; } - [JsonProperty("showCallButton")] - public bool ShowCallButton { get; set; } - - /// + [JsonProperty("showCallButton")] + public bool ShowCallButton { get; set; } + + /// /// Defaults to "Call Help Desk" /// - [JsonProperty("callButtonText")] - /// - /// Gets or sets the CallButtonText - /// - public string CallButtonText { get; set; } + [JsonProperty("callButtonText")] + /// + /// Gets or sets the CallButtonText + /// + public string CallButtonText { get; set; } public EssentialsHelpPropertiesConfig() { @@ -437,23 +437,23 @@ namespace PepperDash.Essentials.Room.Config /// public class EssentialsOneButtonMeetingPropertiesConfig { - [JsonProperty("enable")] - /// - /// Gets or sets the Enable - /// - public bool Enable { get; set; } + [JsonProperty("enable")] + /// + /// Gets or sets the Enable + /// + public bool Enable { get; set; } } public class EssentialsRoomAddressPropertiesConfig { - [JsonProperty("phoneNumber")] - public string PhoneNumber { get; set; } + [JsonProperty("phoneNumber")] + public string PhoneNumber { get; set; } - [JsonProperty("sipAddress")] - /// - /// Gets or sets the SipAddress - /// - public string SipAddress { get; set; } + [JsonProperty("sipAddress")] + /// + /// Gets or sets the SipAddress + /// + public string SipAddress { get; set; } } @@ -462,14 +462,14 @@ namespace PepperDash.Essentials.Room.Config /// public class EssentialsLogoPropertiesConfig { - [JsonProperty("type")] - /// - /// Gets or sets the Type - /// - public string Type { get; set; } + [JsonProperty("type")] + /// + /// Gets or sets the Type + /// + public string Type { get; set; } - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("url")] + public string Url { get; set; } /// /// GetLogoUrlLight method /// @@ -478,7 +478,7 @@ namespace PepperDash.Essentials.Room.Config if (Type == "url") return Url; if (Type == "system") - return string.Format("http://{0}:8080/logo.png", + return string.Format("http://{0}:8080/logo.png", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)); return null; } @@ -502,22 +502,22 @@ namespace PepperDash.Essentials.Room.Config /// public class EssentialsRoomOccSensorConfig { - [JsonProperty("deviceKey")] - /// - /// Gets or sets the DeviceKey - /// - public string DeviceKey { get; set; } + [JsonProperty("deviceKey")] + /// + /// Gets or sets the DeviceKey + /// + public string DeviceKey { get; set; } - [JsonProperty("timeoutMinutes")] - public int TimeoutMinutes { get; set; } + [JsonProperty("timeoutMinutes")] + public int TimeoutMinutes { get; set; } } - public class EssentialsRoomTechConfig - { - [JsonProperty("password")] - /// - /// Gets or sets the Password - /// - public string Password { get; set; } - } + public class EssentialsRoomTechConfig + { + [JsonProperty("password")] + /// + /// Gets or sets the Password + /// + public string Password { get; set; } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs index f955011a..e82c3a63 100644 --- a/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs +++ b/src/PepperDash.Essentials.Core/SmartObjects/SubpageReferencList/SubpageReferenceList.cs @@ -14,14 +14,14 @@ using Serilog.Events; namespace PepperDash.Essentials.Core { - ////***************************************************************************** - /// - /// Base class for all subpage reference list controllers - /// - //public class SubpageReferenceListController - //{ - // public SubpageReferenceList TheList { get; protected set; } - //} + ////***************************************************************************** + ///// + ///// Base class for all subpage reference list controllers + ///// + //public class SubpageReferenceListController + //{ + // public SubpageReferenceList TheList { get; protected set; } + //} //***************************************************************************** /// @@ -34,26 +34,26 @@ namespace PepperDash.Essentials.Core public ushort Count { get { return SetNumberOfItemsSig.UShortValue; } - set { SetNumberOfItemsSig.UShortValue = value; } + set { SetNumberOfItemsSig.UShortValue = value; } } public ushort MaxDefinedItems { get; private set; } - /// - /// Gets or sets the ScrollToItemSig - /// + /// + /// Gets or sets the ScrollToItemSig + /// public UShortInputSig ScrollToItemSig { get; private set; } UShortInputSig SetNumberOfItemsSig; - /// - /// Gets or sets the BoolIncrement - /// + /// + /// Gets or sets the BoolIncrement + /// public uint BoolIncrement { get; protected set; } - /// - /// Gets or sets the UShortIncrement - /// + /// + /// Gets or sets the UShortIncrement + /// public uint UShortIncrement { get; protected set; } - /// - /// Gets or sets the StringIncrement - /// + /// + /// Gets or sets the StringIncrement + /// public uint StringIncrement { get; protected set; } protected readonly SmartObject SRL; @@ -87,8 +87,8 @@ namespace PepperDash.Essentials.Core SRL.SigChange += new SmartObjectSigChangeEventHandler(SRL_SigChange); } else - Debug.LogMessage(LogEventLevel.Information, "ERROR: TriList 0x{0:X2} Cannot load smart object {1}. Verify correct SGD file is loaded", - triList.ID, smartObjectId); + Debug.LogMessage(LogEventLevel.Information, "ERROR: TriList 0x{0:X2} Cannot load smart object {1}. Verify correct SGD file is loaded", + triList.ID, smartObjectId); } /// @@ -96,17 +96,17 @@ namespace PepperDash.Essentials.Core /// DOES NOT adjust Count /// /// - /// - /// AddItem method - /// + /// + /// AddItem method + /// public void AddItem(SubpageReferenceListItem item) { Items.Add(item); } - /// - /// Clear method - /// + /// + /// Clear method + /// public void Clear() { // If a line item needs to disconnect an CueActionPair or do something to release RAM @@ -116,12 +116,12 @@ namespace PepperDash.Essentials.Core // Clean up the SRL Count = 1; - ScrollToItemSig.UShortValue = 1; + ScrollToItemSig.UShortValue = 1; } - /// - /// Refresh method - /// + /// + /// Refresh method + /// public void Refresh() { foreach (var item in Items) item.Refresh(); @@ -157,7 +157,7 @@ namespace PepperDash.Essentials.Core public UShortOutputSig GetUShortOutputSig(uint index, uint sigNum) { if (sigNum > UShortIncrement) return null; - return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetUShortOutputSigName(index, sigNum))); + return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetUShortOutputSigName(index, sigNum))); } /// @@ -172,7 +172,7 @@ namespace PepperDash.Essentials.Core public StringOutputSig GetStringOutputSig(uint index, uint sigNum) { if (sigNum > StringIncrement) return null; - return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetStringOutputSigName(index, sigNum))); + return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetStringOutputSigName(index, sigNum))); } /// @@ -263,9 +263,9 @@ namespace PepperDash.Essentials.Core /// /// /// - /// - /// SRL_SigChange method - /// + /// + /// SRL_SigChange method + /// public static void SRL_SigChange(GenericBase currentDevice, SmartObjectEventArgs args) { var uo = args.Sig.UserObject; diff --git a/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs b/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs index 65249df4..e094aebb 100644 --- a/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs +++ b/src/PepperDash.Essentials.Core/Touchpanels/ModalDialog.cs @@ -6,9 +6,9 @@ using Serilog.Events; namespace PepperDash.Essentials.Core { - /// - /// Represents a ModalDialog - /// + /// + /// Represents a ModalDialog + /// public class ModalDialog { /// @@ -19,10 +19,10 @@ namespace PepperDash.Essentials.Core /// Bool press 3992 /// public const uint Button2Join = 3992; - /// - /// 3993 - /// - public const uint CancelButtonJoin = 3993; + /// + /// 3993 + /// + public const uint CancelButtonJoin = 3993; /// ///For visibility of single button. Bool feedback 3994 /// @@ -35,19 +35,19 @@ namespace PepperDash.Essentials.Core /// Shows the timer guage if in use. Bool feedback 3996 /// public const uint TimerVisibleJoin = 3996; - /// - /// Visibility join to show "X" button 3997 - /// - public const uint CancelVisibleJoin = 3997; + /// + /// Visibility join to show "X" button 3997 + /// + public const uint CancelVisibleJoin = 3997; /// /// Shows the modal subpage. Boolean feeback join 3999 /// public const uint ModalVisibleJoin = 3999; - /// - /// The seconds value of the countdown timer. Ushort join 3991 - /// - //public const uint TimerSecondsJoin = 3991; + ///// + ///// The seconds value of the countdown timer. Ushort join 3991 + ///// + //public const uint TimerSecondsJoin = 3991; /// /// The full ushort value of the countdown timer for a gauge. Ushort join 3992 /// @@ -77,15 +77,15 @@ namespace PepperDash.Essentials.Core /// /// Returns true when modal is showing /// - public bool ModalIsVisible - { - get { return TriList.BooleanInput[ModalVisibleJoin].BoolValue; } + public bool ModalIsVisible + { + get { return TriList.BooleanInput[ModalVisibleJoin].BoolValue; } } - /// - /// - /// - public bool CanCancel { get; private set; } + /// + /// + /// + public bool CanCancel { get; private set; } BasicTriList TriList; @@ -103,10 +103,10 @@ namespace PepperDash.Essentials.Core TriList = triList; // Attach actions to buttons - triList.SetSigFalseAction(Button1Join, () => OnModalComplete(1)); + triList.SetSigFalseAction(Button1Join, () => OnModalComplete(1)); triList.SetSigFalseAction(Button2Join, () => OnModalComplete(2)); - triList.SetSigFalseAction(CancelButtonJoin, () => { if (CanCancel) CancelDialog(); }); - CanCancel = true; + triList.SetSigFalseAction(CancelButtonJoin, () => { if (CanCancel) CancelDialog(); }); + CanCancel = true; } /// @@ -117,7 +117,7 @@ namespace PepperDash.Essentials.Core /// If the progress bar gauge needs to count down instead of up /// The action to run when the dialog is dismissed. Parameter will be 1 or 2 if button pressed, or 0 if dialog times out /// True when modal is created. - public bool PresentModalDialog(uint numberOfButtons, string title, string iconName, + public bool PresentModalDialog(uint numberOfButtons, string title, string iconName, string message, string button1Text, string button2Text, bool showGauge, bool showCancel, Action completeAction) { @@ -151,15 +151,15 @@ namespace PepperDash.Essentials.Core TriList.StringInput[Button2TextJoin].StringValue = button2Text; } // Show/hide guage - TriList.BooleanInput[TimerVisibleJoin].BoolValue = showGauge; - - CanCancel = showCancel; - TriList.BooleanInput[CancelVisibleJoin].BoolValue = showCancel; + TriList.BooleanInput[TimerVisibleJoin].BoolValue = showGauge; + + CanCancel = showCancel; + TriList.BooleanInput[CancelVisibleJoin].BoolValue = showCancel; //Reveal and activate TriList.BooleanInput[ModalVisibleJoin].BoolValue = true; - WakePanel(); + WakePanel(); return true; } @@ -167,48 +167,48 @@ namespace PepperDash.Essentials.Core return false; } - /// - /// WakePanel method - /// - public void WakePanel() - { - try - { - var panel = TriList as TswFt5Button; - - if (panel != null && panel.ExtenderSystemReservedSigs.BacklightOffFeedback.BoolValue) - panel.ExtenderSystemReservedSigs.BacklightOn(); - } - catch - { - Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?"); - } - } - - /// - /// CancelDialog method - /// - public void CancelDialog() + /// + /// WakePanel method + /// + public void WakePanel() { - OnModalComplete(0); + try + { + var panel = TriList as TswFt5Button; + + if (panel != null && panel.ExtenderSystemReservedSigs.BacklightOffFeedback.BoolValue) + panel.ExtenderSystemReservedSigs.BacklightOn(); + } + catch + { + Debug.LogMessage(LogEventLevel.Debug, "Error Waking Panel. Maybe testing with Xpanel?"); + } } - /// - /// Hides dialog. Fires no action - /// - public void HideDialog() - { - TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; - } + /// + /// CancelDialog method + /// + public void CancelDialog() + { + OnModalComplete(0); + } + + /// + /// Hides dialog. Fires no action + /// + public void HideDialog() + { + TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; + } // When the modal is cleared or times out, clean up the various bits void OnModalComplete(uint buttonNum) { TriList.BooleanInput[ModalVisibleJoin].BoolValue = false; - var action = ModalCompleteAction; - if (action != null) - action(buttonNum); + var action = ModalCompleteAction; + if (action != null) + action(buttonNum); } } diff --git a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs index 23f46007..c0f8ac1e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs +++ b/src/PepperDash.Essentials.Devices.Common/Audio/GenericAudioOut.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; +using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; @@ -17,48 +13,68 @@ namespace PepperDash.Essentials.Devices.Common /// public class GenericAudioOut : EssentialsDevice, IRoutingSink { - public RoutingInputPort CurrentInputPort => AnyAudioIn; + /// + /// Gets the current input port + /// + public RoutingInputPort CurrentInputPort => AnyAudioIn; - public event SourceInfoChangeHandler CurrentSourceChange; + /// + /// Event fired when the current source changes + /// + public event SourceInfoChangeHandler CurrentSourceChange; - public string CurrentSourceInfoKey { get; set; } - public SourceListItem CurrentSourceInfo - { - get - { - return _CurrentSourceInfo; - } - set - { - if (value == _CurrentSourceInfo) return; + /// + /// Gets or sets the current source info key + /// + public string CurrentSourceInfoKey { get; set; } + /// + /// Gets or sets the current source info + /// + public SourceListItem CurrentSourceInfo + { + get + { + return _CurrentSourceInfo; + } + set + { + if (value == _CurrentSourceInfo) return; - var handler = CurrentSourceChange; + var handler = CurrentSourceChange; - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.WillChange); + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.WillChange); - _CurrentSourceInfo = value; + _CurrentSourceInfo = value; - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.DidChange); - } - } - SourceListItem _CurrentSourceInfo; + if (handler != null) + handler(_CurrentSourceInfo, ChangeType.DidChange); + } + } + SourceListItem _CurrentSourceInfo; - /// - /// Gets or sets the AnyAudioIn - /// + /// + /// Gets or sets the AnyAudioIn + /// public RoutingInputPort AnyAudioIn { get; private set; } + /// + /// Constructor for GenericAudioOut + /// + /// Device key + /// Device name public GenericAudioOut(string key, string name) : base(key, name) { - AnyAudioIn = new RoutingInputPort(RoutingPortNames.AnyAudioIn, eRoutingSignalType.Audio, + AnyAudioIn = new RoutingInputPort(RoutingPortNames.AnyAudioIn, eRoutingSignalType.Audio, eRoutingPortConnectionType.LineAudio, null, this); } #region IRoutingInputs Members + /// + /// Gets the collection of input ports + /// public RoutingPortCollection InputPorts { get { return new RoutingPortCollection { AnyAudioIn }; } @@ -68,23 +84,32 @@ namespace PepperDash.Essentials.Devices.Common } - /// - /// Represents a GenericAudioOutWithVolume - /// + /// + /// Represents a GenericAudioOutWithVolume + /// public class GenericAudioOutWithVolume : GenericAudioOut, IHasVolumeDevice { + /// + /// Gets the volume device key + /// public string VolumeDeviceKey { get; private set; } + /// + /// Gets the volume zone + /// public uint VolumeZone { get; private set; } + /// + /// Gets the volume device + /// public IBasicVolumeControls VolumeDevice - { + { get { var dev = DeviceManager.GetDeviceForKey(VolumeDeviceKey); if (dev is IAudioZones) return (dev as IAudioZones).Zone[VolumeZone]; else return dev as IBasicVolumeControls; - } + } } /// @@ -103,24 +128,30 @@ namespace PepperDash.Essentials.Devices.Common } - public class GenericAudioOutWithVolumeFactory : EssentialsDeviceFactory - { - public GenericAudioOutWithVolumeFactory() - { - TypeNames = new List() { "genericaudiooutwithvolume" }; - } + /// + /// Factory for creating GenericAudioOutWithVolume devices + /// + public class GenericAudioOutWithVolumeFactory : EssentialsDeviceFactory + { + /// + /// Constructor for GenericAudioOutWithVolumeFactory + /// + public GenericAudioOutWithVolumeFactory() + { + TypeNames = new List() { "genericaudiooutwithvolume" }; + } - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new GenericAudioOutWithVolumeFactory Device"); - var zone = dc.Properties.Value("zone"); - return new GenericAudioOutWithVolume(dc.Key, dc.Name, - dc.Properties.Value("volumeDeviceKey"), zone); - } - } + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new GenericAudioOutWithVolumeFactory Device"); + var zone = dc.Properties.Value("zone"); + return new GenericAudioOutWithVolume(dc.Key, dc.Name, + dc.Properties.Value("volumeDeviceKey"), zone); + } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs index c0eff735..7f760bc3 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/AudioCodecBase.cs @@ -1,18 +1,20 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.Devices.Common.AudioCodec { + /// + /// Abstract base class for audio codec devices + /// public abstract class AudioCodecBase : EssentialsDevice, IHasDialer, IUsageTracking, IAudioCodecInfo { + /// + /// Event fired when call status changes + /// public event EventHandler CallStatusChange; /// @@ -52,6 +54,11 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec /// public List ActiveCalls { get; set; } + /// + /// Constructor for AudioCodecBase + /// + /// Device key + /// Device name public AudioCodecBase(string key, string name) : base(key, name) { @@ -70,11 +77,9 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec } /// - /// + /// Handles call status change events /// - /// - /// - /// + /// The call item that changed status protected void OnCallStatusChange(CodecActiveCallItem item) { var handler = CallStatusChange; @@ -92,16 +97,22 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec #region IHasDialer Members + /// public abstract void Dial(string number); + /// public abstract void EndCall(CodecActiveCallItem activeCall); + /// public abstract void EndAllCalls(); + /// public abstract void AcceptCall(CodecActiveCallItem item); + /// public abstract void RejectCall(CodecActiveCallItem item); + /// public abstract void SendDtmf(string digit); #endregion diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs index e853c898..3e6b0418 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IAudioCodecInfo.cs @@ -1,16 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace PepperDash.Essentials.Devices.Common.AudioCodec +namespace PepperDash.Essentials.Devices.Common.AudioCodec { /// /// Implements a common set of data about a codec /// public interface IAudioCodecInfo { + /// + /// Gets the codec information + /// AudioCodecInfo CodecInfo { get; } } @@ -19,6 +16,9 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec /// public abstract class AudioCodecInfo { + /// + /// Gets or sets the phone number + /// public abstract string PhoneNumber { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs index a1a2d64d..946c2053 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/Interfaces/IHasAudioCodec.cs @@ -1,23 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.AudioCodec { /// /// For rooms that have audio codec /// - public interface IHasAudioCodec:IHasInCallFeedback + public interface IHasAudioCodec : IHasInCallFeedback { + /// + /// Gets the audio codec device + /// AudioCodecBase AudioCodec { get; } - /// - /// Make this more specific - /// //List ActiveCalls { get; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs index 85c21474..48235a45 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAC.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; +using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; @@ -17,6 +13,12 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec /// public class MockAC : AudioCodecBase { + /// + /// Constructor for MockAC + /// + /// Device key + /// Device name + /// MockAC properties configuration public MockAC(string key, string name, MockAcPropertiesConfig props) : base(key, name) { @@ -109,13 +111,10 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec Debug.LogMessage(LogEventLevel.Debug, this, "BEEP BOOP SendDTMF: {0}", s); } - /// - /// - /// - /// /// /// TestIncomingAudioCall method /// + /// Phone number to call from public void TestIncomingAudioCall(string number) { Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingAudioCall from {0}", number); @@ -133,6 +132,7 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec { string _phoneNumber; + /// public override string PhoneNumber { get @@ -151,6 +151,9 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec /// public class MockACFactory : EssentialsDeviceFactory { + /// + /// Constructor for MockACFactory + /// public MockACFactory() { TypeNames = new List() { "mockac" }; diff --git a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs index 5ac31dcc..0deaca97 100644 --- a/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/AudioCodec/MockAC/MockAcPropertiesConfig.cs @@ -1,12 +1,4 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using Newtonsoft.Json; +using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.AudioCodec { @@ -15,10 +7,10 @@ namespace PepperDash.Essentials.Devices.Common.AudioCodec /// public class MockAcPropertiesConfig { - [JsonProperty("phoneNumber")] /// /// Gets or sets the PhoneNumber /// + [JsonProperty("phoneNumber")] public string PhoneNumber { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs index 0fb6f6ca..e2e15668 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraBase.cs @@ -3,20 +3,14 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Crestron.SimplSharp; -using System.Reflection; using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Devices; -using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.Presets; -using PepperDash.Essentials.Devices.Common.Codec; - -using Newtonsoft.Json; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Cameras @@ -26,31 +20,52 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public enum eCameraCapabilities { + /// + /// No camera capabilities + /// None = 0, + /// + /// Camera supports pan movement + /// Pan = 1, - Tilt = 2, + /// + /// Camera supports tilt movement + /// + Tilt = 2, + /// + /// Camera supports zoom functionality + /// Zoom = 4, + /// + /// Camera supports focus adjustment + /// Focus = 8 } + /// + /// Abstract base class for camera devices that provides common camera functionality and capabilities + /// public abstract class CameraBase : ReconfigurableDevice, IRoutingOutputs - { - [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] + { /// /// Gets or sets the ControlMode /// + [JsonProperty("controlMode", NullValueHandling = NullValueHandling.Ignore)] public eCameraControlMode ControlMode { get; protected set; } #region IRoutingOutputs Members - [JsonIgnore] /// /// Gets or sets the OutputPorts /// + [JsonIgnore] public RoutingPortCollection OutputPorts { get; protected set; } #endregion + /// + /// Gets a value indicating whether this camera supports pan movement + /// [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] public bool CanPan { @@ -59,6 +74,10 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Pan) == eCameraCapabilities.Pan; } } + + /// + /// Gets a value indicating whether this camera supports tilt movement + /// [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] public bool CanTilt { @@ -67,6 +86,10 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Tilt) == eCameraCapabilities.Tilt; } } + + /// + /// Gets a value indicating whether this camera supports zoom functionality + /// [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] public bool CanZoom { @@ -75,6 +98,10 @@ namespace PepperDash.Essentials.Devices.Common.Cameras return (Capabilities & eCameraCapabilities.Zoom) == eCameraCapabilities.Zoom; } } + + /// + /// Gets a value indicating whether this camera supports focus adjustment + /// [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] public bool CanFocus { @@ -84,23 +111,42 @@ namespace PepperDash.Essentials.Devices.Common.Cameras } } - // A bitmasked value to indicate the movement capabilites of this camera + /// + /// Gets or sets a bitmasked value to indicate the movement capabilities of this camera + /// protected eCameraCapabilities Capabilities { get; set; } - protected CameraBase(DeviceConfig config) : base(config) - { - OutputPorts = new RoutingPortCollection(); - - ControlMode = eCameraControlMode.Manual; - - } - - protected CameraBase(string key, string name) : - this (new DeviceConfig{Name = name, Key = key}) + /// + /// Initializes a new instance of the CameraBase class with the specified device configuration + /// + /// The device configuration + protected CameraBase(DeviceConfig config) : base(config) { - + OutputPorts = new RoutingPortCollection(); + + ControlMode = eCameraControlMode.Manual; + } + /// + /// Initializes a new instance of the CameraBase class with the specified key and name + /// + /// The unique key for this camera device + /// The friendly name for this camera device + protected CameraBase(string key, string name) : + this(new DeviceConfig { Name = name, Key = key }) + { + + } + + /// + /// Links the camera device to the API bridge for control and feedback + /// + /// The camera device to link + /// The trilist for communication + /// The starting join number for the camera controls + /// The join map key for custom join mappings + /// The EiscApiAdvanced bridge for advanced join mapping protected void LinkCameraToApi(CameraBase cameraDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { @@ -240,13 +286,13 @@ namespace PepperDash.Essentials.Devices.Common.Cameras { int tempNum = i; - trilist.SetSigTrueAction((ushort) (joinMap.PresetRecallStart.JoinNumber + tempNum), () => + trilist.SetSigTrueAction((ushort)(joinMap.PresetRecallStart.JoinNumber + tempNum), () => { presetsCamera.PresetSelect(tempNum); }); - trilist.SetSigTrueAction((ushort) (joinMap.PresetSaveStart.JoinNumber + tempNum), () => + trilist.SetSigTrueAction((ushort)(joinMap.PresetSaveStart.JoinNumber + tempNum), () => { - var label = trilist.GetString((ushort) (joinMap.PresetLabelStart.JoinNumber + tempNum)); + var label = trilist.GetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum)); presetsCamera.PresetStore(tempNum, label); }); @@ -277,7 +323,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras trilist.SetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum), label); } } - } + } /// @@ -285,6 +331,13 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public class CameraPreset : PresetBase { + /// + /// Initializes a new instance of the CameraPreset class + /// + /// The preset ID + /// The preset description + /// Whether the preset is defined + /// Whether the preset can be defined public CameraPreset(int id, string description, bool isDefined, bool isDefinable) : base(id, description, isDefined, isDefinable) { @@ -293,37 +346,37 @@ namespace PepperDash.Essentials.Devices.Common.Cameras } - /// - /// Represents a CameraPropertiesConfig - /// - public class CameraPropertiesConfig - { - /// - /// Gets or sets the CommunicationMonitorProperties - /// - public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } + /// + /// Represents a CameraPropertiesConfig + /// + public class CameraPropertiesConfig + { + /// + /// Gets or sets the CommunicationMonitorProperties + /// + public CommunicationMonitorConfig CommunicationMonitorProperties { get; set; } - /// - /// Gets or sets the Control - /// - public ControlPropertiesConfig Control { get; set; } + /// + /// Gets or sets the Control + /// + public ControlPropertiesConfig Control { get; set; } - [JsonProperty("supportsAutoMode")] /// /// Gets or sets the SupportsAutoMode /// + [JsonProperty("supportsAutoMode")] public bool SupportsAutoMode { get; set; } - [JsonProperty("supportsOffMode")] /// /// Gets or sets the SupportsOffMode /// + [JsonProperty("supportsOffMode")] public bool SupportsOffMode { get; set; } - [JsonProperty("presets")] /// /// Gets or sets the Presets /// + [JsonProperty("presets")] public List Presets { get; set; } - } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs deleted file mode 100644 index cec2f58b..00000000 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraControl.cs +++ /dev/null @@ -1,326 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using PepperDash.Core; -using PepperDash.Essentials.Core; - -namespace PepperDash.Essentials.Devices.Common.Cameras -{ - /// - /// Enum for camera control modes - /// - public enum eCameraControlMode - { - /// - /// Manual control mode, where the camera is controlled directly by the user or system - /// - Manual = 0, - /// - /// Off control mode, where the camera is turned off or disabled - /// - Off, - /// - /// Auto control mode, where the camera automatically adjusts settings based on the environment or conditions - /// - Auto - } - - - /// - /// Interface for devices that have cameras - /// - public interface IHasCameras : IKeyName - { - /// - /// Event that is raised when a camera is selected - /// - event EventHandler CameraSelected; - - /// - /// List of cameras on the device. This should be a list of CameraBase objects - /// - List Cameras { get; } - - /// - /// The currently selected camera. This should be a CameraBase object - /// - CameraBase SelectedCamera { get; } - - /// - /// Feedback that indicates the currently selected camera - /// - StringFeedback SelectedCameraFeedback { get; } - - /// - /// Selects a camera from the list of available cameras based on the provided key. - /// - /// The unique identifier or name of the camera to select. - void SelectCamera(string key); - } - - /// - /// Defines the contract for IHasCodecCameras - /// - public interface IHasCodecCameras : IHasCameras, IHasFarEndCameraControl - { - - } - - /// - /// To be implmented on codecs that can disable their camera(s) to blank the near end video - /// - public interface IHasCameraOff - { - /// - /// Feedback that indicates whether the camera is off - /// - BoolFeedback CameraIsOffFeedback { get; } - - /// - /// Turns the camera off, blanking the near end video - /// - void CameraOff(); - } - - /// - /// Describes the ability to mute and unmute camera video - /// - public interface IHasCameraMute - { - /// - /// Feedback that indicates whether the camera is muted - /// - BoolFeedback CameraIsMutedFeedback { get; } - - /// - /// Mutes the camera video, preventing it from being sent to the far end - /// - void CameraMuteOn(); - - /// - /// Unmutes the camera video, allowing it to be sent to the far end - /// - void CameraMuteOff(); - - /// - /// Toggles the camera mute state. If the camera is muted, it will be unmuted, and vice versa. - /// - void CameraMuteToggle(); - } - - /// - /// Interface for devices that can mute and unmute their camera video, with an event for unmute requests - /// - public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute - { - /// - /// Event that is raised when a video unmute is requested, typically by the far end - /// - event EventHandler VideoUnmuteRequested; - } - - /// - /// Event arguments for the CameraSelected event - /// - public class CameraSelectedEventArgs : EventArgs - { - /// - /// Gets or sets the SelectedCamera - /// - public CameraBase SelectedCamera { get; private set; } - - /// - /// Constructor for CameraSelectedEventArgs - /// - /// - public CameraSelectedEventArgs(CameraBase camera) - { - SelectedCamera = camera; - } - } - - /// - /// Interface for devices that have a far end camera control - /// - public interface IHasFarEndCameraControl - { - /// - /// Gets the far end camera, which is typically a CameraBase object that represents the camera at the far end of a call - /// - CameraBase FarEndCamera { get; } - - /// - /// Feedback that indicates whether the far end camera is being controlled - /// - BoolFeedback ControllingFarEndCameraFeedback { get; } - - } - - /// - /// Defines the contract for IAmFarEndCamera - /// - public interface IAmFarEndCamera - { - - } - - /// - /// Interface for devices that have camera controls - /// - public interface IHasCameraControls - { - } - - /// - /// Defines the contract for IHasCameraPtzControl - /// - public interface IHasCameraPtzControl : IHasCameraPanControl, IHasCameraTiltControl, IHasCameraZoomControl - { - /// - /// Resets the camera position - /// - void PositionHome(); - } - - /// - /// Interface for camera pan control - /// - public interface IHasCameraPanControl : IHasCameraControls - { - /// - /// Pans the camera left - /// - void PanLeft(); - - /// - /// Pans the camera right - /// - void PanRight(); - - /// - /// Stops the camera pan movement - /// - void PanStop(); - } - - /// - /// Defines the contract for IHasCameraTiltControl - /// - public interface IHasCameraTiltControl : IHasCameraControls - { - /// - /// Tilts the camera down - /// - void TiltDown(); - - /// - /// Tilts the camera up - /// - void TiltUp(); - - /// - /// Stops the camera tilt movement - /// - void TiltStop(); - } - - /// - /// Defines the contract for IHasCameraZoomControl - /// - public interface IHasCameraZoomControl : IHasCameraControls - { - /// - /// Zooms the camera in - /// - void ZoomIn(); - - /// - /// Zooms the camera out - /// - void ZoomOut(); - - /// - /// Stops the camera zoom movement - /// - void ZoomStop(); - } - - /// - /// Defines the contract for IHasCameraFocusControl - /// - public interface IHasCameraFocusControl : IHasCameraControls - { - /// - /// Focuses the camera near - /// - void FocusNear(); - - /// - /// Focuses the camera far - /// - void FocusFar(); - - /// - /// Stops the camera focus movement - /// - void FocusStop(); - - /// - /// Triggers the camera's auto focus functionality, if available. - /// - void TriggerAutoFocus(); - } - - /// - /// Interface for devices that have auto focus mode control - /// - public interface IHasAutoFocusMode - { - /// - /// Sets the focus mode to auto or manual, or toggles between them. - /// - void SetFocusModeAuto(); - - /// - /// Sets the focus mode to manual, allowing for manual focus adjustments. - /// - void SetFocusModeManual(); - - /// - /// Toggles the focus mode between auto and manual. - /// - void ToggleFocusMode(); - } - - /// - /// Interface for devices that have camera auto mode control - /// - public interface IHasCameraAutoMode : IHasCameraControls - { - /// - /// Enables or disables the camera's auto mode, which may include automatic adjustments for focus, exposure, and other settings. - /// - void CameraAutoModeOn(); - - /// - /// Disables the camera's auto mode, allowing for manual control of camera settings. - /// - void CameraAutoModeOff(); - - /// - /// Toggles the camera's auto mode state. If the camera is in auto mode, it will switch to manual mode, and vice versa. - /// - void CameraAutoModeToggle(); - - /// - /// Feedback that indicates whether the camera's auto mode is currently enabled. - /// - BoolFeedback CameraAutoModeIsOnFeedback { get; } - } - - - - -} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs index 9a8bce8b..126bcd27 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/CameraVisca.cs @@ -3,38 +3,33 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Devices.Common.Codec; -using System.Text.RegularExpressions; -using System.Reflection; - -using Newtonsoft.Json; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Cameras { - /// - /// Represents a CameraVisca - /// - public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IHasPowerControlWithFeedback, IBridgeAdvanced, IHasCameraFocusControl, IHasAutoFocusMode - { + /// + /// Represents a CameraVisca + /// + public class CameraVisca : CameraBase, IHasCameraPtzControl, ICommunicationMonitor, IHasCameraPresets, IHasPowerControlWithFeedback, IBridgeAdvanced, IHasCameraFocusControl, IHasAutoFocusMode + { private readonly CameraViscaPropertiesConfig PropertiesConfig; - /// - /// Gets or sets the Communication - /// - public IBasicCommunication Communication { get; private set; } + /// + /// Gets or sets the Communication + /// + public IBasicCommunication Communication { get; private set; } - /// - /// Gets or sets the CommunicationMonitor - /// - public StatusMonitorBase CommunicationMonitor { get; private set; } + /// + /// Gets or sets the CommunicationMonitor + /// + public StatusMonitorBase CommunicationMonitor { get; private set; } /// /// Used to store the actions to parse inquiry responses as the inquiries are sent @@ -45,20 +40,41 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// Camera ID (Default 1) /// public byte ID = 0x01; + + /// + /// Response ID used for VISCA communication + /// public byte ResponseID; + /// + /// Slow speed value for pan movement + /// + public byte PanSpeedSlow = 0x10; - public byte PanSpeedSlow = 0x10; - public byte TiltSpeedSlow = 0x10; + /// + /// Slow speed value for tilt movement + /// + public byte TiltSpeedSlow = 0x10; + /// + /// Fast speed value for pan movement + /// public byte PanSpeedFast = 0x13; + + /// + /// Fast speed value for tilt movement + /// public byte TiltSpeedFast = 0x13; // private bool IsMoving; - private bool IsZooming; + private bool IsZooming; bool _powerIsOn; - public bool PowerIsOn + + /// + /// Gets or sets a value indicating whether the camera power is on + /// + public bool PowerIsOn { get { @@ -87,12 +103,23 @@ namespace PepperDash.Essentials.Devices.Common.Cameras long FastSpeedHoldTimeMs = 2000; - byte[] IncomingBuffer = new byte[] { }; - public BoolFeedback PowerIsOnFeedback { get; private set; } + byte[] IncomingBuffer = new byte[] { }; + /// + /// Feedback indicating whether the camera power is on + /// + public BoolFeedback PowerIsOnFeedback { get; private set; } + + /// + /// Initializes a new instance of the CameraVisca class + /// + /// The unique key for this camera device + /// The friendly name for this camera device + /// The communication interface for VISCA protocol + /// The camera properties configuration public CameraVisca(string key, string name, IBasicCommunication comm, CameraViscaPropertiesConfig props) : - base(key, name) - { + base(key, name) + { InquiryResponseQueue = new CrestronQueue>(15); Presets = props.Presets; @@ -107,8 +134,8 @@ namespace PepperDash.Essentials.Devices.Common.Cameras OutputPorts.Add(new RoutingOutputPort("videoOut", eRoutingSignalType.Video, eRoutingPortConnectionType.None, null, this, true)); // Default to all capabilties - Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; - + Capabilities = eCameraCapabilities.Pan | eCameraCapabilities.Tilt | eCameraCapabilities.Zoom | eCameraCapabilities.Focus; + Communication = comm; if (comm is ISocketStatus socket) { @@ -121,19 +148,19 @@ namespace PepperDash.Essentials.Devices.Common.Cameras } Communication.BytesReceived += new EventHandler(Communication_BytesReceived); - PowerIsOnFeedback = new BoolFeedback(() => { return PowerIsOn; }); - CameraIsOffFeedback = new BoolFeedback(() => { return !PowerIsOn; }); + PowerIsOnFeedback = new BoolFeedback("powerIsOn", () => { return PowerIsOn; }); + CameraIsOffFeedback = new BoolFeedback("cameraIsOff", () => { return !PowerIsOn; }); - if (props.CommunicationMonitorProperties != null) - { - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties); - } - else - { - CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 20000, 120000, 300000, "\x81\x09\x04\x00\xFF"); - } - DeviceManager.AddDevice(CommunicationMonitor); - } + if (props.CommunicationMonitorProperties != null) + { + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, props.CommunicationMonitorProperties); + } + else + { + CommunicationMonitor = new GenericCommunicationMonitor(this, Communication, 20000, 120000, 300000, "\x81\x09\x04\x00\xFF"); + } + DeviceManager.AddDevice(CommunicationMonitor); + } /// @@ -165,57 +192,57 @@ namespace PepperDash.Essentials.Devices.Common.Cameras } } - /// - /// CustomActivate method - /// - /// - public override bool CustomActivate() - { - Communication.Connect(); - - - CommunicationMonitor.StatusChange += (o, a) => { Debug.LogMessage(LogEventLevel.Verbose, this, "Communication monitor state: {0}", CommunicationMonitor.Status); }; - CommunicationMonitor.Start(); + /// + /// CustomActivate method + /// + /// + public override bool CustomActivate() + { + Communication.Connect(); - CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator); - return true; - } + CommunicationMonitor.StatusChange += (o, a) => { Debug.LogMessage(LogEventLevel.Verbose, this, "Communication monitor state: {0}", CommunicationMonitor.Status); }; + CommunicationMonitor.Start(); - /// - /// LinkToApi method - /// - public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); - } - void Socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString()); + CrestronConsole.AddNewConsoleCommand(s => Communication.Connect(), "con" + Key, "", ConsoleAccessLevelEnum.AccessOperator); + return true; + } - if (e.Client.IsConnected) - { - - } - else - { + /// + /// LinkToApi method + /// + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); + } - } - } - + void Socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Socket Status Change: {0}", e.Client.ClientStatus.ToString()); - void SendBytes(byte[] b) - { - - if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1 - Debug.LogMessage(LogEventLevel.Verbose, this, "Sending:{0}", ComTextHelper.GetEscapedText(b)); + if (e.Client.IsConnected) + { - Communication.SendBytes(b); - } + } + else + { - void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) - { + } + } + + + void SendBytes(byte[] b) + { + + if (Debug.Level == 2) // This check is here to prevent following string format from building unnecessarily on level 0 or 1 + Debug.LogMessage(LogEventLevel.Verbose, this, "Sending:{0}", ComTextHelper.GetEscapedText(b)); + + Communication.SendBytes(b); + } + + void Communication_BytesReceived(object sender, GenericCommMethodReceiveBytesArgs e) + { var newBytes = new byte[IncomingBuffer.Length + e.Bytes.Length]; try @@ -355,10 +382,10 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// /// Sends a pan/tilt command. If the command is not for fastSpeed then it starts a timer to initiate fast speed. /// - /// - /// - private void SendPanTiltCommand (byte[] cmd, bool fastSpeedEnabled) - { + /// The VISCA command to send + /// Whether fast speed is enabled for this command + private void SendPanTiltCommand(byte[] cmd, bool fastSpeedEnabled) + { SendBytes(GetPanTiltCommand(cmd, fastSpeedEnabled)); if (!fastSpeedEnabled) @@ -372,7 +399,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras SpeedTimer = new CTimer((o) => SendPanTiltCommand(GetPanTiltCommand(cmd, true), true), FastSpeedHoldTimeMs); } - } + } private void StopSpeedTimer() { @@ -381,7 +408,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras SpeedTimer.Stop(); SpeedTimer.Dispose(); SpeedTimer = null; - } + } } /// @@ -424,14 +451,14 @@ namespace PepperDash.Essentials.Devices.Common.Cameras InquiryResponseQueue.Enqueue(HandlePowerResponse); } - /// - /// PowerOn method - /// - public void PowerOn() - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x02, 0xFF }); + /// + /// PowerOn method + /// + public void PowerOn() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x02, 0xFF }); SendPowerQuery(); - } + } void HandlePowerResponse(byte[] response) { @@ -450,12 +477,12 @@ namespace PepperDash.Essentials.Devices.Common.Cameras } } - /// - /// PowerOff method - /// - public void PowerOff() - { - SendBytes(new byte[] {ID, 0x01, 0x04, 0x00, 0x03, 0xFF}); + /// + /// PowerOff method + /// + public void PowerOff() + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x00, 0x03, 0xFF }); SendPowerQuery(); } @@ -470,22 +497,22 @@ namespace PepperDash.Essentials.Devices.Common.Cameras PowerOn(); } - /// - /// PanLeft method - /// - public void PanLeft() - { - SendPanTiltCommand(new byte[] {0x01, 0x03}, false); - // IsMoving = true; - } - /// - /// PanRight method - /// - public void PanRight() - { + /// + /// PanLeft method + /// + public void PanLeft() + { + SendPanTiltCommand(new byte[] { 0x01, 0x03 }, false); + // IsMoving = true; + } + /// + /// PanRight method + /// + public void PanRight() + { SendPanTiltCommand(new byte[] { 0x02, 0x03 }, false); - // IsMoving = true; - } + // IsMoving = true; + } /// /// PanStop method /// @@ -493,22 +520,22 @@ namespace PepperDash.Essentials.Devices.Common.Cameras { Stop(); } - /// - /// TiltDown method - /// - public void TiltDown() - { + /// + /// TiltDown method + /// + public void TiltDown() + { SendPanTiltCommand(new byte[] { 0x03, 0x02 }, false); - // IsMoving = true; - } - /// - /// TiltUp method - /// - public void TiltUp() - { + // IsMoving = true; + } + /// + /// TiltUp method + /// + public void TiltUp() + { SendPanTiltCommand(new byte[] { 0x03, 0x01 }, false); - // IsMoving = true; - } + // IsMoving = true; + } /// /// TiltStop method /// @@ -517,28 +544,28 @@ namespace PepperDash.Essentials.Devices.Common.Cameras Stop(); } - private void SendZoomCommand (byte cmd) - { - SendBytes(new byte[] {ID, 0x01, 0x04, 0x07, cmd, 0xFF} ); - } + private void SendZoomCommand(byte cmd) + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x07, cmd, 0xFF }); + } - /// - /// ZoomIn method - /// - public void ZoomIn() - { + /// + /// ZoomIn method + /// + public void ZoomIn() + { SendZoomCommand(ZoomInCmd); - IsZooming = true; - } - /// - /// ZoomOut method - /// - public void ZoomOut() - { + IsZooming = true; + } + /// + /// ZoomOut method + /// + public void ZoomOut() + { SendZoomCommand(ZoomOutCmd); - IsZooming = true; - } + IsZooming = true; + } /// /// ZoomStop method /// @@ -547,23 +574,23 @@ namespace PepperDash.Essentials.Devices.Common.Cameras Stop(); } - /// - /// Stop method - /// - public void Stop() - { - if (IsZooming) - { + /// + /// Stop method + /// + public void Stop() + { + if (IsZooming) + { SendZoomCommand(ZoomStopCmd); - IsZooming = false; - } - else - { + IsZooming = false; + } + else + { StopSpeedTimer(); SendPanTiltCommand(new byte[] { 0x03, 0x03 }, false); - // IsMoving = false; - } - } + // IsMoving = false; + } + } /// /// PositionHome method /// @@ -572,33 +599,39 @@ namespace PepperDash.Essentials.Devices.Common.Cameras SendBytes(new byte[] { ID, 0x01, 0x06, 0x02, PanSpeedFast, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF }); SendBytes(new byte[] { ID, 0x01, 0x04, 0x47, 0x00, 0x00, 0x00, 0x00, 0xFF }); } - /// - /// RecallPreset method - /// - public void RecallPreset(int presetNumber) - { - SendBytes(new byte[] {ID, 0x01, 0x04, 0x3F, 0x02, (byte)presetNumber, 0xFF} ); - } - /// - /// SavePreset method - /// - public void SavePreset(int presetNumber) - { - SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF }); - } + /// + /// RecallPreset method + /// + public void RecallPreset(int presetNumber) + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x02, (byte)presetNumber, 0xFF }); + } + /// + /// SavePreset method + /// + public void SavePreset(int presetNumber) + { + SendBytes(new byte[] { ID, 0x01, 0x04, 0x3F, 0x01, (byte)presetNumber, 0xFF }); + } #region IHasCameraPresets Members + /// + /// Event that is raised when the presets list has changed + /// public event EventHandler PresetsListHasChanged; - protected void OnPresetsListHasChanged() - { - var handler = PresetsListHasChanged; - if (handler == null) - return; + /// + /// Raises the PresetsListHasChanged event + /// + protected void OnPresetsListHasChanged() + { + var handler = PresetsListHasChanged; + if (handler == null) + return; - handler.Invoke(this, EventArgs.Empty); - } + handler.Invoke(this, EventArgs.Empty); + } /// /// Gets or sets the Presets @@ -741,6 +774,9 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public class CameraViscaFactory : EssentialsDeviceFactory { + /// + /// Initializes a new instance of the CameraViscaFactory class + /// public CameraViscaFactory() { TypeNames = new List() { "cameravisca" }; @@ -768,11 +804,9 @@ namespace PepperDash.Essentials.Devices.Common.Cameras { /// /// Control ID of the camera (1-7) - /// - [JsonProperty("id")] - /// /// Gets or sets the Id /// + [JsonProperty("id")] public uint Id { get; set; } /// @@ -790,7 +824,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// /// Slow tilt speed (0-18) /// - [JsonProperty("tiltSpeedSlow")] + [JsonProperty("tiltSpeedSlow")] public uint TiltSpeedSlow { get; set; } /// diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs index a8e8983d..0234a405 100644 --- a/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/IHasCameraPresets.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; namespace PepperDash.Essentials.Devices.Common.Cameras { @@ -11,12 +8,27 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public interface IHasCameraPresets { + /// + /// Event that is raised when the presets list has changed + /// event EventHandler PresetsListHasChanged; + /// + /// Gets the list of camera presets + /// List Presets { get; } + /// + /// Selects the specified preset + /// + /// The preset number to select void PresetSelect(int preset); + /// + /// Stores a preset at the specified location with the given description + /// + /// The preset number to store + /// The description for the preset void PresetStore(int preset, string description); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/CameraSelectedEventArgs.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/CameraSelectedEventArgs.cs new file mode 100644 index 00000000..bb2a85a2 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/CameraSelectedEventArgs.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Event arguments for the CameraSelected event + /// + [Obsolete("Use CameraSelectedEventArgs instead. This class will be removed in a future version")] + public class CameraSelectedEventArgs : EventArgs + { + /// Gets or sets the SelectedCamera + /// + public CameraBase SelectedCamera { get; private set; } + + /// + /// Constructor for CameraSelectedEventArgs + /// + /// + public CameraSelectedEventArgs(CameraBase camera) + { + SelectedCamera = camera; + } + } + + /// + /// Event arguments for the CameraSelected event + /// + /// + public class CameraSelectedEventArgs : EventArgs + { + /// + /// Gets or sets the SelectedCamera + /// + public T SelectedCamera { get; private set; } + + /// + /// Constructor for CameraSelectedEventArgs + /// + /// + public CameraSelectedEventArgs(T camera) + { + SelectedCamera = camera; + } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IAmFarEndCamera.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IAmFarEndCamera.cs new file mode 100644 index 00000000..a8e96664 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IAmFarEndCamera.cs @@ -0,0 +1,12 @@ +using PepperDash.Core; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IAmFarEndCamera + /// + public interface IAmFarEndCamera : IKeyName + { + + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/ICameraCapabilities.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/ICameraCapabilities.cs new file mode 100644 index 00000000..cf39a95c --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/ICameraCapabilities.cs @@ -0,0 +1,86 @@ +using Newtonsoft.Json; +using PepperDash.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for camera capabilities + /// + public interface ICameraCapabilities: IKeyName + { + /// + /// Indicates whether the camera can pan + /// + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] + bool CanPan { get; } + + /// + /// Indicates whether the camera can tilt + /// + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] + bool CanTilt { get; } + + /// + /// Indicates whether the camera can zoom + /// + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] + bool CanZoom { get; } + + + /// + /// Indicates whether the camera can focus + /// + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] + bool CanFocus { get; } + } + + /// + /// Indicates the capabilities of a camera + /// + public class CameraCapabilities : ICameraCapabilities + { + + /// + /// Unique Key + /// + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + public string Key { get; set; } + + /// + /// Isn't it obvious :) + /// + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } + + + /// + /// Indicates whether the camera can pan + /// + [JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)] + public bool CanPan { get; set; } + + /// + /// Indicates whether the camera can tilt + /// + [JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)] + public bool CanTilt { get; set; } + + /// + /// Indicates whether the camera can zoom + /// + [JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)] + public bool CanZoom { get; set; } + + + /// + /// Indicates whether the camera can focus + /// + [JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)] + public bool CanFocus { get; set; } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasAutoFocusMode.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasAutoFocusMode.cs new file mode 100644 index 00000000..0dbd5f52 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasAutoFocusMode.cs @@ -0,0 +1,24 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that have auto focus mode control + /// + public interface IHasAutoFocusMode : IHasCameraControls + { + /// + /// Sets the focus mode to auto or manual, or toggles between them. + /// + void SetFocusModeAuto(); + + /// + /// Sets the focus mode to manual, allowing for manual focus adjustments. + /// + void SetFocusModeManual(); + + /// + /// Toggles the focus mode between auto and manual. + /// + void ToggleFocusMode(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraAutoMode.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraAutoMode.cs new file mode 100644 index 00000000..9eeb1f40 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraAutoMode.cs @@ -0,0 +1,31 @@ +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + + /// + /// Interface for devices that have camera auto mode control + /// + public interface IHasCameraAutoMode : IHasCameraControls + { + /// + /// Enables or disables the camera's auto mode, which may include automatic adjustments for focus, exposure, and other settings. + /// + void CameraAutoModeOn(); + + /// + /// Disables the camera's auto mode, allowing for manual control of camera settings. + /// + void CameraAutoModeOff(); + + /// + /// Toggles the camera's auto mode state. If the camera is in auto mode, it will switch to manual mode, and vice versa. + /// + void CameraAutoModeToggle(); + + /// + /// Feedback that indicates whether the camera's auto mode is currently enabled. + /// + BoolFeedback CameraAutoModeIsOnFeedback { get; } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraControls.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraControls.cs new file mode 100644 index 00000000..a4ed5937 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraControls.cs @@ -0,0 +1,13 @@ +using PepperDash.Core; + + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + + /// + /// Interface for devices that have camera controls + /// + public interface IHasCameraControls : IKeyName + { + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraFocusControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraFocusControl.cs new file mode 100644 index 00000000..bf266d56 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraFocusControl.cs @@ -0,0 +1,29 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IHasCameraFocusControl + /// + public interface IHasCameraFocusControl : IHasCameraControls + { + /// + /// Focuses the camera near + /// + void FocusNear(); + + /// + /// Focuses the camera far + /// + void FocusFar(); + + /// + /// Stops the camera focus movement + /// + void FocusStop(); + + /// + /// Triggers the camera's auto focus functionality, if available. + /// + void TriggerAutoFocus(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMute.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMute.cs new file mode 100644 index 00000000..cae6f5ef --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMute.cs @@ -0,0 +1,31 @@ +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Describes the ability to mute and unmute camera video + /// + public interface IHasCameraMute : IKeyName + { + /// + /// Feedback that indicates whether the camera is muted + /// + BoolFeedback CameraIsMutedFeedback { get; } + + /// + /// Mutes the camera video, preventing it from being sent to the far end + /// + void CameraMuteOn(); + + /// + /// Unmutes the camera video, allowing it to be sent to the far end + /// + void CameraMuteOff(); + + /// + /// Toggles the camera mute state. If the camera is muted, it will be unmuted, and vice versa. + /// + void CameraMuteToggle(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMuteWithUnmuteRequest.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMuteWithUnmuteRequest.cs new file mode 100644 index 00000000..5426ea2b --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraMuteWithUnmuteRequest.cs @@ -0,0 +1,16 @@ +using System; + + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that can mute and unmute their camera video, with an event for unmute requests + /// + public interface IHasCameraMuteWithUnmuteReqeust : IHasCameraMute + { + /// + /// Event that is raised when a video unmute is requested, typically by the far end + /// + event EventHandler VideoUnmuteRequested; + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraOff.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraOff.cs new file mode 100644 index 00000000..6dc451c1 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraOff.cs @@ -0,0 +1,27 @@ +using PepperDash.Essentials.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + + + /// + /// To be implmented on codecs that can disable their camera(s) to blank the near end video + /// + public interface IHasCameraOff : IHasCameraControls + { + /// + /// Feedback that indicates whether the camera is off + /// + BoolFeedback CameraIsOffFeedback { get; } + + /// + /// Turns the camera off, blanking the near end video + /// + void CameraOff(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPanControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPanControl.cs new file mode 100644 index 00000000..507dc555 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPanControl.cs @@ -0,0 +1,24 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for camera pan control + /// + public interface IHasCameraPanControl : IHasCameraControls + { + /// + /// Pans the camera left + /// + void PanLeft(); + + /// + /// Pans the camera right + /// + void PanRight(); + + /// + /// Stops the camera pan movement + /// + void PanStop(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPtzControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPtzControl.cs new file mode 100644 index 00000000..de2b52dd --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraPtzControl.cs @@ -0,0 +1,14 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IHasCameraPtzControl + /// + public interface IHasCameraPtzControl : IHasCameraPanControl, IHasCameraTiltControl, IHasCameraZoomControl + { + /// + /// Resets the camera position + /// + void PositionHome(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraTiltControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraTiltControl.cs new file mode 100644 index 00000000..87dc1751 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraTiltControl.cs @@ -0,0 +1,24 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IHasCameraTiltControl + /// + public interface IHasCameraTiltControl : IHasCameraControls + { + /// + /// Tilts the camera down + /// + void TiltDown(); + + /// + /// Tilts the camera up + /// + void TiltUp(); + + /// + /// Stops the camera tilt movement + /// + void TiltStop(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraZoomControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraZoomControl.cs new file mode 100644 index 00000000..72bf16c4 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameraZoomControl.cs @@ -0,0 +1,24 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Defines the contract for IHasCameraZoomControl + /// + public interface IHasCameraZoomControl : IHasCameraControls + { + /// + /// Zooms the camera in + /// + void ZoomIn(); + + /// + /// Zooms the camera out + /// + void ZoomOut(); + + /// + /// Stops the camera zoom movement + /// + void ZoomStop(); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameras.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameras.cs new file mode 100644 index 00000000..5a5962f8 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCameras.cs @@ -0,0 +1,41 @@ +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that have cameras + /// + [Obsolete("Use IHasCamerasWithControls instead. This interface will be removed in a future version")] + public interface IHasCameras : IKeyName + { + /// + /// Event that is raised when a camera is selected + /// + event EventHandler CameraSelected; + + /// + /// List of cameras on the device. This should be a list of CameraBase objects + /// + List Cameras { get; } + + /// + /// The currently selected camera. This should be a CameraBase object + /// + CameraBase SelectedCamera { get; } + + /// + /// Feedback that indicates the currently selected camera + /// + StringFeedback SelectedCameraFeedback { get; } + + /// + /// Selects a camera from the list of available cameras based on the provided key. + /// + /// The unique identifier or name of the camera to select. + void SelectCamera(string key); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCamerasWithControls.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCamerasWithControls.cs new file mode 100644 index 00000000..f7aff6d2 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCamerasWithControls.cs @@ -0,0 +1,40 @@ +using PepperDash.Core; +using PepperDash.Essentials.Core; +using System; +using System.Collections.Generic; + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that have cameras with controls + /// + public interface IHasCamerasWithControls : IKeyName, IKeyed + { + /// + /// List of cameras on the device. This should be a list of IHasCameraControls objects + /// + + List Cameras { get; } + + /// + /// The currently selected camera. This should be an IHasCameraControls object + /// + IHasCameraControls SelectedCamera { get; } + + /// + /// Feedback that indicates the currently selected camera + /// + StringFeedback SelectedCameraFeedback { get; } + + /// + /// Event that is raised when a camera is selected + /// + event EventHandler> CameraSelected; + + /// + /// Selects a camera from the list of available cameras based on the provided key. + /// + /// + void SelectCamera(string key); + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCodecCameras.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCodecCameras.cs new file mode 100644 index 00000000..01cdf24e --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasCodecCameras.cs @@ -0,0 +1,13 @@ + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + + /// + /// Defines the contract for IHasCodecCameras + /// + public interface IHasCodecCameras : IHasCameras, IHasFarEndCameraControl + { + + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasFarEndCameraControl.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasFarEndCameraControl.cs new file mode 100644 index 00000000..10a4ba69 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/IHasFarEndCameraControl.cs @@ -0,0 +1,23 @@ +using PepperDash.Core; +using PepperDash.Essentials.Core; + + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Interface for devices that have a far end camera control + /// + public interface IHasFarEndCameraControl : IKeyName + { + /// + /// Gets the far end camera, which is typically a CameraBase object that represents the camera at the far end of a call + /// + CameraBase FarEndCamera { get; } + + /// + /// Feedback that indicates whether the far end camera is being controlled + /// + BoolFeedback ControllingFarEndCameraFeedback { get; } + + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/eCameraControlMode.cs b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/eCameraControlMode.cs new file mode 100644 index 00000000..c966ac41 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Cameras/Interfaces/eCameraControlMode.cs @@ -0,0 +1,24 @@ + + +namespace PepperDash.Essentials.Devices.Common.Cameras +{ + /// + /// Enum for camera control modes + /// + public enum eCameraControlMode + { + /// + /// Manual control mode, where the camera is controlled directly by the user or system + /// + Manual = 0, + /// + /// Off control mode, where the camera is turned off or disabled + /// + Off, + /// + /// Auto control mode, where the camera automatically adjusts settings based on the environment or conditions + /// + Auto + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/Call.cs b/src/PepperDash.Essentials.Devices.Common/Codec/Call.cs new file mode 100644 index 00000000..807a29d0 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/Call.cs @@ -0,0 +1,26 @@ +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a Call + /// + public class Call + { + /// + /// Gets or sets the Number + /// + public string Number { get; set; } + /// + /// Gets or sets the Protocol + /// + public string Protocol { get; set; } + /// + /// Gets or sets the CallRate + /// + public string CallRate { get; set; } + /// + /// Gets or sets the CallType + /// + public string CallType { get; set; } + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs index f3f164bd..134dc7b5 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/IPresenterTrack.cs @@ -1,10 +1,5 @@ using PepperDash.Core; using PepperDash.Essentials.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace PepperDash.Essentials.Devices.Common.Codec.Cisco { diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs index 83735183..522e6ad2 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/Cisco/ISpeakerTrack.cs @@ -1,10 +1,5 @@ using PepperDash.Core; using PepperDash.Essentials.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace PepperDash.Essentials.Devices.Common.Codec.Cisco { diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs b/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs index b0c91e4e..23a39f29 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/CodecActiveCallItem.cs @@ -1,10 +1,6 @@  using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -17,55 +13,55 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public class CodecActiveCallItem { - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Name /// + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } - [JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Number /// + [JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)] public string Number { get; set; } - [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] /// /// Gets or sets the Type /// + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] public eCodecCallType Type { get; set; } - [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] /// /// Gets or sets the Status /// + [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] public eCodecCallStatus Status { get; set; } - [JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)] - [JsonConverter(typeof(StringEnumConverter))] /// /// Gets or sets the Direction /// + [JsonProperty("direction", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(StringEnumConverter))] public eCodecCallDirection Direction { get; set; } - [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Id /// + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public string Id { get; set; } - [JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the IsOnHold /// + [JsonProperty("isOnHold", NullValueHandling = NullValueHandling.Ignore)] public bool IsOnHold { get; set; } - [JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Duration /// + [JsonProperty("duration", NullValueHandling = NullValueHandling.Ignore)] public TimeSpan Duration { get; set; } //public object CallMetaData { get; set; } @@ -81,7 +77,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec { return !(Status == eCodecCallStatus.Disconnected || Status == eCodecCallStatus.Disconnecting - || Status == eCodecCallStatus.Idle + || Status == eCodecCallStatus.Idle || Status == eCodecCallStatus.Unknown); } } @@ -97,6 +93,10 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public CodecActiveCallItem CallItem { get; private set; } + /// + /// Initializes a new instance of the CodecCallStatusItemChangeEventArgs class + /// + /// The call item that changed public CodecCallStatusItemChangeEventArgs(CodecActiveCallItem item) { CallItem = item; diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/CodecDirectory.cs b/src/PepperDash.Essentials.Devices.Common/Codec/CodecDirectory.cs new file mode 100644 index 00000000..df613941 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/CodecDirectory.cs @@ -0,0 +1,121 @@ + + +using System; +using System.Collections.Generic; +using System.Linq; + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a codec directory + /// + public class CodecDirectory + { + /// + /// Represents the contents of the directory + /// We don't want to serialize this for messages to MobileControl. MC can combine Contacts and Folders to get the same data + /// + [JsonIgnore] + public List CurrentDirectoryResults { get; private set; } + + /// + /// Gets the Contacts in the CurrentDirectoryResults + /// + [JsonProperty("contacts")] + public List Contacts + { + get + { + return CurrentDirectoryResults.OfType().Cast().ToList(); + } + } + + /// + /// Gets the Folders in the CurrentDirectoryResults + /// + [JsonProperty("folders")] + public List Folders + { + get + { + return CurrentDirectoryResults.OfType().Cast().ToList(); + } + } + + /// + /// Used to store the ID of the current folder for CurrentDirectoryResults + /// Gets or sets the ResultsFolderId + /// + [JsonProperty("resultsFolderId")] + public string ResultsFolderId { get; set; } + + /// + /// Constructor for + /// + public CodecDirectory() + { + CurrentDirectoryResults = new List(); + } + + /// + /// Adds folders to the directory + /// + /// + public void AddFoldersToDirectory(List folders) + { + if (folders != null) + CurrentDirectoryResults.AddRange(folders); + + SortDirectory(); + } + + /// + /// Adds contacts to the directory + /// + /// + public void AddContactsToDirectory(List contacts) + { + if (contacts != null) + CurrentDirectoryResults.AddRange(contacts); + + SortDirectory(); + } + + /// + /// Filters the CurrentDirectoryResults by the predicate + /// + /// + + public void FilterContacts(Func predicate) + { + CurrentDirectoryResults = CurrentDirectoryResults.Where(predicate).ToList(); + } + + /// + /// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically + /// + private void SortDirectory() + { + var sortedFolders = new List(); + + sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder)); + + sortedFolders.OrderBy(f => f.Name); + + var sortedContacts = new List(); + + sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact)); + + sortedFolders.OrderBy(c => c.Name); + + CurrentDirectoryResults.Clear(); + + CurrentDirectoryResults.AddRange(sortedFolders); + + CurrentDirectoryResults.AddRange(sortedContacts); + } + + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/CodecScheduleAwareness.cs b/src/PepperDash.Essentials.Devices.Common/Codec/CodecScheduleAwareness.cs new file mode 100644 index 00000000..4eea3d2a --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/CodecScheduleAwareness.cs @@ -0,0 +1,146 @@ + + +using System; +using System.Collections.Generic; +using Crestron.SimplSharp; +using PepperDash.Core; +using Serilog.Events; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a CodecScheduleAwareness + /// + public class CodecScheduleAwareness + { + List _meetings; + + /// + /// Event that is raised when a meeting event changes + /// + public event EventHandler MeetingEventChange; + + /// + /// Event that is raised when the meetings list has changed + /// + public event EventHandler MeetingsListHasChanged; + + private int _meetingWarningMinutes = 5; + + //private Meeting _previousChangedMeeting; + + //private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown; + + /// + /// Gets or sets the number of minutes before a meeting to issue a warning + /// + public int MeetingWarningMinutes + { + get { return _meetingWarningMinutes; } + set { _meetingWarningMinutes = value; } + } + + /// + /// Setter triggers MeetingsListHasChanged event + /// + public List Meetings + { + get + { + return _meetings; + } + set + { + _meetings = value; + MeetingsListHasChanged?.Invoke(this, new EventArgs()); + } + } + + private readonly CTimer _scheduleChecker; + + /// + /// Initializes a new instance of the CodecScheduleAwareness class with default poll time + /// + public CodecScheduleAwareness() + { + Meetings = new List(); + + _scheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000); + } + + /// + /// Initializes a new instance of the CodecScheduleAwareness class with specified poll time + /// + /// The poll time in milliseconds for checking schedule changes + public CodecScheduleAwareness(long pollTime) + { + Meetings = new List(); + + _scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime); + } + + /// + /// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting + /// + /// + /// + private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting) + { + Debug.LogMessage(LogEventLevel.Verbose, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType); + if (changeType != (changeType & meeting.NotifiedChangeTypes)) + { + // Add this change type to the NotifiedChangeTypes + meeting.NotifiedChangeTypes |= changeType; + MeetingEventChange?.Invoke(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting }); + } + else + { + Debug.LogMessage(LogEventLevel.Verbose, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType); + } + } + + + /// + /// Checks the schedule to see if any MeetingEventChange updates should be fired + /// + /// + private void CheckSchedule(object o) + { + // Iterate the meeting list and check if any meeting need to do anything + + const double meetingTimeEpsilon = 0.05; + foreach (var m in Meetings) + { + var changeType = eMeetingEventChangeType.Unknown; + + if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start + { + Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds); + changeType = eMeetingEventChangeType.MeetingStartWarning; + } + else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start + { + Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStart"); + changeType = eMeetingEventChangeType.MeetingStart; + } + else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end + { + Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds); + changeType = eMeetingEventChangeType.MeetingEndWarning; + } + else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended + { + Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEnd"); + changeType = eMeetingEventChangeType.MeetingEnd; + } + + if (changeType != eMeetingEventChangeType.Unknown) + { + OnMeetingChange(changeType, m); + } + } + + } + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/ContactMethod.cs b/src/PepperDash.Essentials.Devices.Common/Codec/ContactMethod.cs new file mode 100644 index 00000000..9cbd43cb --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/ContactMethod.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a ContactMethod + /// + public class ContactMethod + { + /// + /// Gets or sets the ContactMethodId + /// + [JsonProperty("contactMethodId")] + public string ContactMethodId { get; set; } + + /// + /// Gets or sets the Number + /// + [JsonProperty("number")] + public string Number { get; set; } + + /// + /// Gets or sets the Device + /// + [JsonProperty("device")] + [JsonConverter(typeof(StringEnumConverter))] + public eContactMethodDevice Device { get; set; } + + /// + /// Gets or sets the CallType + /// + [JsonProperty("callType")] + [JsonConverter(typeof(StringEnumConverter))] + public eContactMethodCallType CallType { get; set; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryContact.cs b/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryContact.cs new file mode 100644 index 00000000..8fd8bf82 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryContact.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a DirectoryContact + /// + public class DirectoryContact : DirectoryItem + { + + /// + /// Gets or sets the ContactId + /// + [JsonProperty("contactId")] + public string ContactId { get; set; } + + /// + /// Gets or sets the Title + /// + [JsonProperty("title")] + public string Title { get; set; } + + /// + /// Gets or sets the ContactMethods + /// + [JsonProperty("contactMethods")] + public List ContactMethods { get; set; } + + /// + /// Constructor for + /// + public DirectoryContact() + { + ContactMethods = new List(); + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryEventArgs.cs b/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryEventArgs.cs new file mode 100644 index 00000000..f7ba8a5f --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryEventArgs.cs @@ -0,0 +1,21 @@ + + +using System; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a DirectoryEventArgs + /// + public class DirectoryEventArgs : EventArgs + { + /// + /// Gets or sets the Directory + /// + public CodecDirectory Directory { get; set; } + /// + /// Gets or sets the DirectoryIsOnRoot + /// + public bool DirectoryIsOnRoot { get; set; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryFolder.cs b/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryFolder.cs new file mode 100644 index 00000000..6da08fba --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryFolder.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a DirectoryFolder + /// + public class DirectoryFolder : DirectoryItem + { + + /// + /// Gets or sets the Contacts + /// + [JsonProperty("contacts")] + public List Contacts { get; set; } + + /// + /// Constructor for + /// + public DirectoryFolder() + { + Contacts = new List(); + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryItem.cs b/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryItem.cs new file mode 100644 index 00000000..92996868 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/DirectoryItem.cs @@ -0,0 +1,41 @@ + + +using System; + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a DirectoryItem + /// + public class DirectoryItem : ICloneable + { + /// + /// Clone method + /// + public object Clone() + { + return MemberwiseClone(); + } + + /// + /// Gets or sets the FolderId + /// + [JsonProperty("folderId")] + public string FolderId { get; set; } + + + /// + /// Gets or sets the Name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the ParentFolderId + /// + [JsonProperty("parentFolderId")] + public string ParentFolderId { get; set; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs b/src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs index fefb4b09..a93337aa 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/ICiscoCodecCameraConfig.cs @@ -1,31 +1,65 @@ -using Crestron.SimplSharpPro; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace PepperDash.Essentials.Devices.Common.Codec -{ +namespace PepperDash.Essentials.Devices.Common.Codec +{ /// /// Describes a cisco codec device that can allow configuration of cameras /// public interface ICiscoCodecCameraConfig { + /// + /// Sets the assigned serial number for the specified camera + /// + /// The camera identifier + /// The serial number to assign void SetCameraAssignedSerialNumber(uint cameraId, string serialNumber); + /// + /// Sets the name for the camera on the specified video connector + /// + /// The video connector identifier + /// The name to assign void SetCameraName(uint videoConnectorId, string name); + /// + /// Sets the input source type for the specified video connector + /// + /// The video connector identifier + /// The source type to set void SetInputSourceType(uint videoConnectorId, eCiscoCodecInputSourceType sourceType); } + /// + /// Enumeration of Cisco codec input source types + /// public enum eCiscoCodecInputSourceType { + /// + /// PC source type + /// PC, + + /// + /// Camera source type + /// camera, + + /// + /// Document camera source type + /// document_camera, + + /// + /// Media player source type + /// mediaplayer, + + /// + /// Other source type + /// other, + + /// + /// Whiteboard source type + /// whiteboard } } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs index 8fbe2b9b..1445bd61 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasCallHold.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Defines the contract for IHasCallHold diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasDirectoryHistoryStack.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasDirectoryHistoryStack.cs new file mode 100644 index 00000000..e46d8762 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasDirectoryHistoryStack.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using PepperDash.Essentials.Devices.Common.Codec; + + +/// +/// Defines the contract for IHasDirectoryHistoryStack +/// +public interface IHasDirectoryHistoryStack : IHasDirectory +{ + /// + /// Gets the DirectoryBrowseHistoryStack + /// + Stack DirectoryBrowseHistoryStack { get; } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs index 7bb9b924..c989e671 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasDoNotDisturb.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec { @@ -34,6 +28,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec void ToggleDoNotDisturbMode(); } + /// + /// Defines the contract for devices that support Do Not Disturb mode with timeout functionality + /// public interface IHasDoNotDisturbModeWithTimeout : IHasDoNotDisturbMode { /// diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs index d22acbba..73884a2a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IHasExternalSourceSwitching.cs @@ -1,25 +1,54 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; namespace PepperDash.Essentials.Devices.Common.Codec { - /// - /// Defines the contract for IHasExternalSourceSwitching - /// + /// + /// Defines the contract for IHasExternalSourceSwitching + /// public interface IHasExternalSourceSwitching { + /// + /// Gets a value indicating whether the external source list is enabled + /// bool ExternalSourceListEnabled { get; } - string ExternalSourceInputPort { get; } + + /// + /// Gets the external source input port identifier + /// + string ExternalSourceInputPort { get; } + + /// + /// Adds an external source to the available sources + /// + /// The connector identifier + /// The unique key for the source + /// The display name for the source + /// The type of external source void AddExternalSource(string connectorId, string key, string name, eExternalSourceType type); + + /// + /// Sets the state of the specified external source + /// + /// The unique key of the external source + /// The mode to set for the source void SetExternalSourceState(string key, eExternalSourceMode mode); + + /// + /// Clears all external sources from the list + /// void ClearExternalSources(); - void SetSelectedSource(string key); - Action RunRouteAction { set;} + + /// + /// Sets the selected source by its key + /// + /// The unique key of the source to select + void SetSelectedSource(string key); + + /// + /// Sets the action to run when routing between sources + /// + Action RunRouteAction { set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/IInvitableContact.cs b/src/PepperDash.Essentials.Devices.Common/Codec/IInvitableContact.cs new file mode 100644 index 00000000..598a9b22 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/IInvitableContact.cs @@ -0,0 +1,13 @@ +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Defines the contract for IInvitableContact + /// + public interface IInvitableContact + { + /// + /// Gets a value indicating whether this contact is invitable + /// + bool IsInvitableContact { get; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/InvitableDirectoryContact.cs b/src/PepperDash.Essentials.Devices.Common/Codec/InvitableDirectoryContact.cs new file mode 100644 index 00000000..68707c35 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/InvitableDirectoryContact.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents an InvitableDirectoryContact + /// + public class InvitableDirectoryContact : DirectoryContact, IInvitableContact + { + /// + /// Gets a value indicating whether this contact is invitable + /// + [JsonProperty("isInvitableContact")] + public bool IsInvitableContact + { + get + { + return this is IInvitableContact; + } + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/Meeting.cs b/src/PepperDash.Essentials.Devices.Common/Codec/Meeting.cs new file mode 100644 index 00000000..22bc697a --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/Meeting.cs @@ -0,0 +1,182 @@ + + +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a Meeting + /// + public class Meeting + { + /// + /// Minutes before the meeting to show warning + /// + [JsonProperty("minutesBeforeMeeting")] + public int MinutesBeforeMeeting; + + /// + /// Gets or sets the meeting ID + /// + [JsonProperty("id")] + public string Id { get; set; } + /// + /// Gets or sets the meeting organizer + /// + [JsonProperty("organizer")] + public string Organizer { get; set; } + /// + /// Gets or sets the Title + /// + [JsonProperty("title")] + public string Title { get; set; } + /// + /// Gets or sets the Agenda + /// + [JsonProperty("agenda")] + public string Agenda { get; set; } + + /// + /// Gets the meeting warning time span in minutes before the meeting starts + /// + [JsonProperty("meetingWarningMinutes")] + public TimeSpan MeetingWarningMinutes + { + get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); } + } + /// + /// Gets the time remaining until the meeting starts + /// + [JsonProperty("timeToMeetingStart")] + public TimeSpan TimeToMeetingStart + { + get + { + return StartTime - DateTime.Now; + } + } + /// + /// Gets the time remaining until the meeting ends + /// + [JsonProperty("timeToMeetingEnd")] + public TimeSpan TimeToMeetingEnd + { + get + { + return EndTime - DateTime.Now; + } + } + /// + /// Gets or sets the StartTime + /// + [JsonProperty("startTime")] + public DateTime StartTime { get; set; } + /// + /// Gets or sets the EndTime + /// + [JsonProperty("endTime")] + public DateTime EndTime { get; set; } + /// + /// Gets the duration of the meeting + /// + [JsonProperty("duration")] + public TimeSpan Duration + { + get + { + return EndTime - StartTime; + } + } + /// + /// Gets or sets the Privacy + /// + [JsonProperty("privacy")] + public eMeetingPrivacy Privacy { get; set; } + /// + /// Gets a value indicating whether the meeting can be joined + /// + [JsonProperty("joinable")] + public bool Joinable + { + get + { + var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now + && DateTime.Now <= EndTime.AddSeconds(-_joinableCooldownSeconds); + //Debug.LogMessage(LogEventLevel.Verbose, "Meeting Id: {0} joinable: {1}", Id, joinable); + return joinable; + } + } + + /// + /// Gets or sets the Dialable + /// + [JsonProperty("dialable")] + public bool Dialable { get; set; } + + //public string ConferenceNumberToDial { get; set; } + + /// + /// Gets or sets the ConferencePassword + /// + [JsonProperty("conferencePassword")] + public string ConferencePassword { get; set; } + + /// + /// Gets or sets the IsOneButtonToPushMeeting + /// + [JsonProperty("isOneButtonToPushMeeting")] + public bool IsOneButtonToPushMeeting { get; set; } + + /// + /// Gets or sets the Calls + /// + [JsonProperty("calls")] + public List Calls { get; private set; } + + /// + /// Tracks the change types that have already been notified for + /// Gets or sets the NotifiedChangeTypes + /// + [JsonIgnore] + public eMeetingEventChangeType NotifiedChangeTypes { get; set; } + + [JsonIgnore] private readonly int _joinableCooldownSeconds; + + /// + /// Constructor for Meeting + /// + public Meeting() + { + Calls = new List(); + _joinableCooldownSeconds = 300; + } + + /// + /// Constructor for Meeting + /// + /// Number of seconds after meeting start when it is no longer joinable + public Meeting(int joinableCooldownSeconds) + { + Calls = new List(); + _joinableCooldownSeconds = joinableCooldownSeconds; + } + + + + #region Overrides of Object + + /// + /// ToString method + /// + /// + public override string ToString() + { + return string.Format("{0}:{1}: {2}-{3}", Title, Agenda, StartTime, EndTime); + } + + #endregion + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/MeetingEventArgs.cs b/src/PepperDash.Essentials.Devices.Common/Codec/MeetingEventArgs.cs new file mode 100644 index 00000000..ed706a1c --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/MeetingEventArgs.cs @@ -0,0 +1,22 @@ + + +using System; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Represents a MeetingEventArgs + /// + public class MeetingEventArgs : EventArgs + { + /// + /// Gets or sets the ChangeType + /// + public eMeetingEventChangeType ChangeType { get; set; } + /// + /// Gets or sets the Meeting + /// + public Meeting Meeting { get; set; } + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs index 01eca3d1..e10f61a3 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallDirection.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec { /// @@ -12,7 +6,20 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public enum eCodecCallDirection { - Unknown = 0, Incoming, Outgoing + /// + /// Unknown call direction + /// + Unknown = 0, + + /// + /// Incoming call direction + /// + Incoming, + + /// + /// Outgoing call direction + /// + Outgoing } /// diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs index b2ab5d99..6116ab16 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallStatus.cs @@ -1,27 +1,68 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eCodecCallStatus values /// public enum eCodecCallStatus { + /// + /// Unknown call status + /// Unknown = 0, - Connected, - Connecting, - Dialing, + + /// + /// Call is connected + /// + Connected, + + /// + /// Call is connecting + /// + Connecting, + + /// + /// Call is dialing + /// + Dialing, + + /// + /// Call is disconnected + /// Disconnected, - Disconnecting, - EarlyMedia, + + /// + /// Call is disconnecting + /// + Disconnecting, + + /// + /// Early media is being sent/received + /// + EarlyMedia, + + /// + /// Call is idle + /// Idle, - OnHold, - Ringing, - Preserved, + + /// + /// Call is on hold + /// + OnHold, + + /// + /// Call is ringing + /// + Ringing, + + /// + /// Call is preserved + /// + Preserved, + + /// + /// Call is remote preserved + /// RemotePreserved, } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs index cf15140e..2b9609fb 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eCodecCallType.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec { /// @@ -12,10 +6,29 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public enum eCodecCallType { - Unknown = 0, - Audio, - Video, - AudioCanEscalate, + /// + /// Unknown call type + /// + Unknown = 0, + + /// + /// Audio-only call type + /// + Audio, + + /// + /// Video call type + /// + Video, + + /// + /// Audio call that can be escalated to video + /// + AudioCanEscalate, + + /// + /// Forward all call type + /// ForwardAllCall } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eContactMethodCallType.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eContactMethodCallType.cs new file mode 100644 index 00000000..8e46a721 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eContactMethodCallType.cs @@ -0,0 +1,21 @@ +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Enumeration of eContactMethodCallType values + /// + public enum eContactMethodCallType + { + /// + /// Unknown call type + /// + Unknown = 0, + /// + /// Audio call type + /// + Audio, + /// + /// Video call type + /// + Video + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eContactMethodDevice.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eContactMethodDevice.cs new file mode 100644 index 00000000..83bfc995 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eContactMethodDevice.cs @@ -0,0 +1,29 @@ +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Enumeration of eContactMethodDevice values + /// + public enum eContactMethodDevice + { + /// + /// Unknown contact method + /// + Unknown = 0, + /// + /// Mobile contact method + /// + Mobile, + /// + /// Other contact method + /// + Other, + /// + /// Telephone contact method + /// + Telephone, + /// + /// Video contact method + /// + Video + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingEventChangeType.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingEventChangeType.cs new file mode 100644 index 00000000..2861703f --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingEventChangeType.cs @@ -0,0 +1,35 @@ + + +using System; + +namespace PepperDash.Essentials.Devices.Common.Codec +{ + /// + /// Enumeration of eMeetingEventChangeType values + /// + [Flags] + public enum eMeetingEventChangeType + { + /// + /// Unknown change type + /// + Unknown = 0, + /// + /// Meeting start warning + /// + MeetingStartWarning = 1, + /// + /// Meeting start + /// + MeetingStart = 2, + /// + /// Meeting end warning + /// + MeetingEndWarning = 4, + /// + /// Meeting end + /// + MeetingEnd = 8 + } + +} diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs b/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs index 29ac5247..19a6d31b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/eMeetingPrivacy.cs @@ -1,18 +1,23 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec { /// /// Enumeration of eMeetingPrivacy values /// public enum eMeetingPrivacy { + /// + /// Unknown meeting privacy level + /// Unknown = 0, + + /// + /// Public meeting + /// Public, + + /// + /// Private meeting + /// Private } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs index d61f7d26..eeab2801 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iCodecAudio.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec { diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs index ae5351c1..eeb6610f 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallFavorites.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; +using System.Collections.Generic; namespace PepperDash.Essentials.Devices.Common.Codec { @@ -11,6 +7,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public interface IHasCallFavorites { + /// + /// Gets the call favorites for this device + /// CodecCallFavorites CallFavorites { get; } } @@ -24,6 +23,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public List Favorites { get; set; } + /// + /// Initializes a new instance of the CodecCallFavorites class + /// public CodecCallFavorites() { Favorites = new List(); diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs index cd7d7b96..7f495daa 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasCallHistory.cs @@ -2,10 +2,9 @@ using System; using System.Collections.Generic; -using PepperDash.Essentials.Devices.Common.VideoCodec; - using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Devices.Common.Codec { @@ -15,8 +14,15 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public interface IHasCallHistory { + /// + /// Gets the call history for this device + /// CodecCallHistory CallHistory { get; } + /// + /// Removes the specified call history entry + /// + /// The call history entry to remove void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry); } @@ -25,9 +31,24 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public enum eCodecOccurrenceType { + /// + /// Unknown occurrence type + /// Unknown = 0, + + /// + /// Call was placed (outgoing) + /// Placed = 1, + + /// + /// Call was received (incoming) + /// Received = 2, + + /// + /// Call received no answer + /// NoAnswer = 3, } @@ -36,6 +57,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public class CodecCallHistory { + /// + /// Event that is raised when the recent calls list has changed + /// public event EventHandler RecentCallsListHasChanged; /// @@ -48,6 +72,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// CallHistoryEntry ListEmptyEntry; + /// + /// Initializes a new instance of the CodecCallHistory class + /// public CodecCallHistory() { ListEmptyEntry = new CallHistoryEntry() { Name = "No Recent Calls" }; @@ -80,15 +107,22 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public class CallHistoryEntry : CodecActiveCallItem { - [JsonConverter(typeof(IsoDateTimeConverter))] - [JsonProperty("startTime")] /// /// Gets or sets the StartTime /// + [JsonConverter(typeof(IsoDateTimeConverter))] + [JsonProperty("startTime")] public DateTime StartTime { get; set; } + /// + /// Gets or sets the occurrence type for this call history entry + /// [JsonConverter(typeof(StringEnumConverter))] [JsonProperty("occurrenceType")] public eCodecOccurrenceType OccurrenceType { get; set; } + + /// + /// Gets or sets the occurrence history identifier + /// [JsonProperty("occurrenceHistoryId")] public string OccurrenceHistoryId { get; set; } } @@ -119,7 +153,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec } // Check if list is empty and if so, add an item to display No Recent Calls - if(genericEntries.Count == 0) + if (genericEntries.Count == 0) genericEntries.Add(ListEmptyEntry); RecentCalls = genericEntries; diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs index e944b432..2dea5b4a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasContentSharing.cs @@ -1,11 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Core; -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec @@ -15,12 +8,29 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public interface IHasContentSharing { + /// + /// Gets feedback indicating whether content sharing is currently active + /// BoolFeedback SharingContentIsOnFeedback { get; } + + /// + /// Gets feedback about the current sharing source + /// StringFeedback SharingSourceFeedback { get; } + /// + /// Gets a value indicating whether content should be automatically shared while in a call + /// bool AutoShareContentWhileInCall { get; } + /// + /// Starts content sharing + /// void StartSharing(); + + /// + /// Stops content sharing + /// void StopSharing(); } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs index bce2dee3..a5373004 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDialer.cs @@ -1,10 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Codec { @@ -15,15 +9,49 @@ namespace PepperDash.Essentials.Devices.Common.Codec { // Add requirements for Dialer functionality + /// + /// Event that is raised when call status changes + /// event EventHandler CallStatusChange; + /// + /// Dials the specified number + /// + /// The number to dial void Dial(string number); + + /// + /// Ends the specified active call + /// + /// The active call to end void EndCall(CodecActiveCallItem activeCall); + + /// + /// Ends all active calls + /// void EndAllCalls(); + + /// + /// Accepts the specified incoming call + /// + /// The call item to accept void AcceptCall(CodecActiveCallItem item); + + /// + /// Rejects the specified incoming call + /// + /// The call item to reject void RejectCall(CodecActiveCallItem item); + + /// + /// Sends DTMF digits during a call + /// + /// The DTMF digit(s) to send void SendDtmf(string digit); + /// + /// Gets a value indicating whether the device is currently in a call + /// bool IsInCall { get; } } diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs index de82bcfb..83cc6c8d 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasDirectory.cs @@ -1,319 +1,59 @@  using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - - -using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Devices.Common.Codec { - /// - /// Defines the API for codecs with a directory - /// + /// + /// Defines the API for codecs with a directory + /// public interface IHasDirectory { + /// + /// Event that fires when a directory result is returned from the codec + /// event EventHandler DirectoryResultReturned; + /// + /// Gets the DirectoryRoot + /// CodecDirectory DirectoryRoot { get; } + /// + /// Gets the CurrentDirectoryResult + /// CodecDirectory CurrentDirectoryResult { get; } + /// + /// Gets the PhonebookSyncState + /// CodecPhonebookSyncState PhonebookSyncState { get; } + /// + /// Method to initiate a search of the directory on the server + /// void SearchDirectory(string searchString); + /// + /// Method to get the contents of a specific folder in the directory on the server + /// void GetDirectoryFolderContents(string folderId); + /// + /// Method to set the current directory to the root folder + /// void SetCurrentDirectoryToRoot(); + /// + /// Method to get the contents of the parent folder in the directory on the server + /// void GetDirectoryParentFolderContents(); + /// + /// Gets the CurrentDirectoryResultIsNotDirectoryRoot + /// BoolFeedback CurrentDirectoryResultIsNotDirectoryRoot { get; } } - - /// - /// Defines the contract for IHasDirectoryHistoryStack - /// - public interface IHasDirectoryHistoryStack : IHasDirectory - { - Stack DirectoryBrowseHistoryStack { get; } - } - - - /// - /// Represents a DirectoryEventArgs - /// - public class DirectoryEventArgs : EventArgs - { - /// - /// Gets or sets the Directory - /// - public CodecDirectory Directory { get; set; } - /// - /// Gets or sets the DirectoryIsOnRoot - /// - public bool DirectoryIsOnRoot { get; set; } - } - - /// - /// Represents a codec directory - /// - public class CodecDirectory - { - /// - /// Represents the contents of the directory - /// We don't want to serialize this for messages to MobileControl. MC can combine Contacts and Folders to get the same data - /// - [JsonIgnore] - public List CurrentDirectoryResults { get; private set; } - - [JsonProperty("contacts")] - public List Contacts - { - get - { - return CurrentDirectoryResults.OfType().Cast().ToList(); - } - } - - [JsonProperty("folders")] - public List Folders - { - get - { - return CurrentDirectoryResults.OfType().Cast().ToList(); - } - } - - /// - /// Used to store the ID of the current folder for CurrentDirectoryResults - /// - [JsonProperty("resultsFolderId")] - /// - /// Gets or sets the ResultsFolderId - /// - public string ResultsFolderId { get; set; } - - public CodecDirectory() - { - CurrentDirectoryResults = new List(); - } - - /// - /// Adds folders to the directory - /// - /// - /// - /// AddFoldersToDirectory method - /// - public void AddFoldersToDirectory(List folders) - { - if(folders != null) - CurrentDirectoryResults.AddRange(folders); - - SortDirectory(); - } - - /// - /// Adds contacts to the directory - /// - /// - /// - /// AddContactsToDirectory method - /// - public void AddContactsToDirectory(List contacts) - { - if(contacts != null) - CurrentDirectoryResults.AddRange(contacts); - - SortDirectory(); - } - - /// - /// Filters the CurrentDirectoryResults by the predicate - /// - /// - /// - /// FilterContacts method - /// - public void FilterContacts(Func predicate) - { - CurrentDirectoryResults = CurrentDirectoryResults.Where(predicate).ToList(); - } - - /// - /// Sorts the DirectoryResults list to display all folders alphabetically, then all contacts alphabetically - /// - private void SortDirectory() - { - var sortedFolders = new List(); - - sortedFolders.AddRange(CurrentDirectoryResults.Where(f => f is DirectoryFolder)); - - sortedFolders.OrderBy(f => f.Name); - - var sortedContacts = new List(); - - sortedContacts.AddRange(CurrentDirectoryResults.Where(c => c is DirectoryContact)); - - sortedFolders.OrderBy(c => c.Name); - - CurrentDirectoryResults.Clear(); - - CurrentDirectoryResults.AddRange(sortedFolders); - - CurrentDirectoryResults.AddRange(sortedContacts); - } - - } - - /// - /// Defines the contract for IInvitableContact - /// - public interface IInvitableContact - { - bool IsInvitableContact { get; } - } - - public class InvitableDirectoryContact : DirectoryContact, IInvitableContact - { - [JsonProperty("isInvitableContact")] - public bool IsInvitableContact - { - get - { - return this is IInvitableContact; - } - } - } - - /// - /// Represents a DirectoryItem - /// - public class DirectoryItem : ICloneable - { - /// - /// Clone method - /// - public object Clone() - { - return this.MemberwiseClone(); - } - - [JsonProperty("folderId")] - public string FolderId { get; set; } - - [JsonProperty("name")] - /// - /// Gets or sets the Name - /// - public string Name { get; set; } - - [JsonProperty("parentFolderId")] - /// - /// Gets or sets the ParentFolderId - /// - public string ParentFolderId { get; set; } - } - - /// - /// Represents a DirectoryFolder - /// - public class DirectoryFolder : DirectoryItem - { - [JsonProperty("contacts")] - /// - /// Gets or sets the Contacts - /// - public List Contacts { get; set; } - - - public DirectoryFolder() - { - Contacts = new List(); - } - } - - /// - /// Represents a DirectoryContact - /// - public class DirectoryContact : DirectoryItem - { - [JsonProperty("contactId")] - /// - /// Gets or sets the ContactId - /// - public string ContactId { get; set; } - - [JsonProperty("title")] - public string Title { get; set; } - - [JsonProperty("contactMethods")] - public List ContactMethods { get; set; } - - public DirectoryContact() - { - ContactMethods = new List(); - } - } - - /// - /// Represents a ContactMethod - /// - public class ContactMethod - { - [JsonProperty("contactMethodId")] - /// - /// Gets or sets the ContactMethodId - /// - public string ContactMethodId { get; set; } - - [JsonProperty("number")] - public string Number { get; set; } - - [JsonProperty("device")] - [JsonConverter(typeof(StringEnumConverter))] - /// - /// Gets or sets the Device - /// - public eContactMethodDevice Device { get; set; } - - [JsonProperty("callType")] - [JsonConverter(typeof(StringEnumConverter))] - /// - /// Gets or sets the CallType - /// - public eContactMethodCallType CallType { get; set; } - } - - /// - /// Enumeration of eContactMethodDevice values - /// - public enum eContactMethodDevice - { - Unknown = 0, - Mobile, - Other, - Telephone, - Video - } - - /// - /// Enumeration of eContactMethodCallType values - /// - public enum eContactMethodCallType - { - Unknown = 0, - Audio, - Video - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs b/src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs index 240ac15f..ed17762a 100644 --- a/src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs +++ b/src/PepperDash.Essentials.Devices.Common/Codec/iHasScheduleAwareness.cs @@ -1,339 +1,20 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Core; - -using Newtonsoft.Json; -using Serilog.Events; - -namespace PepperDash.Essentials.Devices.Common.Codec +namespace PepperDash.Essentials.Devices.Common.Codec { - [Flags] - /// - /// Enumeration of eMeetingEventChangeType values - /// - public enum eMeetingEventChangeType - { - Unknown = 0, - MeetingStartWarning = 1, - MeetingStart = 2, - MeetingEndWarning = 4, - MeetingEnd = 8 - } /// /// Defines the contract for IHasScheduleAwareness /// public interface IHasScheduleAwareness { + /// + /// Gets the CodecScheduleAwareness instance + /// CodecScheduleAwareness CodecSchedule { get; } + /// + /// Method to initiate getting the schedule from the server + /// void GetSchedule(); } - /// - /// Represents a CodecScheduleAwareness - /// - public class CodecScheduleAwareness - { - List _meetings; - - public event EventHandler MeetingEventChange; - - public event EventHandler MeetingsListHasChanged; - - private int _meetingWarningMinutes = 5; - - //private Meeting _previousChangedMeeting; - - //private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown; - - public int MeetingWarningMinutes - { - get { return _meetingWarningMinutes; } - set { _meetingWarningMinutes = value; } - } - - /// - /// Setter triggers MeetingsListHasChanged event - /// - public List Meetings - { - get - { - return _meetings; - } - set - { - _meetings = value; - MeetingsListHasChanged?.Invoke(this, new EventArgs()); - } - } - - private readonly CTimer _scheduleChecker; - - public CodecScheduleAwareness() - { - Meetings = new List(); - - _scheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000); - } - - public CodecScheduleAwareness(long pollTime) - { - Meetings = new List(); - - _scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime); - } - - /// - /// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting - /// - /// - /// - private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting) - { - Debug.LogMessage(LogEventLevel.Verbose, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType); - if (changeType != (changeType & meeting.NotifiedChangeTypes)) - { - // Add this change type to the NotifiedChangeTypes - meeting.NotifiedChangeTypes |= changeType; - MeetingEventChange?.Invoke(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting }); - } - else - { - Debug.LogMessage(LogEventLevel.Verbose, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType); - } - } - - - /// - /// Checks the schedule to see if any MeetingEventChange updates should be fired - /// - /// - private void CheckSchedule(object o) - { - // Iterate the meeting list and check if any meeting need to do anything - - const double meetingTimeEpsilon = 0.05; - foreach (var m in Meetings) - { - var changeType = eMeetingEventChangeType.Unknown; - - if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start - { - Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds); - changeType = eMeetingEventChangeType.MeetingStartWarning; - } - else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start - { - Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingStart"); - changeType = eMeetingEventChangeType.MeetingStart; - } - else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end - { - Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds); - changeType = eMeetingEventChangeType.MeetingEndWarning; - } - else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended - { - Debug.LogMessage(LogEventLevel.Verbose, "********************* MeetingEnd"); - changeType = eMeetingEventChangeType.MeetingEnd; - } - - if (changeType != eMeetingEventChangeType.Unknown) - { - OnMeetingChange(changeType, m); - } - } - - } - } - - /// - /// Represents a Meeting - /// - public class Meeting - { - [JsonProperty("minutesBeforeMeeting")] - public int MinutesBeforeMeeting; - - [JsonProperty("id")] - public string Id { get; set; } - [JsonProperty("organizer")] - public string Organizer { get; set; } - [JsonProperty("title")] - /// - /// Gets or sets the Title - /// - public string Title { get; set; } - [JsonProperty("agenda")] - /// - /// Gets or sets the Agenda - /// - public string Agenda { get; set; } - - [JsonProperty("meetingWarningMinutes")] - public TimeSpan MeetingWarningMinutes - { - get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); } - } - [JsonProperty("timeToMeetingStart")] - public TimeSpan TimeToMeetingStart - { - get - { - return StartTime - DateTime.Now; - } - } - [JsonProperty("timeToMeetingEnd")] - public TimeSpan TimeToMeetingEnd - { - get - { - return EndTime - DateTime.Now; - } - } - [JsonProperty("startTime")] - /// - /// Gets or sets the StartTime - /// - public DateTime StartTime { get; set; } - [JsonProperty("endTime")] - /// - /// Gets or sets the EndTime - /// - public DateTime EndTime { get; set; } - [JsonProperty("duration")] - public TimeSpan Duration - { - get - { - return EndTime - StartTime; - } - } - [JsonProperty("privacy")] - /// - /// Gets or sets the Privacy - /// - public eMeetingPrivacy Privacy { get; set; } - [JsonProperty("joinable")] - public bool Joinable - { - get - { - var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now - && DateTime.Now <= EndTime.AddSeconds(-_joinableCooldownSeconds); - //Debug.LogMessage(LogEventLevel.Verbose, "Meeting Id: {0} joinable: {1}", Id, joinable); - return joinable; - } - } - - [JsonProperty("dialable")] - /// - /// Gets or sets the Dialable - /// - public bool Dialable { get; set; } - - //public string ConferenceNumberToDial { get; set; } - [JsonProperty("conferencePassword")] - /// - /// Gets or sets the ConferencePassword - /// - public string ConferencePassword { get; set; } - [JsonProperty("isOneButtonToPushMeeting")] - /// - /// Gets or sets the IsOneButtonToPushMeeting - /// - public bool IsOneButtonToPushMeeting { get; set; } - - [JsonProperty("calls")] - /// - /// Gets or sets the Calls - /// - public List Calls { get; private set; } - - /// - /// Tracks the change types that have already been notified for - /// - [JsonIgnore] - /// - /// Gets or sets the NotifiedChangeTypes - /// - public eMeetingEventChangeType NotifiedChangeTypes { get; set; } - - [JsonIgnore] private readonly int _joinableCooldownSeconds; - - - public Meeting() - { - Calls = new List(); - _joinableCooldownSeconds = 300; - } - - public Meeting(int joinableCooldownSeconds) - { - Calls = new List(); - _joinableCooldownSeconds = joinableCooldownSeconds; - } - - - - #region Overrides of Object - - /// - /// ToString method - /// - /// - public override string ToString() - { - return String.Format("{0}:{1}: {2}-{3}", Title, Agenda, StartTime, EndTime); - } - - #endregion - } - - /// - /// Represents a Call - /// - public class Call - { - /// - /// Gets or sets the Number - /// - public string Number { get; set; } - /// - /// Gets or sets the Protocol - /// - public string Protocol { get; set; } - /// - /// Gets or sets the CallRate - /// - public string CallRate { get; set; } - /// - /// Gets or sets the CallType - /// - public string CallType { get; set; } - } - - /// - /// Represents a MeetingEventArgs - /// - public class MeetingEventArgs : EventArgs - { - /// - /// Gets or sets the ChangeType - /// - public eMeetingEventChangeType ChangeType { get; set; } - /// - /// Gets or sets the Meeting - /// - public Meeting Meeting { get; set; } - } - } diff --git a/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs b/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs index 296eb91a..e20abc9c 100644 --- a/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/DSP/DspBase.cs @@ -1,61 +1,84 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.Devices.Common.DSP { - public abstract class DspBase : EssentialsDevice, ILevelControls - { - public Dictionary LevelControlPoints { get; private set; } + /// + /// Base class for DSP devices + /// + public abstract class DspBase : EssentialsDevice, ILevelControls + { + /// + /// Gets the collection of level control points + /// + public Dictionary LevelControlPoints { get; private set; } + /// + /// Gets the collection of dialer control points + /// public Dictionary DialerControlPoints { get; private set; } + /// + /// Gets the collection of switcher control points + /// public Dictionary SwitcherControlPoints { get; private set; } - public DspBase(string key, string name) : - base(key, name) - { + /// + /// Initializes a new instance of the DspBase class + /// + /// The device key + /// The device name + public DspBase(string key, string name) : + base(key, name) + { - LevelControlPoints = new Dictionary(); - DialerControlPoints = new Dictionary(); - SwitcherControlPoints = new Dictionary(); - } + LevelControlPoints = new Dictionary(); + DialerControlPoints = new Dictionary(); + SwitcherControlPoints = new Dictionary(); + } - // in audio call feedback + // in audio call feedback - // VOIP - // Phone dialer + // VOIP + // Phone dialer - } + } - // Fusion - // Privacy state - // Online state - // level/mutes ? - - // AC Log call stats - - // Typical presets: - // call default preset to restore levels and mutes + // Fusion + // Privacy state + // Online state + // level/mutes ? - public abstract class DspControlPoint :IKeyed - { + // AC Log call stats + + // Typical presets: + // call default preset to restore levels and mutes + + /// + /// Base class for DSP control points + /// + public abstract class DspControlPoint : IKeyed + { /// /// Gets or sets the Key /// public string Key { get; } + /// + /// Initializes a new instance of the DspControlPoint class + /// + /// The control point key protected DspControlPoint(string key) => Key = key; - } + } - public abstract class DspLevelControlPoint :DspControlPoint, IBasicVolumeWithFeedback + /// + /// Base class for DSP level control points with volume and mute functionality + /// + public abstract class DspLevelControlPoint : DspControlPoint, IBasicVolumeWithFeedback { /// /// Gets or sets the MuteFeedback @@ -66,30 +89,63 @@ namespace PepperDash.Essentials.Devices.Common.DSP /// public IntFeedback VolumeLevelFeedback { get; } + /// + /// Initializes a new instance of the DspLevelControlPoint class + /// + /// The control point key + /// Function to get mute status + /// Function to get volume level protected DspLevelControlPoint(string key, Func muteFeedbackFunc, Func volumeLevelFeedbackFunc) : base(key) { - MuteFeedback = new BoolFeedback(muteFeedbackFunc); - VolumeLevelFeedback = new IntFeedback(volumeLevelFeedbackFunc); + MuteFeedback = new BoolFeedback("mute", muteFeedbackFunc); + VolumeLevelFeedback = new IntFeedback("volume", volumeLevelFeedbackFunc); } + /// + /// Turns mute off + /// public abstract void MuteOff(); + /// + /// Turns mute on + /// public abstract void MuteOn(); + /// + /// Toggles mute state + /// public abstract void MuteToggle(); + /// + /// Sets the volume level + /// + /// The volume level to set public abstract void SetVolume(ushort level); + /// + /// Decreases volume + /// + /// True when pressed, false when released public abstract void VolumeDown(bool pressRelease); + /// + /// Increases volume + /// + /// True when pressed, false when released public abstract void VolumeUp(bool pressRelease); } - - public abstract class DspDialerBase:DspControlPoint - { + /// + /// Base class for DSP dialer control points + /// + public abstract class DspDialerBase : DspControlPoint + { + /// + /// Initializes a new instance of the DspDialerBase class + /// + /// The dialer control point key protected DspDialerBase(string key) : base(key) { } - } + } - // Main program - // VTC - // ATC - // Mics, unusual + // Main program + // VTC + // ATC + // Mics, unusual } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs b/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs index 178c53a7..2c7507ba 100644 --- a/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs +++ b/src/PepperDash.Essentials.Devices.Common/DeviceFactory.cs @@ -14,7 +14,9 @@ namespace PepperDash.Essentials.Devices.Common /// public class DeviceFactory { - + /// + /// Initializes a new instance of the DeviceFactory class + /// public DeviceFactory() { var assy = Assembly.GetExecutingAssembly(); diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs index 52fc5233..858cdf42 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/BasicIrDisplay.cs @@ -11,37 +11,53 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Displays { - /// - /// Represents a BasicIrDisplay - /// - public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced + /// + /// Represents a BasicIrDisplay + /// + public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced { - /// - /// Gets or sets the IrPort - /// + /// + /// Gets or sets the IrPort + /// public IrOutputPortController IrPort { get; private set; } - /// - /// Gets or sets the IrPulseTime - /// + /// + /// Gets or sets the IrPulseTime + /// public ushort IrPulseTime { get; set; } - protected Func PowerIsOnFeedbackFunc - { - get { return () => _PowerIsOn; } - } + /// + /// Gets the power is on feedback function + /// + protected Func PowerIsOnFeedbackFunc + { + get { return () => _PowerIsOn; } + } + /// + /// Gets the is cooling down feedback function + /// protected override Func IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } } + /// + /// Gets the is warming up feedback function + /// protected override Func IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } } - bool _PowerIsOn; + bool _PowerIsOn; bool _IsWarmingUp; bool _IsCoolingDown; + /// + /// Initializes a new instance of the BasicIrDisplay class + /// + /// The device key + /// The device name + /// The IR output port + /// The path to the IR driver file public BasicIrDisplay(string key, string name, IROutputPort port, string irDriverFilepath) : base(key, name) { @@ -53,74 +69,74 @@ namespace PepperDash.Essentials.Devices.Common.Displays InputPorts.AddRange(new RoutingPortCollection { - new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video, + new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi1), this, false), - new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video, + new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi2), this, false), - new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.Audio | eRoutingSignalType.Video, + new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi3), this, false), - new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.Audio | eRoutingSignalType.Video, + new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Hdmi4), this, false), - new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, + new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Component1), this, false), - new RoutingInputPort(RoutingPortNames.CompositeIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, + new RoutingInputPort(RoutingPortNames.CompositeIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Video1), this, false), - new RoutingInputPort(RoutingPortNames.AntennaIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, + new RoutingInputPort(RoutingPortNames.AntennaIn, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, new Action(Antenna), this, false), }); } - /// - /// Hdmi1 method - /// + /// + /// Hdmi1 method + /// public void Hdmi1() { IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_1, IrPulseTime); } - /// - /// Hdmi2 method - /// + /// + /// Hdmi2 method + /// public void Hdmi2() { IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_2, IrPulseTime); } - /// - /// Hdmi3 method - /// + /// + /// Hdmi3 method + /// public void Hdmi3() { IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_3, IrPulseTime); } - /// - /// Hdmi4 method - /// + /// + /// Hdmi4 method + /// public void Hdmi4() { IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_4, IrPulseTime); } - /// - /// Component1 method - /// + /// + /// Component1 method + /// public void Component1() { IrPort.Pulse(IROutputStandardCommands.IROut_COMPONENT_1, IrPulseTime); } - /// - /// Video1 method - /// + /// + /// Video1 method + /// public void Video1() { IrPort.Pulse(IROutputStandardCommands.IROut_VIDEO_1, IrPulseTime); } - /// - /// Antenna method - /// + /// + /// Antenna method + /// public void Antenna() { IrPort.Pulse(IROutputStandardCommands.IROut_ANTENNA, IrPulseTime); @@ -128,31 +144,31 @@ namespace PepperDash.Essentials.Devices.Common.Displays #region IPower Members - /// - /// PowerOn method - /// - /// + /// + /// PowerOn method + /// + /// public override void PowerOn() { IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime); - _PowerIsOn = true; + _PowerIsOn = true; } - /// - /// PowerOff method - /// + /// + /// PowerOff method + /// public override void PowerOff() { - _PowerIsOn = false; + _PowerIsOn = false; IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime); } - /// - /// PowerToggle method - /// + /// + /// PowerToggle method + /// public override void PowerToggle() { - _PowerIsOn = false; + _PowerIsOn = false; IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime); } @@ -160,25 +176,25 @@ namespace PepperDash.Essentials.Devices.Common.Displays #region IBasicVolumeControls Members - /// - /// VolumeUp method - /// + /// + /// VolumeUp method + /// public void VolumeUp(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_PLUS, pressRelease); } - /// - /// VolumeDown method - /// + /// + /// VolumeDown method + /// public void VolumeDown(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_MINUS, pressRelease); } - /// - /// MuteToggle method - /// + /// + /// MuteToggle method + /// public void MuteToggle() { IrPort.Pulse(IROutputStandardCommands.IROut_MUTE, 200); @@ -190,7 +206,8 @@ namespace PepperDash.Essentials.Devices.Common.Displays { _IsWarmingUp = true; IsWarmingUpFeedback.FireUpdate(); - new CTimer(o => { + new CTimer(o => + { _IsWarmingUp = false; IsWarmingUpFeedback.FireUpdate(); }, 10000); @@ -213,13 +230,13 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// Typically called by the discovery routing algorithm. /// /// A delegate containing the input selector method to call - /// - /// ExecuteSwitch method - /// - /// + /// + /// ExecuteSwitch method + /// + /// public override void ExecuteSwitch(object inputSelector) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString()); + Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString()); Action finishSwitch = () => { @@ -246,42 +263,45 @@ namespace PepperDash.Essentials.Devices.Common.Displays #endregion - /// - /// LinkToApi method - /// - public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge); - } + /// + /// LinkToApi method + /// + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge); + } } - /// - /// Represents a BasicIrDisplayFactory - /// - public class BasicIrDisplayFactory : EssentialsDeviceFactory - { - public BasicIrDisplayFactory() - { - TypeNames = new List() { "basicirdisplay" }; - } + /// + /// Represents a BasicIrDisplayFactory + /// + public class BasicIrDisplayFactory : EssentialsDeviceFactory + { + /// + /// Initializes a new instance of the BasicIrDisplayFactory class + /// + public BasicIrDisplayFactory() + { + TypeNames = new List() { "basicirdisplay" }; + } - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BasicIrDisplay Device"); - var ir = IRPortHelper.GetIrPort(dc.Properties); - if (ir != null) - { - var display = new BasicIrDisplay(dc.Key, dc.Name, ir.Port, ir.FileName); - display.IrPulseTime = 200; // Set default pulse time for IR commands. - return display; - } + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BasicIrDisplay Device"); + var ir = IRPortHelper.GetIrPort(dc.Properties); + if (ir != null) + { + var display = new BasicIrDisplay(dc.Key, dc.Name, ir.Port, ir.FileName); + display.IrPulseTime = 200; // Set default pulse time for IR commands. + return display; + } - return null; - } - } + return null; + } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs index c94591a3..5db03a30 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/DisplayBase.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// Abstract base class for display devices that provides common display functionality /// including power control, input switching, and routing capabilities. /// - public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources + public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources, IHasFeedback { private RoutingInputPort _currentInputPort; @@ -73,13 +73,11 @@ namespace PepperDash.Essentials.Devices.Common.Displays var handler = CurrentSourceChange; - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.WillChange); + handler?.Invoke(_CurrentSourceInfo, ChangeType.WillChange); _CurrentSourceInfo = value; - if (handler != null) - handler(_CurrentSourceInfo, ChangeType.DidChange); + handler?.Invoke(_CurrentSourceInfo, ChangeType.DidChange); } } SourceListItem _CurrentSourceInfo; @@ -160,6 +158,9 @@ namespace PepperDash.Essentials.Devices.Common.Displays IsCoolingDownFeedback = new BoolFeedback("IsCoolingDown", IsCoolingDownFeedbackFunc); IsWarmingUpFeedback = new BoolFeedback("IsWarmingUp", IsWarmingUpFeedbackFunc); + Feedbacks.Add(IsCoolingDownFeedback); + Feedbacks.Add(IsWarmingUpFeedback); + InputPorts = new RoutingPortCollection(); CurrentSources = new Dictionary @@ -194,17 +195,8 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// Gets the collection of feedback objects for this display device. /// /// - public virtual FeedbackCollection Feedbacks - { - get - { - return new FeedbackCollection - { - IsCoolingDownFeedback, - IsWarmingUpFeedback - }; - } - } + public virtual FeedbackCollection Feedbacks { get; private set; } = new FeedbackCollection(); + /// /// Executes a switch to the specified input on the display device. Must be implemented by derived classes. @@ -252,47 +244,35 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// The join map configuration for the device. protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, DisplayControllerJoinMap joinMap) { - Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); - Debug.LogMessage(LogEventLevel.Information, "Linking to Display: {0}", displayDevice.Name); + this.LogDebug("Linking to Trilist {ipId}", trilist.ID.ToString("X")); + this.LogDebug("Linking to Display: {displayName}", displayDevice.Name); trilist.StringInput[joinMap.Name.JoinNumber].StringValue = displayDevice.Name; - var commMonitor = displayDevice as ICommunicationMonitor; - if (commMonitor != null) + if (displayDevice is ICommunicationMonitor commMonitor) { commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); } + // TODO: revisit this as there could be issues with this approach var inputNumber = 0; var inputKeys = new List(); - var inputNumberFeedback = new IntFeedback(() => inputNumber); + var inputNumberFeedback = new IntFeedback("inputNumber", () => inputNumber); - // Two way feedbacks - var twoWayDisplay = displayDevice as TwoWayDisplayBase; + // Add input number feedback to the device feedback collection to keep it around... + Feedbacks.Add(inputNumberFeedback); - if (twoWayDisplay != null) + // Two way feedbacks + if (displayDevice is TwoWayDisplayBase twoWayDisplay) { trilist.SetBool(joinMap.IsTwoWayDisplay.JoinNumber, true); - twoWayDisplay.CurrentInputFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Information, "CurrentInputFeedback_OutputChange {0}", a.StringValue); - + twoWayDisplay.CurrentInputFeedback.OutputChange += (o, a) => this.LogDebug("CurrentInputFeedback_OutputChange {input}", a.StringValue); inputNumberFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputSelect.JoinNumber]); - } - // Power Off - trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () => - { - inputNumber = 102; - inputNumberFeedback.FireUpdate(); - displayDevice.PowerOff(); - }); - - var twoWayDisplayDevice = displayDevice as TwoWayDisplayBase; - if (twoWayDisplayDevice != null) - { - twoWayDisplayDevice.PowerIsOnFeedback.OutputChange += (o, a) => + twoWayDisplay.PowerIsOnFeedback.OutputChange += (o, a) => { if (!a.BoolValue) { @@ -307,10 +287,18 @@ namespace PepperDash.Essentials.Devices.Common.Displays } }; - twoWayDisplayDevice.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]); - twoWayDisplayDevice.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]); + twoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]); + twoWayDisplay.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]); } + // Power Off + trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () => + { + inputNumber = 102; + inputNumberFeedback.FireUpdate(); + displayDevice.PowerOff(); + }); + // PowerOn trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () => { @@ -320,44 +308,61 @@ namespace PepperDash.Essentials.Devices.Common.Displays }); - for (int i = 0; i < displayDevice.InputPorts.Count; i++) { - if (i < joinMap.InputNamesOffset.JoinSpan) + var localindex = i; + if (localindex >= joinMap.InputNamesOffset.JoinSpan) { - inputKeys.Add(displayDevice.InputPorts[i].Key); - var tempKey = inputKeys.ElementAt(i); - trilist.SetSigTrueAction((ushort)(joinMap.InputSelectOffset.JoinNumber + i), - () => displayDevice.ExecuteSwitch(displayDevice.InputPorts[tempKey].Selector)); - Debug.LogMessage(LogEventLevel.Verbose, displayDevice, "Setting Input Select Action on Digital Join {0} to Input: {1}", - joinMap.InputSelectOffset.JoinNumber + i, displayDevice.InputPorts[tempKey].Key.ToString()); - trilist.StringInput[(ushort)(joinMap.InputNamesOffset.JoinNumber + i)].StringValue = displayDevice.InputPorts[i].Key.ToString(); + this.LogWarning("Device has {inputCount} inputs. The Join Map allows up to {joinSpan} inputs. Discarding inputs {discardStart} - {discardEnd} from bridge.", + displayDevice.InputPorts.Count, joinMap.InputNamesOffset.JoinSpan, localindex + 1, displayDevice.InputPorts.Count); + + continue; } else - Debug.LogMessage(LogEventLevel.Information, displayDevice, "Device has {0} inputs. The Join Map allows up to {1} inputs. Discarding inputs {2} - {3} from bridge.", - displayDevice.InputPorts.Count, joinMap.InputNamesOffset.JoinSpan, i + 1, displayDevice.InputPorts.Count); + { + inputKeys.Add(displayDevice.InputPorts[localindex].Key); + + var tempKey = inputKeys.ElementAt(localindex); + + trilist.SetSigTrueAction((ushort)(joinMap.InputSelectOffset.JoinNumber + localindex), () => displayDevice.ExecuteSwitch(displayDevice.InputPorts[tempKey].Selector)); + + this.LogDebug("Setting Input Select Action on Digital Join {joinNumber} to Input: {input}", joinMap.InputSelectOffset.JoinNumber + localindex, displayDevice.InputPorts[tempKey].Key); + + trilist.SetString((uint)(joinMap.InputNamesOffset.JoinNumber + localindex), displayDevice.InputPorts[localindex].Key); + } } - Debug.LogMessage(LogEventLevel.Verbose, displayDevice, "Setting Input Select Action on Analog Join {0}", joinMap.InputSelect); - trilist.SetUShortSigAction(joinMap.InputSelect.JoinNumber, (a) => + this.LogDebug("Setting Input Select Action on Analog Join {inputSelectJoin}", joinMap.InputSelect); + + trilist.SetUShortSigAction(joinMap.InputSelect.JoinNumber, (requestedInput) => { - if (a == 0) + if (requestedInput == 0) { displayDevice.PowerOff(); inputNumber = 0; + return; } - else if (a > 0 && a < displayDevice.InputPorts.Count && a != inputNumber) + + // using 1-based indexing for inputs coming from SIMPL, so need to check if the input is <= the count, not < + if (requestedInput > 0 && requestedInput <= displayDevice.InputPorts.Count && requestedInput != inputNumber) { - displayDevice.ExecuteSwitch(displayDevice.InputPorts.ElementAt(a - 1).Selector); - inputNumber = a; + displayDevice.ExecuteSwitch(displayDevice.InputPorts.ElementAt(requestedInput - 1).Selector); + + inputNumber = requestedInput; + + return; } - else if (a == 102) + + if (requestedInput == 102) { displayDevice.PowerToggle(); - + return; + } + + if (displayDevice is TwoWayDisplayBase) + { + inputNumberFeedback?.FireUpdate(); } - if (twoWayDisplay != null) - inputNumberFeedback.FireUpdate(); }); @@ -430,95 +435,4 @@ namespace PepperDash.Essentials.Devices.Common.Displays } } - - /// - /// Abstract base class for two-way display devices that provide feedback capabilities. - /// Extends DisplayBase with routing feedback and power control feedback functionality. - /// - public abstract class TwoWayDisplayBase : DisplayBase, IRoutingFeedback, IHasPowerControlWithFeedback - { - /// - /// Gets feedback for the current input selection on the display. - /// - public StringFeedback CurrentInputFeedback { get; private set; } - - /// - /// Abstract function that must be implemented by derived classes to provide the current input feedback value. - /// Must be implemented by concrete sub-classes. - /// - abstract protected Func CurrentInputFeedbackFunc { get; } - - /// - /// Gets feedback indicating whether the display is currently powered on. - /// - public BoolFeedback PowerIsOnFeedback { get; protected set; } - - /// - /// Abstract function that must be implemented by derived classes to provide the power state feedback value. - /// Must be implemented by concrete sub-classes. - /// - abstract protected Func PowerIsOnFeedbackFunc { get; } - - /// - /// Gets the default mock display instance for testing and development purposes. - /// - public static MockDisplay DefaultDisplay - { - get - { - if (_DefaultDisplay == null) - _DefaultDisplay = new MockDisplay("default", "Default Display"); - return _DefaultDisplay; - } - } - static MockDisplay _DefaultDisplay; - - /// - /// Initializes a new instance of the TwoWayDisplayBase class. - /// - /// The unique key identifier for this display device. - /// The friendly name for this display device. - public TwoWayDisplayBase(string key, string name) - : base(key, name) - { - CurrentInputFeedback = new StringFeedback(CurrentInputFeedbackFunc); - - WarmupTime = 7000; - CooldownTime = 15000; - - PowerIsOnFeedback = new BoolFeedback("PowerOnFeedback", PowerIsOnFeedbackFunc); - - Feedbacks.Add(CurrentInputFeedback); - Feedbacks.Add(PowerIsOnFeedback); - - PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; - - } - - void PowerIsOnFeedback_OutputChange(object sender, EventArgs e) - { - if (UsageTracker != null) - { - if (PowerIsOnFeedback.BoolValue) - UsageTracker.StartDeviceUsage(); - else - UsageTracker.EndDeviceUsage(); - } - } - - /// - /// Event that is raised when a numeric switch change occurs on the display. - /// - public event EventHandler NumericSwitchChange; - - /// - /// Raise an event when the status of a switch object changes. - /// - /// Arguments defined as IKeyName sender, output, input, and eRoutingSignalType - protected void OnSwitchChange(RoutingNumericEventArgs e) - { - var newEvent = NumericSwitchChange; - if (newEvent != null) newEvent(this, e); - } - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs b/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs index abc2e7f1..b4314c6b 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/InputInterfaces.cs @@ -1,38 +1,89 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; namespace PepperDash.Essentials.Devices.Displays { /// /// Defines the contract for IInputHdmi1 /// - public interface IInputHdmi1 { void InputHdmi1(); } + [Obsolete()] + public interface IInputHdmi1 + { + /// + /// Switches to HDMI 1 input + /// + void InputHdmi1(); + } + /// /// Defines the contract for IInputHdmi2 /// - public interface IInputHdmi2 { void InputHdmi2(); } + [Obsolete()] + public interface IInputHdmi2 + { + /// + /// Switches to HDMI 2 input + /// + void InputHdmi2(); + } + /// /// Defines the contract for IInputHdmi3 /// - public interface IInputHdmi3 { void InputHdmi3(); } + [Obsolete()] + public interface IInputHdmi3 + { + /// + /// Switches to HDMI 3 input + /// + void InputHdmi3(); + } + /// /// Defines the contract for IInputHdmi4 /// - public interface IInputHdmi4 { void InputHdmi4(); } + [Obsolete()] + public interface IInputHdmi4 + { + /// + /// Switches to HDMI 4 input + /// + void InputHdmi4(); + } + /// /// Defines the contract for IInputDisplayPort1 /// - public interface IInputDisplayPort1 { void InputDisplayPort1(); } + [Obsolete()] + public interface IInputDisplayPort1 + { + /// + /// Switches to DisplayPort 1 input + /// + void InputDisplayPort1(); + } + /// /// Defines the contract for IInputDisplayPort2 /// - public interface IInputDisplayPort2 { void InputDisplayPort2(); } + [Obsolete()] + public interface IInputDisplayPort2 + { + /// + /// Switches to DisplayPort 2 input + /// + void InputDisplayPort2(); + } + /// /// Defines the contract for IInputVga1 /// - public interface IInputVga1 { void InputVga1(); } + [Obsolete()] + public interface IInputVga1 + { + /// + /// Switches to VGA 1 input + /// + void InputVga1(); + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs index 976dfdc3..6f46b1a4 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplay.cs @@ -16,16 +16,19 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// Represents a MockDisplay /// public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback - { + { /// /// Gets or sets the Inputs /// public ISelectableItems Inputs { get; private set; } - bool _PowerIsOn; - bool _IsWarmingUp; - bool _IsCoolingDown; + bool _PowerIsOn; + bool _IsWarmingUp; + bool _IsCoolingDown; + /// + /// Gets the power is on feedback function + /// protected override Func PowerIsOnFeedbackFunc { get @@ -34,8 +37,12 @@ namespace PepperDash.Essentials.Devices.Common.Displays { return _PowerIsOn; }; - } } - protected override Func IsCoolingDownFeedbackFunc + } + } + /// + /// Gets the is cooling down feedback function + /// + protected override Func IsCoolingDownFeedbackFunc { get { @@ -45,7 +52,10 @@ namespace PepperDash.Essentials.Devices.Common.Displays }; } } - protected override Func IsWarmingUpFeedbackFunc + /// + /// Gets the is warming up feedback function + /// + protected override Func IsWarmingUpFeedbackFunc { get { @@ -55,120 +65,128 @@ namespace PepperDash.Essentials.Devices.Common.Displays }; } } + /// + /// Gets the current input feedback function + /// protected override Func CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } } int VolumeHeldRepeatInterval = 200; ushort VolumeInterval = 655; - ushort _FakeVolumeLevel = 31768; - bool _IsMuted; + ushort _FakeVolumeLevel = 31768; + bool _IsMuted; - public MockDisplay(string key, string name) - : base(key, name) - { + /// + /// Initializes a new instance of the MockDisplay class + /// + /// The device key + /// The device name + public MockDisplay(string key, string name) + : base(key, name) + { Inputs = new MockDisplayInputs { Items = new Dictionary - { - { "HDMI1", new MockDisplayInput ( "HDMI1", "HDMI 1",this ) }, - { "HDMI2", new MockDisplayInput ("HDMI2", "HDMI 2",this ) }, - { "HDMI3", new MockDisplayInput ("HDMI3", "HDMI 3",this ) }, - { "HDMI4", new MockDisplayInput ("HDMI4", "HDMI 4",this )}, - { "DP", new MockDisplayInput ("DP", "DisplayPort", this ) } - } + { + { "HDMI1", new MockDisplayInput ( "HDMI1", "HDMI 1",this ) }, + { "HDMI2", new MockDisplayInput ("HDMI2", "HDMI 2",this ) }, + { "HDMI3", new MockDisplayInput ("HDMI3", "HDMI 3",this ) }, + { "HDMI4", new MockDisplayInput ("HDMI4", "HDMI 4",this )}, + { "DP", new MockDisplayInput ("DP", "DisplayPort", this ) } + } }; - Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate(); - - var hdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, - eRoutingPortConnectionType.Hdmi, "HDMI1", this); - var hdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, - eRoutingPortConnectionType.Hdmi, "HDMI2", this); - var hdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo, - eRoutingPortConnectionType.Hdmi, "HDMI3", this); - var hdmiIn4 = new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo, - eRoutingPortConnectionType.Hdmi, "HDMI4", this); - var dpIn = new RoutingInputPort(RoutingPortNames.DisplayPortIn, eRoutingSignalType.AudioVideo, - eRoutingPortConnectionType.DisplayPort, "DP", this); - InputPorts.AddRange(new[] { hdmiIn1, hdmiIn2, hdmiIn3, hdmiIn4, dpIn }); + Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate(); - VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; }); - MuteFeedback = new BoolFeedback("MuteOn", () => _IsMuted); + var hdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, + eRoutingPortConnectionType.Hdmi, "HDMI1", this); + var hdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, + eRoutingPortConnectionType.Hdmi, "HDMI2", this); + var hdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo, + eRoutingPortConnectionType.Hdmi, "HDMI3", this); + var hdmiIn4 = new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo, + eRoutingPortConnectionType.Hdmi, "HDMI4", this); + var dpIn = new RoutingInputPort(RoutingPortNames.DisplayPortIn, eRoutingSignalType.AudioVideo, + eRoutingPortConnectionType.DisplayPort, "DP", this); + InputPorts.AddRange(new[] { hdmiIn1, hdmiIn2, hdmiIn3, hdmiIn4, dpIn }); + + VolumeLevelFeedback = new IntFeedback("volume", () => { return _FakeVolumeLevel; }); + MuteFeedback = new BoolFeedback("muteOn", () => _IsMuted); WarmupTime = 10000; CooldownTime = 10000; - } + } - /// - /// PowerOn method - /// - /// - public override void PowerOn() - { - if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) - { - _IsWarmingUp = true; - IsWarmingUpFeedback.InvokeFireUpdate(); - // Fake power-up cycle - WarmupTimer = new CTimer(o => - { - _IsWarmingUp = false; - _PowerIsOn = true; - IsWarmingUpFeedback.InvokeFireUpdate(); - PowerIsOnFeedback.InvokeFireUpdate(); - }, WarmupTime); - } - } + /// + /// PowerOn method + /// + /// + public override void PowerOn() + { + if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) + { + _IsWarmingUp = true; + IsWarmingUpFeedback.InvokeFireUpdate(); + // Fake power-up cycle + WarmupTimer = new CTimer(o => + { + _IsWarmingUp = false; + _PowerIsOn = true; + IsWarmingUpFeedback.InvokeFireUpdate(); + PowerIsOnFeedback.InvokeFireUpdate(); + }, WarmupTime); + } + } - /// - /// PowerOff method - /// - /// - public override void PowerOff() - { - // If a display has unreliable-power off feedback, just override this and - // remove this check. - if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) - { - _IsCoolingDown = true; - IsCoolingDownFeedback.InvokeFireUpdate(); - // Fake cool-down cycle - CooldownTimer = new CTimer(o => - { - Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this); - _IsCoolingDown = false; - IsCoolingDownFeedback.InvokeFireUpdate(); + /// + /// PowerOff method + /// + /// + public override void PowerOff() + { + // If a display has unreliable-power off feedback, just override this and + // remove this check. + if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) + { + _IsCoolingDown = true; + IsCoolingDownFeedback.InvokeFireUpdate(); + // Fake cool-down cycle + CooldownTimer = new CTimer(o => + { + Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this); + _IsCoolingDown = false; + IsCoolingDownFeedback.InvokeFireUpdate(); _PowerIsOn = false; PowerIsOnFeedback.InvokeFireUpdate(); - }, CooldownTime); - } - } - - /// - /// PowerToggle method - /// - /// - public override void PowerToggle() - { - if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue) - PowerOff(); - else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue) - PowerOn(); - } + }, CooldownTime); + } + } - /// - /// ExecuteSwitch method - /// - /// - public override void ExecuteSwitch(object selector) - { + /// + /// PowerToggle method + /// + /// + public override void PowerToggle() + { + if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue) + PowerOff(); + else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue) + PowerOn(); + } + + /// + /// ExecuteSwitch method + /// + /// + public override void ExecuteSwitch(object selector) + { try { Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector); - if (!_PowerIsOn) - { - PowerOn(); - } + if (!_PowerIsOn) + { + PowerOn(); + } if (!Inputs.Items.TryGetValue(selector.ToString(), out var input)) return; @@ -184,13 +202,14 @@ namespace PepperDash.Essentials.Devices.Common.Displays if (inputPort == null) { - Debug.LogMessage(LogEventLevel.Verbose, "Unable to find input port for selector {selector}", this, selector); + Debug.LogMessage(LogEventLevel.Verbose, "Unable to find input port for selector {selector}", this, selector); return; } Debug.LogMessage(LogEventLevel.Verbose, "Setting current input port to {inputPort}", this, inputPort); CurrentInputPort = inputPort; - } catch (Exception ex) + } + catch (Exception ex) { Debug.LogMessage(ex, "Error making switch: {Exception}", this, ex); } @@ -201,14 +220,14 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// public void SetInput(string selector) { - ISelectableItem currentInput = null; + ISelectableItem currentInput = null; + + try + { + currentInput = Inputs.Items.SingleOrDefault(Inputs => Inputs.Value.IsSelected).Value; + } + catch { } - try - { - currentInput = Inputs.Items.SingleOrDefault(Inputs => Inputs.Value.IsSelected).Value; - } - catch { } - if (currentInput != null) { @@ -216,12 +235,12 @@ namespace PepperDash.Essentials.Devices.Common.Displays currentInput.IsSelected = false; } - if (!Inputs.Items.TryGetValue(selector, out var input)) + if (!Inputs.Items.TryGetValue(selector, out var input)) return; - input.IsSelected = true; + input.IsSelected = true; - Inputs.CurrentItem = selector; + Inputs.CurrentItem = selector; } @@ -232,37 +251,37 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// public IntFeedback VolumeLevelFeedback { get; private set; } - /// - /// SetVolume method - /// - public void SetVolume(ushort level) - { - _FakeVolumeLevel = level; - VolumeLevelFeedback.InvokeFireUpdate(); - } + /// + /// SetVolume method + /// + public void SetVolume(ushort level) + { + _FakeVolumeLevel = level; + VolumeLevelFeedback.InvokeFireUpdate(); + } - /// - /// MuteOn method - /// - public void MuteOn() - { - _IsMuted = true; - MuteFeedback.InvokeFireUpdate(); - } + /// + /// MuteOn method + /// + public void MuteOn() + { + _IsMuted = true; + MuteFeedback.InvokeFireUpdate(); + } - /// - /// MuteOff method - /// - public void MuteOff() - { - _IsMuted = false; - MuteFeedback.InvokeFireUpdate(); - } + /// + /// MuteOff method + /// + public void MuteOff() + { + _IsMuted = false; + MuteFeedback.InvokeFireUpdate(); + } - /// - /// Gets or sets the MuteFeedback - /// - public BoolFeedback MuteFeedback { get; private set; } + /// + /// Gets or sets the MuteFeedback + /// + public BoolFeedback MuteFeedback { get; private set; } #endregion @@ -273,74 +292,77 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// VolumeUp method /// public void VolumeUp(bool pressRelease) - { + { //while (pressRelease) //{ - Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease); - if (pressRelease) - { - var newLevel = _FakeVolumeLevel + VolumeInterval; - SetVolume((ushort)newLevel); - CrestronEnvironment.Sleep(VolumeHeldRepeatInterval); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease); + if (pressRelease) + { + var newLevel = _FakeVolumeLevel + VolumeInterval; + SetVolume((ushort)newLevel); + CrestronEnvironment.Sleep(VolumeHeldRepeatInterval); + } //} - } + } - /// - /// VolumeDown method - /// - public void VolumeDown(bool pressRelease) - { + /// + /// VolumeDown method + /// + public void VolumeDown(bool pressRelease) + { //while (pressRelease) //{ - Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease); - if (pressRelease) - { - var newLevel = _FakeVolumeLevel - VolumeInterval; - SetVolume((ushort)newLevel); - CrestronEnvironment.Sleep(VolumeHeldRepeatInterval); - } + Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease); + if (pressRelease) + { + var newLevel = _FakeVolumeLevel - VolumeInterval; + SetVolume((ushort)newLevel); + CrestronEnvironment.Sleep(VolumeHeldRepeatInterval); + } //} - } + } - /// - /// MuteToggle method - /// - public void MuteToggle() - { - _IsMuted = !_IsMuted; - MuteFeedback.InvokeFireUpdate(); - } + /// + /// MuteToggle method + /// + public void MuteToggle() + { + _IsMuted = !_IsMuted; + MuteFeedback.InvokeFireUpdate(); + } - #endregion + #endregion - /// - /// LinkToApi method - /// - public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge); - } + /// + /// LinkToApi method + /// + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge); + } } - /// - /// Represents a MockDisplayFactory - /// - public class MockDisplayFactory : EssentialsDeviceFactory - { - public MockDisplayFactory() - { - TypeNames = new List() { "mockdisplay" , "mockdisplay2" }; - } + /// + /// Represents a MockDisplayFactory + /// + public class MockDisplayFactory : EssentialsDeviceFactory + { + /// + /// Initializes a new instance of the MockDisplayFactory class + /// + public MockDisplayFactory() + { + TypeNames = new List() { "mockdisplay", "mockdisplay2" }; + } - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device"); - return new MockDisplay(dc.Key, dc.Name); - } - } + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device"); + return new MockDisplay(dc.Key, dc.Name); + } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs index 5b2ee2e2..b30963ac 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/MockDisplayInputs.cs @@ -1,10 +1,6 @@ -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System; +using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials.Devices.Common.Displays { @@ -15,6 +11,9 @@ namespace PepperDash.Essentials.Devices.Common.Displays { private Dictionary _items; + /// + /// Gets or sets the collection of selectable items + /// public Dictionary Items { get @@ -34,8 +33,11 @@ namespace PepperDash.Essentials.Devices.Common.Displays private string _currentItem; + /// + /// Gets or sets the currently selected item + /// public string CurrentItem - { + { get { return _currentItem; @@ -51,7 +53,13 @@ namespace PepperDash.Essentials.Devices.Common.Displays } } + /// + /// Occurs when the items collection is updated + /// public event EventHandler ItemsUpdated; + /// + /// Occurs when the current item changes + /// public event EventHandler CurrentItemChanged; } @@ -63,7 +71,10 @@ namespace PepperDash.Essentials.Devices.Common.Displays private MockDisplay _parent; private bool _isSelected; - + + /// + /// Gets or sets a value indicating whether this input is selected + /// public bool IsSelected { get @@ -91,8 +102,17 @@ namespace PepperDash.Essentials.Devices.Common.Displays /// public string Key { get; set; } + /// + /// Occurs when this item is updated + /// public event EventHandler ItemUpdated; + /// + /// Initializes a new instance of the MockDisplayInput class + /// + /// The input key + /// The input name + /// The parent mock display public MockDisplayInput(string key, string name, MockDisplay parent) { Key = key; @@ -107,7 +127,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays { if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn(); - foreach(var input in _parent.Inputs.Items) + foreach (var input in _parent.Inputs.Items) { input.Value.IsSelected = input.Key == this.Key; } diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs index 204fee42..9163c2a3 100644 --- a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftController.cs @@ -1,14 +1,11 @@ using System; using System.Collections.Generic; using Crestron.SimplSharp; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.CrestronIO; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using PepperDash.Essentials.Devices.Common; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Shades @@ -28,6 +25,9 @@ namespace PepperDash.Essentials.Devices.Common.Shades ISwitchedOutput LowerRelay; ISwitchedOutput LatchedRelay; + /// + /// Gets or sets the InUpPosition + /// public bool InUpPosition { get { return _isInUpPosition; } @@ -41,10 +41,12 @@ namespace PepperDash.Essentials.Devices.Common.Shades } private bool _isInUpPosition { get; set; } + /// /// Gets or sets the Type /// public eScreenLiftControlType Type { get; private set; } + /// /// Gets or sets the Mode /// @@ -54,13 +56,20 @@ namespace PepperDash.Essentials.Devices.Common.Shades /// Gets or sets the DisplayDeviceKey /// public string DisplayDeviceKey { get; private set; } + /// /// Gets or sets the IsInUpPosition /// public BoolFeedback IsInUpPosition { get; private set; } + /// + /// Event that fires when the position changes + /// public event EventHandler PositionChanged; + /// + /// Constructor for ScreenLiftController + /// public ScreenLiftController(string key, string name, ScreenLiftControllerConfigProperties config) : base(key, name) { @@ -69,7 +78,7 @@ namespace PepperDash.Essentials.Devices.Common.Shades Mode = Config.Mode; Type = Config.Type; - IsInUpPosition = new BoolFeedback(() => _isInUpPosition); + IsInUpPosition = new BoolFeedback("isInUpPosition", () => _isInUpPosition); switch (Mode) { @@ -206,14 +215,14 @@ namespace PepperDash.Essentials.Devices.Common.Shades /// /// Attempts to get the port on teh specified device from config /// - /// + /// /// ISwitchedOutput GetSwitchedOutputFromDevice(string relayKey) { var portDevice = DeviceManager.GetDeviceForKey(relayKey); if (portDevice != null) { - return (portDevice as ISwitchedOutput); + return portDevice as ISwitchedOutput; } else { @@ -238,58 +247,14 @@ namespace PepperDash.Essentials.Devices.Common.Shades } - /// - /// Represents a ScreenLiftControllerConfigProperties - /// - public class ScreenLiftControllerConfigProperties - { - [JsonProperty("displayDeviceKey")] - /// - /// Gets or sets the DisplayDeviceKey - /// - public string DisplayDeviceKey { get; set; } - - [JsonProperty("type")] - [JsonConverter(typeof(StringEnumConverter))] - /// - /// Gets or sets the Type - /// - public eScreenLiftControlType Type { get; set; } - - [JsonProperty("mode")] - [JsonConverter(typeof(StringEnumConverter))] - /// - /// Gets or sets the Mode - /// - public eScreenLiftControlMode Mode { get; set; } - - [JsonProperty("relays")] - public Dictionary Relays { get; set; } - - } - /// - /// Represents a ScreenLiftRelaysConfig - /// - public class ScreenLiftRelaysConfig - { - [JsonProperty("deviceKey")] - /// - /// Gets or sets the DeviceKey - /// - public string DeviceKey { get; set; } - - [JsonProperty("pulseTimeInMs")] - /// - /// Gets or sets the PulseTimeInMs - /// - public int PulseTimeInMs { get; set; } - } - /// /// Represents a ScreenLiftControllerFactory /// public class ScreenLiftControllerFactory : EssentialsDeviceFactory { + /// + /// Constructor for ScreenLiftControllerFactory + /// public ScreenLiftControllerFactory() { TypeNames = new List() { "screenliftcontroller" }; @@ -307,13 +272,4 @@ namespace PepperDash.Essentials.Devices.Common.Shades return new ScreenLiftController(dc.Key, dc.Name, props); } } - - /// - /// Enumeration of eScreenLiftControlMode values - /// - public enum eScreenLiftControlMode - { - momentary, - latched - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftControllerConfigProperties.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftControllerConfigProperties.cs new file mode 100644 index 00000000..9de1faa0 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftControllerConfigProperties.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; + +namespace PepperDash.Essentials.Devices.Common.Shades +{ + /// + /// Represents a ScreenLiftControllerConfigProperties + /// + public class ScreenLiftControllerConfigProperties + { + + /// + /// Gets or sets the DisplayDeviceKey + /// + [JsonProperty("displayDeviceKey")] + public string DisplayDeviceKey { get; set; } + + /// + /// Gets or sets the Type + /// + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public eScreenLiftControlType Type { get; set; } + + /// + /// Gets or sets the Mode + /// + [JsonProperty("mode")] + [JsonConverter(typeof(StringEnumConverter))] + public eScreenLiftControlMode Mode { get; set; } + + /// + /// Gets or sets the Relays + /// + [JsonProperty("relays")] + public Dictionary Relays { get; set; } + + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs new file mode 100644 index 00000000..4de9eb25 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Displays/ScreenLiftRelaysConfig.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.Shades +{ + /// + /// Represents a ScreenLiftRelaysConfig + /// + public class ScreenLiftRelaysConfig + { + /// + /// Gets or sets the DeviceKey + /// + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + /// + /// Gets or sets the PulseTimeInMs + /// + [JsonProperty("pulseTimeInMs")] + public int PulseTimeInMs { get; set; } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/TwoWayDisplayBase.cs b/src/PepperDash.Essentials.Devices.Common/Displays/TwoWayDisplayBase.cs new file mode 100644 index 00000000..226d4bbe --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Displays/TwoWayDisplayBase.cs @@ -0,0 +1,95 @@ +using System; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.Displays +{ + /// + /// Abstract base class for two-way display devices that provide feedback capabilities. + /// Extends DisplayBase with routing feedback and power control feedback functionality. + /// + public abstract class TwoWayDisplayBase : DisplayBase, IRoutingFeedback, IHasPowerControlWithFeedback + { + /// + /// Gets feedback for the current input selection on the display. + /// + public StringFeedback CurrentInputFeedback { get; private set; } + + /// + /// Abstract function that must be implemented by derived classes to provide the current input feedback value. + /// Must be implemented by concrete sub-classes. + /// + abstract protected Func CurrentInputFeedbackFunc { get; } + + /// + /// Gets feedback indicating whether the display is currently powered on. + /// + public BoolFeedback PowerIsOnFeedback { get; protected set; } + + /// + /// Abstract function that must be implemented by derived classes to provide the power state feedback value. + /// Must be implemented by concrete sub-classes. + /// + abstract protected Func PowerIsOnFeedbackFunc { get; } + + /// + /// Gets the default mock display instance for testing and development purposes. + /// + public static MockDisplay DefaultDisplay + { + get + { + if (_DefaultDisplay == null) + _DefaultDisplay = new MockDisplay("default", "Default Display"); + return _DefaultDisplay; + } + } + static MockDisplay _DefaultDisplay; + + /// + /// Initializes a new instance of the TwoWayDisplayBase class. + /// + /// The unique key identifier for this display device. + /// The friendly name for this display device. + public TwoWayDisplayBase(string key, string name) + : base(key, name) + { + CurrentInputFeedback = new StringFeedback("currentInput", CurrentInputFeedbackFunc); + + WarmupTime = 7000; + CooldownTime = 15000; + + PowerIsOnFeedback = new BoolFeedback("PowerOnFeedback", PowerIsOnFeedbackFunc); + + Feedbacks.Add(CurrentInputFeedback); + Feedbacks.Add(PowerIsOnFeedback); + + PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; + + } + + void PowerIsOnFeedback_OutputChange(object sender, EventArgs e) + { + if (UsageTracker != null) + { + if (PowerIsOnFeedback.BoolValue) + UsageTracker.StartDeviceUsage(); + else + UsageTracker.EndDeviceUsage(); + } + } + + /// + /// Event that is raised when a numeric switch change occurs on the display. + /// + public event EventHandler NumericSwitchChange; + + /// + /// Raise an event when the status of a switch object changes. + /// + /// Arguments defined as IKeyName sender, output, input, and eRoutingSignalType + protected void OnSwitchChange(RoutingNumericEventArgs e) + { + NumericSwitchChange?.Invoke(this, e); + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Displays/eScreenLiftControlMode.cs b/src/PepperDash.Essentials.Devices.Common/Displays/eScreenLiftControlMode.cs new file mode 100644 index 00000000..8114ac26 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Displays/eScreenLiftControlMode.cs @@ -0,0 +1,17 @@ +namespace PepperDash.Essentials.Devices.Common.Shades +{ + /// + /// Enumeration of eScreenLiftControlMode values + /// + public enum eScreenLiftControlMode + { + /// + /// Momentary control mode for screen lift + /// + momentary, + /// + /// Latched control mode for screen lift + /// + latched + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs index 748b48bb..a44eb012 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSink.cs @@ -1,9 +1,8 @@ -using PepperDash.Core; +using System.Collections.Generic; +using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using Serilog.Events; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.Devices.Common.Generic { @@ -12,11 +11,16 @@ namespace PepperDash.Essentials.Devices.Common.Generic /// public class GenericSink : EssentialsDevice, IRoutingSinkWithInputPort { + /// + /// Initializes a new instance of the GenericSink class + /// + /// The device key + /// The device name public GenericSink(string key, string name) : base(key, name) { InputPorts = new RoutingPortCollection(); - var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); + var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); InputPorts.Add(inputPort); } @@ -35,10 +39,12 @@ namespace PepperDash.Essentials.Devices.Common.Generic /// /// Gets or sets the CurrentSourceInfo /// - public SourceListItem CurrentSourceInfo { + public SourceListItem CurrentSourceInfo + { get => _currentSource; - set { - if(value == _currentSource) + set + { + if (value == _currentSource) { return; } @@ -51,8 +57,14 @@ namespace PepperDash.Essentials.Devices.Common.Generic } } + /// + /// Gets the current input port + /// public RoutingInputPort CurrentInputPort => InputPorts[0]; + /// + /// Event fired when the current source changes + /// public event SourceInfoChangeHandler CurrentSourceChange; } @@ -61,6 +73,9 @@ namespace PepperDash.Essentials.Devices.Common.Generic /// public class GenericSinkFactory : EssentialsDeviceFactory { + /// + /// Initializes a new instance of the GenericSinkFactory class + /// public GenericSinkFactory() { TypeNames = new List() { "genericsink", "genericdestination" }; diff --git a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs index 6cf359e8..3d0f1304 100644 --- a/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs +++ b/src/PepperDash.Essentials.Devices.Common/Generic/GenericSource.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DeviceSupport; +using System.Collections.Generic; using PepperDash.Core; using PepperDash.Essentials.Core; @@ -13,38 +7,43 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { - /// - /// Represents a GenericSource - /// - public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking - { + /// + /// Represents a GenericSource + /// + public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking + { - /// - /// Gets or sets the DisplayUiType - /// - public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } } + /// + /// Gets or sets the DisplayUiType + /// + public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } } + /// + /// Initializes a new instance of the GenericSource class + /// + /// The device key + /// The device name public GenericSource(string key, string name) - : base(key, name) - { + : base(key, name) + { - AnyOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.Hdmi, null, this); - OutputPorts = new RoutingPortCollection { AnyOut }; - } + AnyOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.Hdmi, null, this); + OutputPorts = new RoutingPortCollection { AnyOut }; + } - #region IRoutingOutputs Members + #region IRoutingOutputs Members - /// - /// Gets or sets the AnyOut - /// - public RoutingOutputPort AnyOut { get; private set; } - /// - /// Gets or sets the OutputPorts - /// - public RoutingPortCollection OutputPorts { get; private set; } + /// + /// Gets or sets the AnyOut + /// + public RoutingOutputPort AnyOut { get; private set; } + /// + /// Gets or sets the OutputPorts + /// + public RoutingPortCollection OutputPorts { get; private set; } - #endregion + #endregion #region IUsageTracking Members @@ -54,13 +53,16 @@ namespace PepperDash.Essentials.Devices.Common public UsageTracking UsageTracker { get; set; } #endregion - } + } /// /// Represents a GenericSourceFactory /// public class GenericSourceFactory : EssentialsDeviceFactory { + /// + /// Initializes a new instance of the GenericSourceFactory class + /// public GenericSourceFactory() { TypeNames = new List() { "genericsource" }; diff --git a/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs b/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs index d98d8804..9dd3b816 100644 --- a/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Lighting/LightingBase.cs @@ -3,9 +3,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; @@ -16,134 +13,165 @@ using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.Lighting { - public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes - { - #region ILightingScenes Members - - public event EventHandler LightingSceneChange; - - /// - /// Gets or sets the LightingScenes - /// - public List LightingScenes { get; protected set; } - - /// - /// Gets or sets the CurrentLightingScene - /// - public LightingScene CurrentLightingScene { get; protected set; } - /// - /// Gets or sets the CurrentLightingSceneFeedback + /// Base class for lighting devices that support scenes /// - public IntFeedback CurrentLightingSceneFeedback { get; protected set; } + public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes + { + #region ILightingScenes Members - #endregion + /// + /// Event fired when lighting scene changes + /// + public event EventHandler LightingSceneChange; - protected LightingBase(string key, string name) - : base(key, name) - { - LightingScenes = new List(); + /// + /// Gets or sets the LightingScenes + /// + public List LightingScenes { get; protected set; } - CurrentLightingScene = new LightingScene(); - //CurrentLightingSceneFeedback = new IntFeedback(() => { return int.Parse(this.CurrentLightingScene.ID); }); - } + /// + /// Gets or sets the CurrentLightingScene + /// + public LightingScene CurrentLightingScene { get; protected set; } - public abstract void SelectScene(LightingScene scene); + /// + /// Gets or sets the CurrentLightingSceneFeedback + /// + public IntFeedback CurrentLightingSceneFeedback { get; protected set; } - /// - /// SimulateSceneSelect method - /// - public void SimulateSceneSelect(string sceneName) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Simulating selection of scene '{0}'", sceneName); + #endregion - var scene = LightingScenes.FirstOrDefault(s => s.Name.Equals(sceneName)); + /// + /// Initializes a new instance of the LightingBase class + /// + /// The device key + /// The device name + protected LightingBase(string key, string name) + : base(key, name) + { + LightingScenes = new List(); - if (scene != null) - { - CurrentLightingScene = scene; - OnLightingSceneChange(); - } - } + CurrentLightingScene = new LightingScene(); + //CurrentLightingSceneFeedback = new IntFeedback(() => { return int.Parse(this.CurrentLightingScene.ID); }); + } - /// - /// Sets the IsActive property on each scene and fires the LightingSceneChange event - /// - protected void OnLightingSceneChange() - { - foreach (var scene in LightingScenes) - { - if (scene == CurrentLightingScene) - scene.IsActive = true; - - else - scene.IsActive = false; - } - LightingSceneChange?.Invoke(this, new LightingSceneChangeEventArgs(CurrentLightingScene)); - } + /// + /// Selects the specified lighting scene + /// + /// The lighting scene to select + public abstract void SelectScene(LightingScene scene); - protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, uint joinStart, - string joinMapKey, EiscApiAdvanced bridge) - { - var joinMap = new GenericLightingJoinMap(joinStart); + /// + /// SimulateSceneSelect method + /// + public void SimulateSceneSelect(string sceneName) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Simulating selection of scene '{0}'", sceneName); - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + var scene = LightingScenes.FirstOrDefault(s => s.Name.Equals(sceneName)); - if (!string.IsNullOrEmpty(joinMapSerialized)) - joinMap = JsonConvert.DeserializeObject(joinMapSerialized); - - if (bridge != null) - { - bridge.AddJoinMap(Key, joinMap); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); - } - - return LinkLightingToApi(lightingDevice, trilist, joinMap); - } - - protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap) + if (scene != null) { - Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + CurrentLightingScene = scene; + OnLightingSceneChange(); + } + } - Debug.LogMessage(LogEventLevel.Information, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); + /// + /// Sets the IsActive property on each scene and fires the LightingSceneChange event + /// + protected void OnLightingSceneChange() + { + foreach (var scene in LightingScenes) + { + if (scene == CurrentLightingScene) + scene.IsActive = true; - // GenericLighitng Actions & FeedBack - trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); + else + scene.IsActive = false; + } + LightingSceneChange?.Invoke(this, new LightingSceneChangeEventArgs(CurrentLightingScene)); + } - var sceneIndex = 0; + /// + /// Links the lighting device to API with join map configuration + /// + /// The lighting device to link + /// The trilist to link to + /// The starting join number + /// The join map key + /// The EISC API bridge + /// The configured join map + protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, uint joinStart, + string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = new GenericLightingJoinMap(joinStart); + + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!string.IsNullOrEmpty(joinMapSerialized)) + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + + if (bridge != null) + { + bridge.AddJoinMap(Key, joinMap); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); + } + + return LinkLightingToApi(lightingDevice, trilist, joinMap); + } + + /// + /// Links the lighting device to API using an existing join map + /// + /// The lighting device to link + /// The trilist to link to + /// The join map to use + /// The join map used for linking + protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap) + { + Debug.LogMessage(LogEventLevel.Debug, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + + Debug.LogMessage(LogEventLevel.Information, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); + + // GenericLighitng Actions & FeedBack + trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); + + var sceneIndex = 0; + foreach (var scene in lightingDevice.LightingScenes) + { + var index = sceneIndex; + + trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index])); + scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]); + trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; + trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; + + sceneIndex++; + } + + trilist.OnlineStatusChange += (sender, args) => + { + if (!args.DeviceOnLine) return; + + sceneIndex = 0; foreach (var scene in lightingDevice.LightingScenes) { var index = sceneIndex; - trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index])); - scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]); trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; + scene.IsActiveFeedback.FireUpdate(); sceneIndex++; } + }; - trilist.OnlineStatusChange += (sender, args) => - { - if (!args.DeviceOnLine) return; - - sceneIndex = 0; - foreach (var scene in lightingDevice.LightingScenes) - { - var index = sceneIndex; - - trilist.StringInput[(uint) (joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; - trilist.BooleanInput[(uint) (joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true; - scene.IsActiveFeedback.FireUpdate(); - - sceneIndex++; - } - }; - - return joinMap; - } + return joinMap; } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs index 6e5e3797..ecce473e 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleSpaceRoom.cs @@ -9,10 +9,20 @@ namespace PepperDash.Essentials.Devices.Common.Room public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IHasDefaultDisplay, IHasCurrentVolumeControls, IRoomOccupancy, IEmergency, IMicrophonePrivacy { + /// + /// Gets whether to exclude this room from global functions + /// bool ExcludeFromGlobalFunctions { get; } + /// + /// Runs the route action for the given routeKey and sourceListKey + /// + /// The route key void RunRouteAction(string routeKey); + /// + /// Gets the PropertiesConfig + /// EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs index 98d01956..5547f595 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsHuddleVtc1Room.cs @@ -12,18 +12,40 @@ namespace PepperDash.Essentials.Devices.Common.Room public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback, IRoomOccupancy, IEmergency, IMicrophonePrivacy { + /// + /// Gets the PropertiesConfig + /// EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } + /// + /// Gets whether to exclude this room from global functions + /// bool ExcludeFromGlobalFunctions { get; } + /// + /// Runs the route action for the given routeKey and sourceListKey + /// + /// The route key void RunRouteAction(string routeKey); + /// + /// Gets the ScheduleSource + /// IHasScheduleAwareness ScheduleSource { get; } + /// + /// Gets the InCallFeedback + /// new BoolFeedback InCallFeedback { get; } + /// + /// Gets the PrivacyModeIsOnFeedback + /// new BoolFeedback PrivacyModeIsOnFeedback { get; } + /// + /// Gets the DefaultCodecRouteString + /// string DefaultCodecRouteString { get; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs index d536242e..e45be6e0 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsRoomPropertiesConfig.cs @@ -1,9 +1,4 @@ using PepperDash.Essentials.Room.Config; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace PepperDash.Essentials.Devices.Common.Room { @@ -12,6 +7,9 @@ namespace PepperDash.Essentials.Devices.Common.Room /// public interface IEssentialsRoomPropertiesConfig { + /// + /// Gets the PropertiesConfig + /// EssentialsRoomPropertiesConfig PropertiesConfig { get; } } } diff --git a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs index e651011a..9301f37d 100644 --- a/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs +++ b/src/PepperDash.Essentials.Devices.Common/Room/IEssentialsTechRoom.cs @@ -1,9 +1,9 @@ -using PepperDash.Essentials.Core; +using System.Collections.Generic; +using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Devices.Common.Displays; using PepperDash.Essentials.Room.Config; -using System.Collections.Generic; -using TwoWayDisplayBase = PepperDash.Essentials.Devices.Common.Displays.TwoWayDisplayBase; namespace PepperDash.Essentials.Devices.Common.Room @@ -11,15 +11,31 @@ namespace PepperDash.Essentials.Devices.Common.Room /// /// Defines the contract for IEssentialsTechRoom /// - public interface IEssentialsTechRoom:IEssentialsRoom, ITvPresetsProvider,IBridgeAdvanced,IRunDirectRouteAction + public interface IEssentialsTechRoom : IEssentialsRoom, ITvPresetsProvider, IBridgeAdvanced, IRunDirectRouteAction { + /// + /// Gets the PropertiesConfig + /// EssentialsTechRoomConfig PropertiesConfig { get; } + + /// + /// Gets the Tuners + /// Dictionary Tuners { get; } + /// + /// Gets the Displays + /// Dictionary Displays { get; } + /// + /// Powers on the room + /// void RoomPowerOn(); + /// + /// Powers off the room + /// void RoomPowerOff(); } } diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs index db21a03a..7d49b9b7 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBase.cs @@ -1,38 +1,31 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Presets; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Presets; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { - [Description("Wrapper class for an IR Set Top Box")] /// /// Represents a IRSetTopBoxBase + /// Wrapper class for an IR Set Top Box /// + [Description("Wrapper class for an IR Set Top Box")] public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IRoutingOutputs, IUsageTracking, IHasPowerControl, ITvPresetsProvider - { - /// - /// Gets or sets the IrPort - /// + { + /// + /// Gets or sets the IrPort + /// public IrOutputPortController IrPort { get; private set; } - /// - /// Gets or sets the DisplayUiType - /// - public uint DisplayUiType { get { return DisplayUiConstants.TypeDirecTv; } } + /// + /// Gets or sets the DisplayUiType + /// + public uint DisplayUiType { get { return DisplayUiConstants.TypeDirecTv; } } /// /// Gets or sets the IrPulseTime /// @@ -60,11 +53,18 @@ namespace PepperDash.Essentials.Devices.Common /// public DevicePresetsModel TvPresets { get; private set; } - public IRSetTopBoxBase(string key, string name, IrOutputPortController portCont, + /// + /// Initializes a new instance of the class + /// + /// The unique identifier for the device + /// The name of the device + /// The IR output port controller + /// The properties configuration + public IRSetTopBoxBase(string key, string name, IrOutputPortController portCont, SetTopBoxPropertiesConfig props) - : base(key, name) - { - IrPort = portCont; + : base(key, name) + { + IrPort = portCont; IrPulseTime = 200; if (props.IrPulseTime > 0) @@ -72,424 +72,433 @@ namespace PepperDash.Essentials.Devices.Common IrPulseTime = (ushort)props.IrPulseTime; } - DeviceManager.AddDevice(portCont); + DeviceManager.AddDevice(portCont); HasPresets = props.HasPresets; HasDvr = props.HasDvr; HasDpad = props.HasDpad; HasNumeric = props.HasNumeric; - HasKeypadAccessoryButton1 = true; - KeypadAccessoryButton1Command = "Dash"; - KeypadAccessoryButton1Label = "-"; - - HasKeypadAccessoryButton2 = true; - KeypadAccessoryButton2Command = "KEYPAD_ENTER"; - KeypadAccessoryButton2Label = "Enter"; - - AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.Hdmi, null, this); - AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio, - eRoutingPortConnectionType.DigitalAudio, null, this); - OutputPorts = new RoutingPortCollection { AnyVideoOut, AnyAudioOut }; - } - - /// - /// LoadPresets method - /// - public void LoadPresets(string filePath) - { - TvPresets = new DevicePresetsModel(Key + "-presets", this, filePath); - DeviceManager.AddDevice(TvPresets); - } - - - #region ISetTopBoxControls Members - - /// - /// DvrList method - /// - public void DvrList(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_DVR, pressRelease); - } - - /// - /// Replay method - /// - public void Replay(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_REPLAY, pressRelease); - } - - #endregion - - #region IDPad Members - - /// - /// Up method - /// - public void Up(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_UP_ARROW, pressRelease); - } - - /// - /// Down method - /// - public void Down(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_DN_ARROW, pressRelease); - } - - /// - /// Left method - /// - public void Left(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_LEFT_ARROW, pressRelease); - } - - /// - /// Right method - /// - public void Right(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_RIGHT_ARROW, pressRelease); - } - - /// - /// Select method - /// - public void Select(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease); - } - - /// - /// Menu method - /// - public void Menu(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_MENU, pressRelease); - } - - /// - /// Exit method - /// - public void Exit(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_EXIT, pressRelease); - } - - #endregion - - #region INumericKeypad Members - - /// - /// Digit0 method - /// - public void Digit0(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_0, pressRelease); - } - - /// - /// Digit1 method - /// - public void Digit1(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_1, pressRelease); - } - - /// - /// Digit2 method - /// - public void Digit2(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_2, pressRelease); - } - - /// - /// Digit3 method - /// - public void Digit3(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_3, pressRelease); - } - - /// - /// Digit4 method - /// - public void Digit4(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_4, pressRelease); - } - - /// - /// Digit5 method - /// - public void Digit5(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_5, pressRelease); - } - - /// - /// Digit6 method - /// - public void Digit6(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_6, pressRelease); - } - - /// - /// Digit7 method - /// - public void Digit7(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_7, pressRelease); - } - - /// - /// Digit8 method - /// - public void Digit8(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_8, pressRelease); - } - - /// - /// Digit9 method - /// - public void Digit9(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_9, pressRelease); - } - - /// - /// Gets or sets the HasKeypadAccessoryButton1 - /// - public bool HasKeypadAccessoryButton1 { get; set; } - - /// - /// Defaults to "-" - /// - public string KeypadAccessoryButton1Label { get; set; } - - - /// - /// Defaults to "Dash" - /// - public string KeypadAccessoryButton1Command { get; set; } - - public void KeypadAccessoryButton1(bool pressRelease) - { - IrPort.PressRelease(KeypadAccessoryButton1Command, pressRelease); - } - - /// - /// Gets or sets the HasKeypadAccessoryButton2 - /// - public bool HasKeypadAccessoryButton2 { get; set; } - - /// - /// Defaults to "Enter" - /// - public string KeypadAccessoryButton2Label { get; set; } - - - /// - /// Defaults to "Enter" - /// - public string KeypadAccessoryButton2Command { get; set; } - - public void KeypadAccessoryButton2(bool pressRelease) - { - IrPort.PressRelease(KeypadAccessoryButton2Command, pressRelease); - } - - #endregion - - #region ISetTopBoxNumericKeypad Members - - /// - /// Dash method - /// - public void Dash(bool pressRelease) - { - IrPort.PressRelease("dash", pressRelease); - } - - /// - /// Corresponds to "numericEnter" IR command - /// - public void KeypadEnter(bool pressRelease) - { - IrPort.PressRelease("numericEnter", pressRelease); - } - - #endregion - - #region IChannelFunctions Members - - public void ChannelUp(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_CH_PLUS, pressRelease); - } - - /// - /// ChannelDown method - /// - public void ChannelDown(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_CH_MINUS, pressRelease); - } - - /// - /// LastChannel method - /// - public void LastChannel(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_LAST, pressRelease); - } - - /// - /// Guide method - /// - public void Guide(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_GUIDE, pressRelease); - } - - /// - /// Info method - /// - public void Info(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_INFO, pressRelease); - } - - #endregion - - #region IColorFunctions Members - - /// - /// Red method - /// - public void Red(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_RED, pressRelease); - } - - /// - /// Green method - /// - public void Green(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_GREEN, pressRelease); - } - - /// - /// Yellow method - /// - public void Yellow(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_YELLOW, pressRelease); - } - - /// - /// Blue method - /// - public void Blue(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_BLUE, pressRelease); - } - - #endregion - - #region IRoutingOutputs Members - - /// - /// Gets or sets the AnyVideoOut - /// - public RoutingOutputPort AnyVideoOut { get; private set; } - /// - /// Gets or sets the AnyAudioOut - /// - public RoutingOutputPort AnyAudioOut { get; private set; } - /// - /// Gets or sets the OutputPorts - /// - public RoutingPortCollection OutputPorts { get; private set; } - - #endregion - - #region ITransport Members - - /// - /// ChapMinus method - /// - public void ChapMinus(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_REPLAY, pressRelease); - } - - /// - /// ChapPlus method - /// - public void ChapPlus(bool pressRelease) - { - } - - /// - /// FFwd method - /// - public void FFwd(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_FSCAN, pressRelease); - } - - /// - /// Pause method - /// - public void Pause(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease); - } - - /// - /// Play method - /// - public void Play(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_PLAY, pressRelease); - } - - /// - /// Record method - /// - public void Record(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_RECORD, pressRelease); - } - - /// - /// Rewind method - /// - public void Rewind(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease); - } - - /// - /// Stop method - /// - public void Stop(bool pressRelease) - { - IrPort.PressRelease(IROutputStandardCommands.IROut_STOP, pressRelease); - } - - #endregion + HasKeypadAccessoryButton1 = true; + KeypadAccessoryButton1Command = "Dash"; + KeypadAccessoryButton1Label = "-"; + + HasKeypadAccessoryButton2 = true; + KeypadAccessoryButton2Command = "KEYPAD_ENTER"; + KeypadAccessoryButton2Label = "Enter"; + + AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.Hdmi, null, this); + AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio, + eRoutingPortConnectionType.DigitalAudio, null, this); + OutputPorts = new RoutingPortCollection { AnyVideoOut, AnyAudioOut }; + } + + /// + /// LoadPresets method + /// + public void LoadPresets(string filePath) + { + TvPresets = new DevicePresetsModel(Key + "-presets", this, filePath); + DeviceManager.AddDevice(TvPresets); + } + + + #region ISetTopBoxControls Members + + /// + /// DvrList method + /// + public void DvrList(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_DVR, pressRelease); + } + + /// + /// Replay method + /// + public void Replay(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_REPLAY, pressRelease); + } + + #endregion + + #region IDPad Members + + /// + /// Up method + /// + public void Up(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_UP_ARROW, pressRelease); + } + + /// + /// Down method + /// + public void Down(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_DN_ARROW, pressRelease); + } + + /// + /// Left method + /// + public void Left(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_LEFT_ARROW, pressRelease); + } + + /// + /// Right method + /// + public void Right(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_RIGHT_ARROW, pressRelease); + } + + /// + /// Select method + /// + public void Select(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease); + } + + /// + /// Menu method + /// + public void Menu(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_MENU, pressRelease); + } + + /// + /// Exit method + /// + public void Exit(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_EXIT, pressRelease); + } + + #endregion + + #region INumericKeypad Members + + /// + /// Digit0 method + /// + public void Digit0(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_0, pressRelease); + } + + /// + /// Digit1 method + /// + public void Digit1(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_1, pressRelease); + } + + /// + /// Digit2 method + /// + public void Digit2(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_2, pressRelease); + } + + /// + /// Digit3 method + /// + public void Digit3(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_3, pressRelease); + } + + /// + /// Digit4 method + /// + public void Digit4(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_4, pressRelease); + } + + /// + /// Digit5 method + /// + public void Digit5(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_5, pressRelease); + } + + /// + /// Digit6 method + /// + public void Digit6(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_6, pressRelease); + } + + /// + /// Digit7 method + /// + public void Digit7(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_7, pressRelease); + } + + /// + /// Digit8 method + /// + public void Digit8(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_8, pressRelease); + } + + /// + /// Digit9 method + /// + public void Digit9(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_9, pressRelease); + } + + /// + /// Gets or sets the HasKeypadAccessoryButton1 + /// + public bool HasKeypadAccessoryButton1 { get; set; } + + /// + /// Defaults to "-" + /// + public string KeypadAccessoryButton1Label { get; set; } + + + /// + /// Defaults to "Dash" + /// + public string KeypadAccessoryButton1Command { get; set; } + + /// + /// Presses the KeypadAccessoryButton1 + /// + public void KeypadAccessoryButton1(bool pressRelease) + { + IrPort.PressRelease(KeypadAccessoryButton1Command, pressRelease); + } + + /// + /// Gets or sets the HasKeypadAccessoryButton2 + /// + public bool HasKeypadAccessoryButton2 { get; set; } + + /// + /// Defaults to "Enter" + /// + public string KeypadAccessoryButton2Label { get; set; } + + + /// + /// Defaults to "Enter" + /// + public string KeypadAccessoryButton2Command { get; set; } + + /// + /// Presses the KeypadAccessoryButton2 + /// + public void KeypadAccessoryButton2(bool pressRelease) + { + IrPort.PressRelease(KeypadAccessoryButton2Command, pressRelease); + } + + #endregion + + #region ISetTopBoxNumericKeypad Members + + /// + /// Dash method + /// + public void Dash(bool pressRelease) + { + IrPort.PressRelease("dash", pressRelease); + } + + /// + /// Corresponds to "numericEnter" IR command + /// + public void KeypadEnter(bool pressRelease) + { + IrPort.PressRelease("numericEnter", pressRelease); + } + + #endregion + + #region IChannelFunctions Members + + /// + /// ChannelUp method + /// + public void ChannelUp(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_CH_PLUS, pressRelease); + } + + /// + /// ChannelDown method + /// + public void ChannelDown(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_CH_MINUS, pressRelease); + } + + /// + /// LastChannel method + /// + public void LastChannel(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_LAST, pressRelease); + } + + /// + /// Guide method + /// + public void Guide(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_GUIDE, pressRelease); + } + + /// + /// Info method + /// + public void Info(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_INFO, pressRelease); + } + + #endregion + + #region IColorFunctions Members + + /// + /// Red method + /// + public void Red(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_RED, pressRelease); + } + + /// + /// Green method + /// + public void Green(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_GREEN, pressRelease); + } + + /// + /// Yellow method + /// + public void Yellow(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_YELLOW, pressRelease); + } + + /// + /// Blue method + /// + public void Blue(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_BLUE, pressRelease); + } + + #endregion + + #region IRoutingOutputs Members + + /// + /// Gets or sets the AnyVideoOut + /// + public RoutingOutputPort AnyVideoOut { get; private set; } + /// + /// Gets or sets the AnyAudioOut + /// + public RoutingOutputPort AnyAudioOut { get; private set; } + /// + /// Gets or sets the OutputPorts + /// + public RoutingPortCollection OutputPorts { get; private set; } + + #endregion + + #region ITransport Members + + /// + /// ChapMinus method + /// + public void ChapMinus(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_REPLAY, pressRelease); + } + + /// + /// ChapPlus method + /// + public void ChapPlus(bool pressRelease) + { + } + + /// + /// FFwd method + /// + public void FFwd(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_FSCAN, pressRelease); + } + + /// + /// Pause method + /// + public void Pause(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease); + } + + /// + /// Play method + /// + public void Play(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_PLAY, pressRelease); + } + + /// + /// Record method + /// + public void Record(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_RECORD, pressRelease); + } + + /// + /// Rewind method + /// + public void Rewind(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease); + } + + /// + /// Stop method + /// + public void Stop(bool pressRelease) + { + IrPort.PressRelease(IROutputStandardCommands.IROut_STOP, pressRelease); + } + + #endregion #region IUsageTracking Members @@ -528,12 +537,12 @@ namespace PepperDash.Essentials.Devices.Common #endregion - /// - /// LinkToApi method - /// - /// - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { + /// + /// LinkToApi method + /// + /// + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { var joinMap = new SetTopBoxControllerJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); @@ -561,8 +570,7 @@ namespace PepperDash.Essentials.Devices.Common }); - var stbBase = this as ISetTopBoxControls; - if (stbBase != null) + if (this is ISetTopBoxControls stbBase) { trilist.BooleanInput[joinMap.HasDpad.JoinNumber].BoolValue = stbBase.HasDpad; trilist.BooleanInput[joinMap.HasNumeric.JoinNumber].BoolValue = stbBase.HasNumeric; @@ -575,16 +583,14 @@ namespace PepperDash.Essentials.Devices.Common trilist.SetStringSigAction(joinMap.LoadPresets.JoinNumber, stbBase.LoadPresets); } - var stbPower = this as IHasPowerControl; - if (stbPower != null) + if (this is IHasPowerControl stbPower) { trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, stbPower.PowerOn); trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, stbPower.PowerOff); trilist.SetSigTrueAction(joinMap.PowerToggle.JoinNumber, stbPower.PowerToggle); } - var stbDPad = this as IDPad; - if (stbDPad != null) + if (this is IDPad stbDPad) { trilist.SetBoolSigAction(joinMap.Up.JoinNumber, stbDPad.Up); trilist.SetBoolSigAction(joinMap.Down.JoinNumber, stbDPad.Down); @@ -595,8 +601,7 @@ namespace PepperDash.Essentials.Devices.Common trilist.SetBoolSigAction(joinMap.Exit.JoinNumber, stbDPad.Exit); } - var stbChannel = this as IChannel; - if (stbChannel != null) + if (this is IChannel stbChannel) { trilist.SetBoolSigAction(joinMap.ChannelUp.JoinNumber, stbChannel.ChannelUp); trilist.SetBoolSigAction(joinMap.ChannelDown.JoinNumber, stbChannel.ChannelDown); @@ -606,8 +611,7 @@ namespace PepperDash.Essentials.Devices.Common trilist.SetBoolSigAction(joinMap.Exit.JoinNumber, stbChannel.Exit); } - var stbColor = this as IColor; - if (stbColor != null) + if (this is IColor stbColor) { trilist.SetBoolSigAction(joinMap.Red.JoinNumber, stbColor.Red); trilist.SetBoolSigAction(joinMap.Green.JoinNumber, stbColor.Green); @@ -615,8 +619,7 @@ namespace PepperDash.Essentials.Devices.Common trilist.SetBoolSigAction(joinMap.Blue.JoinNumber, stbColor.Blue); } - var stbKeypad = this as ISetTopBoxNumericKeypad; - if (stbKeypad != null) + if (this is ISetTopBoxNumericKeypad stbKeypad) { trilist.StringInput[joinMap.KeypadAccessoryButton1Label.JoinNumber].StringValue = stbKeypad.KeypadAccessoryButton1Label; trilist.StringInput[joinMap.KeypadAccessoryButton2Label.JoinNumber].StringValue = stbKeypad.KeypadAccessoryButton2Label; @@ -640,8 +643,7 @@ namespace PepperDash.Essentials.Devices.Common trilist.SetBoolSigAction(joinMap.KeypadEnter.JoinNumber, stbKeypad.KeypadEnter); } - var stbTransport = this as ITransport; - if (stbTransport != null) + if (this is ITransport stbTransport) { trilist.SetBoolSigAction(joinMap.Play.JoinNumber, stbTransport.Play); trilist.SetBoolSigAction(joinMap.Pause.JoinNumber, stbTransport.Pause); @@ -652,35 +654,6 @@ namespace PepperDash.Essentials.Devices.Common trilist.SetBoolSigAction(joinMap.Stop.JoinNumber, stbTransport.Stop); trilist.SetBoolSigAction(joinMap.Record.JoinNumber, stbTransport.Record); } - } - } - - /// - /// Represents a IRSetTopBoxBaseFactory - /// - public class IRSetTopBoxBaseFactory : EssentialsDeviceFactory - { - public IRSetTopBoxBaseFactory() - { - TypeNames = new List() { "settopbox" }; - } - - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new SetTopBox Device"); - var irCont = IRPortHelper.GetIrOutputPortController(dc); - var config = dc.Properties.ToObject(); - var stb = new IRSetTopBoxBase(dc.Key, dc.Name, irCont, config); - - var listName = dc.Properties.Value("presetsList"); - if (listName != null) - stb.LoadPresets(listName); - return stb; - } } diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBaseFactory.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBaseFactory.cs new file mode 100644 index 00000000..5b122a6a --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/IRSetTopBoxBaseFactory.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using Serilog.Events; + +namespace PepperDash.Essentials.Devices.Common +{ + /// + /// Represents a IRSetTopBoxBaseFactory + /// + public class IRSetTopBoxBaseFactory : EssentialsDeviceFactory + { + /// + /// Initializes a new instance of the class + /// + public IRSetTopBoxBaseFactory() + { + TypeNames = new List() { "settopbox" }; + } + + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new SetTopBox Device"); + var irCont = IRPortHelper.GetIrOutputPortController(dc); + var config = dc.Properties.ToObject(); + var stb = new IRSetTopBoxBase(dc.Key, dc.Name, irCont, config); + + var listName = dc.Properties.Value("presetsList"); + if (listName != null) + stb.LoadPresets(listName); + return stb; + + } + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs index a2ec7e54..193b41e7 100644 --- a/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/SetTopBox/SetTopBoxPropertiesConfig.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Core; +using PepperDash.Core; namespace PepperDash.Essentials.Devices.Common { diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs b/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs index ad094703..e0080627 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/RelayControlledShade.cs @@ -27,6 +27,12 @@ namespace PepperDash.Essentials.Devices.Common.Shades /// public string StopOrPresetButtonLabel { get; set; } + /// + /// Initializes a new instance of the RelayControlledShade class + /// + /// The device key + /// The device name + /// The relay controlled shade configuration public RelayControlledShade(string key, string name, RelayControlledShadeConfigProperties config) : base(key, name) { @@ -157,6 +163,9 @@ namespace PepperDash.Essentials.Devices.Common.Shades /// public class RelayControlledShadeFactory : EssentialsDeviceFactory { + /// + /// Initializes a new instance of the RelayControlledShadeFactory class + /// public RelayControlledShadeFactory() { TypeNames = new List() { "relaycontrolledshade" }; diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs index 2c506750..ba3d67dd 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeBase.cs @@ -1,10 +1,18 @@ -using PepperDash.Essentials.Core.Shades; -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Shades; namespace PepperDash.Essentials.Devices.Common.Shades { + /// + /// Base class for shade devices + /// public abstract class ShadeBase : EssentialsDevice, IShadesOpenCloseStop { + /// + /// Initializes a new instance of the ShadeBase class + /// + /// The device key + /// The device name public ShadeBase(string key, string name) : base(key, name) { @@ -13,8 +21,17 @@ namespace PepperDash.Essentials.Devices.Common.Shades #region iShadesOpenClose Members + /// + /// Opens the shade + /// public abstract void Open(); + /// + /// Stops the shade + /// public abstract void Stop(); + /// + /// Closes the shade + /// public abstract void Close(); #endregion diff --git a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs index 9d28fe98..dc8cb125 100644 --- a/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs +++ b/src/PepperDash.Essentials.Devices.Common/Shades/ShadeController.cs @@ -14,8 +14,17 @@ namespace PepperDash.Essentials.Devices.Common.Shades { ShadeControllerConfigProperties Config; + /// + /// Gets the collection of shades controlled by this controller + /// public List Shades { get; private set; } + /// + /// Initializes a new instance of the ShadeController class + /// + /// The device key + /// The device name + /// The shade controller configuration public ShadeController(string key, string name, ShadeControllerConfigProperties config) : base(key, name) { @@ -76,6 +85,9 @@ namespace PepperDash.Essentials.Devices.Common.Shades /// public class ShadeControllerFactory : EssentialsDeviceFactory { + /// + /// Initializes a new instance of the ShadeControllerFactory class + /// public ShadeControllerFactory() { TypeNames = new List() { "shadecontroller" }; diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs index c96e6f01..afe47814 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPc.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using Crestron.SimplSharp; using PepperDash.Core; @@ -22,6 +21,9 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec /// public RoutingInputPort AnyVideoIn { get; private set; } + /// + /// Gets the CurrentInputPort + /// public RoutingInputPort CurrentInputPort => AnyVideoIn; #region IRoutingInputs Members @@ -33,6 +35,11 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec #endregion + /// + /// Initializes a new instance of the class + /// + /// The device key + /// The device name public BlueJeansPc(string key, string name) : base(key, name) { @@ -177,30 +184,12 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec } SourceListItem _CurrentSourceInfo; + /// + /// Event fired when the current source changes + /// public event SourceInfoChangeHandler CurrentSourceChange; #endregion } - /// - /// Represents a BlueJeansPcFactory - /// - public class BlueJeansPcFactory : EssentialsDeviceFactory - { - public BlueJeansPcFactory() - { - TypeNames = new List() { "bluejeanspc" }; - } - - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BlueJeansPc Device"); - return new SoftCodec.BlueJeansPc(dc.Key, dc.Name); - } - } - } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPcFactory.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPcFactory.cs new file mode 100644 index 00000000..75f39bbd --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/BlueJeansPcFactory.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using Serilog.Events; + + +namespace PepperDash.Essentials.Devices.Common.SoftCodec +{ + /// + /// Represents a BlueJeansPcFactory + /// + public class BlueJeansPcFactory : EssentialsDeviceFactory + { + /// + /// Initializes a new instance of the class + /// + public BlueJeansPcFactory() + { + TypeNames = new List() { "bluejeanspc" }; + } + + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BlueJeansPc Device"); + return new BlueJeansPc(dc.Key, dc.Name); + } + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs index f00fb9ce..f8a8f640 100644 --- a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodec.cs @@ -1,10 +1,7 @@ -using Newtonsoft.Json; +using System.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; using Serilog.Events; -using System.Collections.Generic; -using System.Linq; namespace PepperDash.Essentials.Devices.Common.SoftCodec { @@ -18,7 +15,8 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec /// /// Gets or sets the CurrentInputPort /// - public RoutingInputPort CurrentInputPort { + public RoutingInputPort CurrentInputPort + { get => _currentInputPort; set { @@ -28,19 +26,25 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec } } + /// + /// Initializes a new instance of the class + /// + /// The device key + /// The device name + /// The device properties public GenericSoftCodec(string key, string name, GenericSoftCodecProperties props) : base(key, name) { InputPorts = new RoutingPortCollection(); OutputPorts = new RoutingPortCollection(); - for(var i = 1; i <= props.OutputCount; i++) + for (var i = 1; i <= props.OutputCount; i++) { var outputPort = new RoutingOutputPort($"output{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this); OutputPorts.Add(outputPort); } - for(var i = 1; i<= props.ContentInputCount; i++) + for (var i = 1; i <= props.ContentInputCount; i++) { var inputPort = new RoutingInputPort($"contentInput{i}", eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, $"contentInput{i}", this); @@ -52,7 +56,7 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec return; } - for(var i = 1; i <=props.CameraInputCount; i++) + for (var i = 1; i <= props.CameraInputCount; i++) { var cameraPort = new RoutingInputPort($"cameraInput{i}", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, $"cameraInput{i}", this); @@ -72,7 +76,11 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec /// /// Gets or sets the CurrentSourceInfoKey /// - public string CurrentSourceInfoKey { get ; set; } + public string CurrentSourceInfoKey { get; set; } + + /// + /// Gets or sets the CurrentSourceInfo + /// public SourceListItem CurrentSourceInfo { get @@ -97,7 +105,14 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec SourceListItem _CurrentSourceInfo; + /// + /// Event fired when the current source changes + /// public event SourceInfoChangeHandler CurrentSourceChange; + + /// + /// Event fired when the input changes + /// public event InputChangedEventHandler InputChanged; /// @@ -107,7 +122,7 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec { var inputPort = InputPorts.FirstOrDefault(p => p.Selector == inputSelector); - if(inputPort == null) + if (inputPort == null) { Debug.LogMessage(LogEventLevel.Warning, "No input port found for selector {inputSelector}", inputSelector); return; @@ -116,58 +131,4 @@ namespace PepperDash.Essentials.Devices.Common.SoftCodec CurrentInputPort = inputPort; } } - - /// - /// Represents a GenericSoftCodecProperties - /// - public class GenericSoftCodecProperties - { - [JsonProperty("hasCameraInputs")] - /// - /// Gets or sets the HasCameraInputs - /// - public bool HasCameraInputs { get; set; } - - [JsonProperty("cameraInputCount")] - /// - /// Gets or sets the CameraInputCount - /// - public int CameraInputCount { get; set; } - - [JsonProperty("contentInputCount")] - /// - /// Gets or sets the ContentInputCount - /// - public int ContentInputCount { get; set; } - - [JsonProperty("contentOutputCount")] - /// - /// Gets or sets the OutputCount - /// - public int OutputCount { get; set; } - } - - /// - /// Represents a GenericSoftCodecFactory - /// - public class GenericSoftCodecFactory: EssentialsDeviceFactory - { - public GenericSoftCodecFactory() - { - TypeNames = new List { "genericsoftcodec" }; - } - - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Generic SoftCodec Device"); - - var props = dc.Properties.ToObject(); - - return new GenericSoftCodec(dc.Key, dc.Name, props); - } - } } diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodecFactory.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodecFactory.cs new file mode 100644 index 00000000..51fa5240 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodecFactory.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using Serilog.Events; + +namespace PepperDash.Essentials.Devices.Common.SoftCodec +{ + /// + /// Represents a GenericSoftCodecFactory + /// + public class GenericSoftCodecFactory : EssentialsDeviceFactory + { + /// + /// Initializes a new instance of the class + /// + public GenericSoftCodecFactory() + { + TypeNames = new List { "genericsoftcodec" }; + } + + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Attempting to create new Generic SoftCodec Device"); + + var props = dc.Properties.ToObject(); + + return new GenericSoftCodec(dc.Key, dc.Name, props); + } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodecProperties.cs b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodecProperties.cs new file mode 100644 index 00000000..70ee19e9 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/SoftCodec/GenericSoftCodecProperties.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.SoftCodec +{ + /// + /// Represents a GenericSoftCodecProperties + /// + public class GenericSoftCodecProperties + { + /// + /// Gets or sets the HasCameraInputs + /// + [JsonProperty("hasCameraInputs")] + public bool HasCameraInputs { get; set; } + + /// + /// Gets or sets the CameraInputCount + /// + [JsonProperty("cameraInputCount")] + public int CameraInputCount { get; set; } + + /// + /// Gets or sets the ContentInputCount + /// + [JsonProperty("contentInputCount")] + public int ContentInputCount { get; set; } + + /// + /// Gets or sets the OutputCount + /// + [JsonProperty("contentOutputCount")] + public int OutputCount { get; set; } + } +} diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs index 48586bd2..e2ef1c09 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPc.cs @@ -1,71 +1,74 @@ -using System; -using System.Collections.Generic; -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using Serilog.Events; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Sources { - /// - /// Represents a InRoomPc - /// - public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking - { - /// - /// Gets or sets the DisplayUiType - /// - public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } - /// - /// Gets or sets the IconName - /// - public string IconName { get; set; } - /// - /// Gets or sets the HasPowerOnFeedback - /// - public BoolFeedback HasPowerOnFeedback { get; private set; } + /// + /// Represents a InRoomPc + /// + public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking + { + /// + /// Gets or sets the DisplayUiType + /// + public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } + /// + /// Gets or sets the IconName + /// + public string IconName { get; set; } + /// + /// Gets or sets the HasPowerOnFeedback + /// + public BoolFeedback HasPowerOnFeedback { get; private set; } - /// - /// Gets or sets the AnyVideoOut - /// - public RoutingOutputPort AnyVideoOut { get; private set; } + /// + /// Gets or sets the AnyVideoOut + /// + public RoutingOutputPort AnyVideoOut { get; private set; } - #region IRoutingOutputs Members + #region IRoutingOutputs Members - /// - /// Gets or sets the OutputPorts - /// - public RoutingPortCollection OutputPorts { get; private set; } + /// + /// Gets or sets the OutputPorts + /// + public RoutingPortCollection OutputPorts { get; private set; } - #endregion + #endregion - public InRoomPc(string key, string name) - : base(key, name) - { - IconName = "PC"; - HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", - () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); - OutputPorts = new RoutingPortCollection(); - OutputPorts.Add(AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.None, 0, this)); - } + /// + /// Initializes a new instance of the class + /// + /// + /// + public InRoomPc(string key, string name) + : base(key, name) + { + IconName = "PC"; + HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", + () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); - #region IHasFeedback Members + OutputPorts = new RoutingPortCollection + { + (AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.None, 0, this)) + }; + } - /// - /// Passes through the VideoStatuses list - /// + #region IHasFeedback Members + + /// + /// Passes through the VideoStatuses list + /// public FeedbackCollection Feedbacks - { - get + { + get { var newList = new FeedbackCollection(); newList.AddRange(this.GetVideoStatuses().ToList()); return newList; } - } + } - #endregion + #endregion #region IUsageTracking Members @@ -75,27 +78,6 @@ namespace PepperDash.Essentials.Devices.Common.Sources public UsageTracking UsageTracker { get; set; } #endregion - } - - /// - /// Represents a InRoomPcFactory - /// - public class InRoomPcFactory : EssentialsDeviceFactory - { - public InRoomPcFactory() - { - TypeNames = new List() { "inroompc" }; - } - - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new InRoomPc Device"); - return new InRoomPc(dc.Key, dc.Name); - } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPcFactory.cs b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPcFactory.cs new file mode 100644 index 00000000..3136fd45 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Sources/InRoomPcFactory.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using Serilog.Events; + +namespace PepperDash.Essentials.Devices.Common.Sources +{ + /// + /// Represents a InRoomPcFactory + /// + public class InRoomPcFactory : EssentialsDeviceFactory + { + /// + /// Initializes a new instance of the class + /// + public InRoomPcFactory() + { + TypeNames = new List() { "inroompc" }; + } + + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new InRoomPc Device"); + return new InRoomPc(dc.Key, dc.Name); + } + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs index d2da9475..83ccfc4c 100644 --- a/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs +++ b/src/PepperDash.Essentials.Devices.Common/Sources/Laptop.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using Serilog.Events; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.Sources { @@ -11,54 +6,59 @@ namespace PepperDash.Essentials.Devices.Common.Sources /// Represents a Laptop /// public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking - { - /// - /// Gets or sets the DisplayUiType - /// - public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } - /// - /// Gets or sets the IconName - /// - public string IconName { get; set; } - /// - /// Gets or sets the HasPowerOnFeedback - /// - public BoolFeedback HasPowerOnFeedback { get; private set; } + { + /// + /// Gets or sets the DisplayUiType + /// + public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } + /// + /// Gets or sets the IconName + /// + public string IconName { get; set; } + /// + /// Gets or sets the HasPowerOnFeedback + /// + public BoolFeedback HasPowerOnFeedback { get; private set; } - /// - /// Gets or sets the AnyVideoOut - /// - public RoutingOutputPort AnyVideoOut { get; private set; } + /// + /// Gets or sets the AnyVideoOut + /// + public RoutingOutputPort AnyVideoOut { get; private set; } - #region IRoutingOutputs Members + #region IRoutingOutputs Members - /// - /// Gets or sets the OutputPorts - /// - public RoutingPortCollection OutputPorts { get; private set; } + /// + /// Gets or sets the OutputPorts + /// + public RoutingPortCollection OutputPorts { get; private set; } - #endregion + #endregion - public Laptop(string key, string name) - : base(key, name) - { - IconName = "Laptop"; + /// + /// Initializes a new instance of the Laptop class + /// + /// The device key + /// The device name + public Laptop(string key, string name) + : base(key, name) + { + IconName = "Laptop"; - HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", - () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); + HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", + () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); - OutputPorts = new RoutingPortCollection + OutputPorts = new RoutingPortCollection { (AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this)) }; - } + } - #region IHasFeedback Members + #region IHasFeedback Members - /// - /// Passes through the VideoStatuses list - /// + /// + /// Passes through the VideoStatuses list + /// public FeedbackCollection Feedbacks { get @@ -69,7 +69,7 @@ namespace PepperDash.Essentials.Devices.Common.Sources } } - #endregion + #endregion #region IUsageTracking Members @@ -79,26 +79,5 @@ namespace PepperDash.Essentials.Devices.Common.Sources public UsageTracking UsageTracker { get; set; } #endregion - } - - /// - /// Represents a LaptopFactory - /// - public class LaptopFactory : EssentialsDeviceFactory - { - public LaptopFactory() - { - TypeNames = new List() { "laptop" }; - } - - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Laptop Device"); - return new Laptop(dc.Key, dc.Name); - } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Sources/LaptopFactory.cs b/src/PepperDash.Essentials.Devices.Common/Sources/LaptopFactory.cs new file mode 100644 index 00000000..ebb072ba --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Sources/LaptopFactory.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using Serilog.Events; + +namespace PepperDash.Essentials.Devices.Common.Sources +{ + /// + /// Represents a LaptopFactory + /// + public class LaptopFactory : EssentialsDeviceFactory + { + /// + /// Initializes a new instance of the class + /// + public LaptopFactory() + { + TypeNames = new List() { "laptop" }; + } + + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Laptop Device"); + return new Laptop(dc.Key, dc.Name); + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs index 365a8271..6cf11c54 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTV.cs @@ -1,60 +1,63 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; +using System.Linq; using System.Reflection; -using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Bridges; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { + /// + /// Represents a AppleTV + /// Wrapper class for an IR-Controlled AppleTV + /// [Description("Wrapper class for an IR-Controlled AppleTV")] - /// - /// Represents a AppleTV - /// - public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs + public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs { - /// - /// Gets or sets the IrPort - /// + /// + /// Gets or sets the IrPort + /// public IrOutputPortController IrPort { get; private set; } + + /// + /// Standard Driver Name + /// public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir"; - /// - /// Gets or sets the DisplayUiType - /// - public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } } + /// + /// Gets or sets the DisplayUiType + /// + public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } } - public AppleTV(string key, string name, IrOutputPortController portCont) - : base(key, name) - { - IrPort = portCont; - DeviceManager.AddDevice(portCont); + /// + /// Initializes a new instance of the class + /// + /// The device key + /// The device name + /// The IR output port controller + public AppleTV(string key, string name, IrOutputPortController portCont) + : base(key, name) + { + IrPort = portCont; + DeviceManager.AddDevice(portCont); - HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.Hdmi, null, this); - AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio, - eRoutingPortConnectionType.DigitalAudio, null, this); - OutputPorts = new RoutingPortCollection { HdmiOut, AnyAudioOut }; + HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.Hdmi, null, this); + AnyAudioOut = new RoutingOutputPort(RoutingPortNames.AnyAudioOut, eRoutingSignalType.Audio, + eRoutingPortConnectionType.DigitalAudio, null, this); + OutputPorts = new RoutingPortCollection { HdmiOut, AnyAudioOut }; PrintExpectedIrCommands(); - } + } /// /// PrintExpectedIrCommands method /// public void PrintExpectedIrCommands() { - var cmds = typeof (AppleTvIrCommands).GetFields(BindingFlags.Public | BindingFlags.Static); + var cmds = typeof(AppleTvIrCommands).GetFields(BindingFlags.Public | BindingFlags.Static); foreach (var value in cmds.Select(cmd => cmd.GetValue(null)).OfType()) { @@ -64,151 +67,158 @@ namespace PepperDash.Essentials.Devices.Common #region IDPad Members - /// - /// Up method - /// - public void Up(bool pressRelease) - { - IrPort.PressRelease(AppleTvIrCommands.Up, pressRelease); - } + /// + /// Up method + /// + public void Up(bool pressRelease) + { + IrPort.PressRelease(AppleTvIrCommands.Up, pressRelease); + } - /// - /// Down method - /// - public void Down(bool pressRelease) - { - IrPort.PressRelease(AppleTvIrCommands.Down, pressRelease); - } + /// + /// Down method + /// + public void Down(bool pressRelease) + { + IrPort.PressRelease(AppleTvIrCommands.Down, pressRelease); + } - /// - /// Left method - /// - public void Left(bool pressRelease) - { - IrPort.PressRelease(AppleTvIrCommands.Left, pressRelease); - } + /// + /// Left method + /// + public void Left(bool pressRelease) + { + IrPort.PressRelease(AppleTvIrCommands.Left, pressRelease); + } - /// - /// Right method - /// - public void Right(bool pressRelease) - { - IrPort.PressRelease(AppleTvIrCommands.Right, pressRelease); - } + /// + /// Right method + /// + public void Right(bool pressRelease) + { + IrPort.PressRelease(AppleTvIrCommands.Right, pressRelease); + } - /// - /// Select method - /// - public void Select(bool pressRelease) - { - IrPort.PressRelease(AppleTvIrCommands.Enter, pressRelease); - } + /// + /// Select method + /// + public void Select(bool pressRelease) + { + IrPort.PressRelease(AppleTvIrCommands.Enter, pressRelease); + } - /// - /// Menu method - /// - public void Menu(bool pressRelease) - { - IrPort.PressRelease(AppleTvIrCommands.Menu, pressRelease); - } + /// + /// Menu method + /// + public void Menu(bool pressRelease) + { + IrPort.PressRelease(AppleTvIrCommands.Menu, pressRelease); + } - /// - /// Exit method - /// - public void Exit(bool pressRelease) - { + /// + /// Exit method + /// + public void Exit(bool pressRelease) + { - } + } - #endregion + #endregion - #region ITransport Members + #region ITransport Members - /// - /// Play method - /// - public void Play(bool pressRelease) - { - IrPort.PressRelease(AppleTvIrCommands.PlayPause, pressRelease); - } - - /// - /// Pause method - /// - public void Pause(bool pressRelease) - { + /// + /// Play method + /// + public void Play(bool pressRelease) + { IrPort.PressRelease(AppleTvIrCommands.PlayPause, pressRelease); - } + } - /// - /// Not implemented - /// - /// - /// - /// Rewind method - /// - public void Rewind(bool pressRelease) - { - } + /// + /// Pause method + /// + public void Pause(bool pressRelease) + { + IrPort.PressRelease(AppleTvIrCommands.PlayPause, pressRelease); + } - /// - /// Not implemented - /// - /// - public void FFwd(bool pressRelease) - { - } + /// + /// Not implemented + /// + /// + /// + /// Rewind method + /// + public void Rewind(bool pressRelease) + { + } - /// - /// Not implemented - /// - /// - public void ChapMinus(bool pressRelease) - { - } + /// + /// Not implemented + /// + /// + public void FFwd(bool pressRelease) + { + } - /// - /// Not implemented - /// - /// - public void ChapPlus(bool pressRelease) - { - } + /// + /// Not implemented + /// + /// + public void ChapMinus(bool pressRelease) + { + } - /// - /// Not implemented - /// - /// - public void Stop(bool pressRelease) - { - } + /// + /// Not implemented + /// + /// + public void ChapPlus(bool pressRelease) + { + } - /// - /// Not implemented - /// - /// - public void Record(bool pressRelease) - { - } + /// + /// Not implemented + /// + /// + public void Stop(bool pressRelease) + { + } - #endregion + /// + /// Not implemented + /// + /// + public void Record(bool pressRelease) + { + } - #region IRoutingOutputs Members + #endregion - public RoutingOutputPort HdmiOut { get; private set; } - public RoutingOutputPort AnyAudioOut { get; private set; } - /// - /// Gets or sets the OutputPorts - /// - public RoutingPortCollection OutputPorts { get; private set; } + #region IRoutingOutputs Members - #endregion + /// + /// Gets the HdmiOut + /// + public RoutingOutputPort HdmiOut { get; private set; } - /// - /// LinkToApi method - /// - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { + /// + /// Gets the AnyAudioOut + /// + public RoutingOutputPort AnyAudioOut { get; private set; } + /// + /// Gets or sets the OutputPorts + /// + public RoutingPortCollection OutputPorts { get; private set; } + + #endregion + + /// + /// LinkToApi method + /// + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { var joinMap = new AppleTvJoinMap(joinStart); var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); @@ -235,42 +245,6 @@ namespace PepperDash.Essentials.Devices.Common trilist.SetBoolSigAction(joinMap.Select.JoinNumber, Select); trilist.SetBoolSigAction(joinMap.Menu.JoinNumber, Menu); trilist.SetBoolSigAction(joinMap.PlayPause.JoinNumber, Play); - } - } - - /// - /// Represents a AppleTVFactory - /// - public class AppleTVFactory : EssentialsDeviceFactory - { - public AppleTVFactory() - { - TypeNames = new List() { "appletv" }; } - - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new AppleTV Device"); - var irCont = IRPortHelper.GetIrOutputPortController(dc); - return new AppleTV(dc.Key, dc.Name, irCont); - } - } - - public static class AppleTvIrCommands - { - - public static string Up = "+"; - public static string Down = "-"; - public static string Left = IROutputStandardCommands.IROut_TRACK_MINUS; - public static string Right = IROutputStandardCommands.IROut_TRACK_PLUS; - public static string Enter = IROutputStandardCommands.IROut_ENTER; - public static string PlayPause = "PLAY/PAUSE"; - public static string Rewind = "REWIND"; - public static string Menu = "Menu"; - public static string FastForward = "FASTFORWARD"; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTVFactory.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTVFactory.cs new file mode 100644 index 00000000..f5ef907b --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTVFactory.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using Serilog.Events; + +namespace PepperDash.Essentials.Devices.Common +{ + /// + /// Represents a AppleTVFactory + /// + public class AppleTVFactory : EssentialsDeviceFactory + { + /// + /// Initializes a new instance of the class + /// + public AppleTVFactory() + { + TypeNames = new List() { "appletv" }; + } + + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new AppleTV Device"); + var irCont = IRPortHelper.GetIrOutputPortController(dc); + return new AppleTV(dc.Key, dc.Name, irCont); + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTvIrCommands.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTvIrCommands.cs new file mode 100644 index 00000000..2b3d1d14 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/AppleTvIrCommands.cs @@ -0,0 +1,56 @@ +using Crestron.SimplSharpPro; + +namespace PepperDash.Essentials.Devices.Common +{ + /// + /// Represents AppleTvIrCommands + /// + public static class AppleTvIrCommands + { + + /// + /// Up command + /// + public static string Up = "+"; + + /// + /// Down command + /// + public static string Down = "-"; + + /// + /// Left command + /// + public static string Left = IROutputStandardCommands.IROut_TRACK_MINUS; + + /// + /// Right command + /// + public static string Right = IROutputStandardCommands.IROut_TRACK_PLUS; + + /// + /// Enter command + /// + public static string Enter = IROutputStandardCommands.IROut_ENTER; + + /// + /// PlayPause command + /// + public static string PlayPause = "PLAY/PAUSE"; + + /// + /// Rewind command + /// + public static string Rewind = "REWIND"; + + /// + /// Menu command + /// + public static string Menu = "Menu"; + + /// + /// FastForward command + /// + public static string FastForward = "FASTFORWARD"; + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs index a08872f5..8b956a5d 100644 --- a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku.cs @@ -1,107 +1,106 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DeviceSupport; - -using PepperDash.Core; +using Crestron.SimplSharpPro; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using Serilog.Events; namespace PepperDash.Essentials.Devices.Common { - [Description("Wrapper class for an IR-Controlled Roku")] - /// - /// Represents a Roku2 - /// + /// + /// Represents a Roku2 + /// Wrapper class for an IR-Controlled Roku + /// + [Description("Wrapper class for an IR-Controlled Roku")] public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs { + /// + /// Gets or sets the IrPort + /// [Api] - /// - /// Gets or sets the IrPort - /// public IrOutputPortController IrPort { get; private set; } + + /// + /// Standard Driver Name + /// public const string StandardDriverName = "Roku XD_S.ir"; + /// + /// Gets or sets the DisplayUiType + /// [Api] - /// - /// Gets or sets the DisplayUiType - /// public uint DisplayUiType { get { return DisplayUiConstants.TypeRoku; } } + /// + /// Initializes a new instance of the class + /// public Roku2(string key, string name, IrOutputPortController portCont) : base(key, name) { IrPort = portCont; - DeviceManager.AddDevice(portCont);; + DeviceManager.AddDevice(portCont); ; - HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + HdmiOut = new RoutingOutputPort(RoutingPortNames.HdmiOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, null, this); OutputPorts = new RoutingPortCollection { HdmiOut }; } #region IDPad Members + /// + /// Up method + /// [Api] - /// - /// Up method - /// public void Up(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_UP_ARROW, pressRelease); } + /// + /// Down method + /// [Api] - /// - /// Down method - /// public void Down(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_DN_ARROW, pressRelease); } + /// + /// Left method + /// [Api] - /// - /// Left method - /// public void Left(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_LEFT_ARROW, pressRelease); } + /// + /// Right method + /// [Api] - /// - /// Right method - /// public void Right(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RIGHT_ARROW, pressRelease); } + + /// + /// Select method + /// [Api] - /// - /// Select method - /// public void Select(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_ENTER, pressRelease); } + /// + /// Menu method + /// [Api] - /// - /// Menu method - /// public void Menu(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_MENU, pressRelease); } + /// + /// Exit method + /// [Api] - /// - /// Exit method - /// public void Exit(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_EXIT, pressRelease); @@ -111,49 +110,46 @@ namespace PepperDash.Essentials.Devices.Common #region ITransport Members + /// + /// Play method + /// [Api] - /// - /// Play method - /// public void Play(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_PLAY, pressRelease); } + /// + /// Pause method + /// [Api] - /// - /// Pause method - /// public void Pause(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_PAUSE, pressRelease); } + /// + /// Rewind method + /// [Api] - /// - /// Rewind method - /// public void Rewind(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_RSCAN, pressRelease); } + /// + /// FFwd method + /// [Api] - /// - /// FFwd method - /// public void FFwd(bool pressRelease) { IrPort.PressRelease(IROutputStandardCommands.IROut_FSCAN, pressRelease); } /// - /// Not implemented + /// ChapMinus method - Not implemented /// /// - /// - /// ChapMinus method - /// public void ChapMinus(bool pressRelease) { } @@ -186,34 +182,18 @@ namespace PepperDash.Essentials.Devices.Common #region IRoutingOutputs Members + /// + /// HdmiOut + /// public RoutingOutputPort HdmiOut { get; private set; } + + /// + /// OutputPorts + /// public RoutingPortCollection OutputPorts { get; private set; } #endregion } - /// - /// Represents a Roku2Factory - /// - public class Roku2Factory : EssentialsDeviceFactory - { - public Roku2Factory() - { - TypeNames = new List() { "roku" }; - } - - /// - /// BuildDevice method - /// - /// - public override EssentialsDevice BuildDevice(DeviceConfig dc) - { - Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Roku Device"); - var irCont = IRPortHelper.GetIrOutputPortController(dc); - return new Roku2(dc.Key, dc.Name, irCont); - - } - } - } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/Streaming/Roku2Factory.cs b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku2Factory.cs new file mode 100644 index 00000000..acd330c4 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/Streaming/Roku2Factory.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using Serilog.Events; + +namespace PepperDash.Essentials.Devices.Common +{ + /// + /// Represents a Roku2Factory + /// + public class Roku2Factory : EssentialsDeviceFactory + { + /// + /// Roku2Factory constructor + /// + public Roku2Factory() + { + TypeNames = new List() { "roku" }; + } + + /// + /// BuildDevice method + /// + /// + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Roku Device"); + var irCont = IRPortHelper.GetIrOutputPortController(dc); + return new Roku2(dc.Key, dc.Name, irCont); + + } + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs index 9a1f770c..8872172a 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/CallHistoryDataClasses.cs @@ -1,8 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; namespace PepperDash.Essentials.Devices.Common.VideoCodec { diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs index dfccd74b..e6e2be7e 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/RoomPresets.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; - -using PepperDash.Core; using PepperDash.Essentials.Core.Presets; namespace PepperDash.Essentials.Devices.Common.VideoCodec @@ -38,19 +36,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// /// /// - void CodecRoomPresetStore(int preset, string description); + void CodecRoomPresetStore(int preset, string description); /// /// Selects a far end preset by its ID. This is typically used to recall a preset that has been defined on the far end codec. /// /// - void SelectFarEndPreset(int preset); + void SelectFarEndPreset(int preset); } /// /// Static class for converting non-generic RoomPresets to generic CameraPresets. /// - public static class RoomPresets + public static class RoomPresets { /// /// Converts non-generic RoomPresets to generic CameraPresets diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs index ef960406..6d77551d 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceMode.cs @@ -3,5 +3,23 @@ /// /// Enumeration of eExternalSourceMode values /// - public enum eExternalSourceMode {Ready, NotReady, Hidden, Error} + public enum eExternalSourceMode + { + /// + /// Ready state + /// + Ready, + /// + /// Not ready state + /// + NotReady, + /// + /// Hidden state + /// + Hidden, + /// + /// Error state + /// + Error + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs index a5cea36c..6d5811e3 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CiscoCodec/eExternalSourceType.cs @@ -3,5 +3,35 @@ /// /// Enumeration of eExternalSourceType values /// - public enum eExternalSourceType {camera, desktop, document_camera, mediaplayer, PC, whiteboard, other} + public enum eExternalSourceType + { + /// + /// Camera source type + /// + camera, + /// + /// Desktop source type + /// + desktop, + /// + /// Document camera source type + /// + document_camera, + /// + /// Media player source type + /// + mediaplayer, + /// + /// PC source type + /// + PC, + /// + /// Whiteboard source type + /// + whiteboard, + /// + /// Other source type + /// + other + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CodecCommandWithLabel.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CodecCommandWithLabel.cs new file mode 100644 index 00000000..a69fc77a --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CodecCommandWithLabel.cs @@ -0,0 +1,31 @@ +namespace PepperDash.Essentials.Devices.Common.VideoCodec +{ + /// + /// Represents a CodecCommandWithLabel + /// + public class CodecCommandWithLabel + { + /// + /// Gets or sets the Command + /// + public string Command { get; private set; } + /// + /// Gets or sets the Label + /// + public string Label { get; private set; } + + /// + /// Constructor for + /// + /// Command string + /// Label string + public CodecCommandWithLabel(string command, string label) + { + Command = command; + Label = label; + } + } + + + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/CodecPhonebookSyncState.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CodecPhonebookSyncState.cs new file mode 100644 index 00000000..c677c906 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/CodecPhonebookSyncState.cs @@ -0,0 +1,150 @@ +using System; +using PepperDash.Core; +using Serilog.Events; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec +{ + /// + /// Represents a CodecPhonebookSyncState + /// + public class CodecPhonebookSyncState : IKeyed + { + private bool _InitialSyncComplete; + + /// + /// Constructor for CodecPhonebookSyncState + /// + /// Key for the codec phonebook sync state + public CodecPhonebookSyncState(string key) + { + Key = key; + + CodecDisconnected(); + } + + /// + /// Gets or sets the InitialSyncComplete + /// + public bool InitialSyncComplete + { + get { return _InitialSyncComplete; } + private set + { + if (value == true) + { + InitialSyncCompleted?.Invoke(this, new EventArgs()); + } + _InitialSyncComplete = value; + } + } + + /// + /// Gets or sets the InitialPhonebookFoldersWasReceived + /// + public bool InitialPhonebookFoldersWasReceived { get; private set; } + + /// + /// Gets or sets the NumberOfContactsWasReceived + /// + public bool NumberOfContactsWasReceived { get; private set; } + + /// + /// Gets or sets the PhonebookRootEntriesWasRecieved + /// + public bool PhonebookRootEntriesWasRecieved { get; private set; } + + /// + /// Gets or sets the PhonebookHasFolders + /// + public bool PhonebookHasFolders { get; private set; } + + /// + /// Gets or sets the NumberOfContacts + /// + public int NumberOfContacts { get; private set; } + + #region IKeyed Members + + /// + /// Gets or sets the Key + /// + public string Key { get; private set; } + + #endregion + + /// + /// Event InitialSyncCompleted + /// + public event EventHandler InitialSyncCompleted; + + /// + /// InitialPhonebookFoldersReceived method + /// + public void InitialPhonebookFoldersReceived() + { + InitialPhonebookFoldersWasReceived = true; + + CheckSyncStatus(); + } + + /// + /// PhonebookRootEntriesReceived method + /// + public void PhonebookRootEntriesReceived() + { + PhonebookRootEntriesWasRecieved = true; + + CheckSyncStatus(); + } + + /// + /// SetPhonebookHasFolders method + /// + public void SetPhonebookHasFolders(bool value) + { + PhonebookHasFolders = value; + + Debug.LogMessage(LogEventLevel.Debug, this, "Phonebook has folders: {0}", PhonebookHasFolders); + } + + /// + /// SetNumberOfContacts method + /// + public void SetNumberOfContacts(int contacts) + { + NumberOfContacts = contacts; + NumberOfContactsWasReceived = true; + + Debug.LogMessage(LogEventLevel.Debug, this, "Phonebook contains {0} contacts.", NumberOfContacts); + + CheckSyncStatus(); + } + + /// + /// CodecDisconnected method + /// + public void CodecDisconnected() + { + InitialPhonebookFoldersWasReceived = false; + PhonebookHasFolders = false; + NumberOfContacts = 0; + NumberOfContactsWasReceived = false; + } + + private void CheckSyncStatus() + { + if (InitialPhonebookFoldersWasReceived && NumberOfContactsWasReceived && PhonebookRootEntriesWasRecieved) + { + InitialSyncComplete = true; + Debug.LogMessage(LogEventLevel.Debug, this, "Initial Phonebook Sync Complete!"); + } + else + { + InitialSyncComplete = false; + } + } + } + + + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs index 4c01d94e..e75f436d 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/ConvertiblePreset.cs @@ -2,8 +2,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { + /// + /// Base class for presets that can be converted to PresetBase + /// public abstract class ConvertiblePreset { + /// + /// Converts the preset to a PresetBase + /// + /// public abstract PresetBase ConvertCodecPreset(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/CodecParticipants.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/CodecParticipants.cs new file mode 100644 index 00000000..a297c9e6 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/CodecParticipants.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +{ + /// + /// Represents a CodecParticipants + /// + public class CodecParticipants + { + private List _currentParticipants; + + /// + /// Gets or sets the CurrentParticipants + /// + public List CurrentParticipants + { + get { return _currentParticipants; } + set + { + _currentParticipants = value; + OnParticipantsChanged(); + } + } + + /// + /// Gets the Host participant + /// + public Participant Host + { + get + { + return _currentParticipants.FirstOrDefault(p => p.IsHost); + } + } + + /// + /// Event fired when the participants list has changed + /// + public event EventHandler ParticipantsListHasChanged; + + /// + /// Initializes a new instance of the CodecParticipants class + /// + public CodecParticipants() + { + _currentParticipants = new List(); + } + + /// + /// OnParticipantsChanged method + /// + public void OnParticipantsChanged() + { + var handler = ParticipantsListHasChanged; + + if (handler == null) return; + + handler(this, new EventArgs()); + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs index 98a8e4f4..61a40048 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecLayouts.cs @@ -1,14 +1,4 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; - -using Newtonsoft.Json; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec { @@ -17,10 +7,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public interface IHasCodecLayouts { + /// + /// Feedback that indicates the current layout on the local display + /// StringFeedback LocalLayoutFeedback { get; } + /// + /// Toggles the local layout + /// void LocalLayoutToggle(); - void LocalLayoutToggleSingleProminent(); - void MinMaxLayoutToggle(); + + /// + /// Toggles the local layout to single prominent + /// + void LocalLayoutToggleSingleProminent(); + + /// + /// Toggle the MinMax layout + /// + void MinMaxLayoutToggle(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs index 3b079b7d..a52670bc 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasCodecSelfview.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec { @@ -13,14 +7,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public interface IHasCodecSelfView { + /// + /// Feedback that indicates whether Selfview is on + /// BoolFeedback SelfviewIsOnFeedback { get; } + /// + /// Setting that indicates whether the device shows selfview by default + /// bool ShowSelfViewByDefault { get; } + /// + /// Turns selfview on + /// void SelfViewModeOn(); + /// + /// Turns selfview off + /// void SelfViewModeOff(); + /// + /// Toggles selfview mode + /// void SelfViewModeToggle(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs index 88ccfcac..6ec1f8da 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingInfo.cs @@ -1,12 +1,6 @@  using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { @@ -15,94 +9,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces /// public interface IHasMeetingInfo { + /// + /// Raised when meeting info changes + /// event EventHandler MeetingInfoChanged; + /// + /// Gets the current meeting information + /// MeetingInfo MeetingInfo { get; } } - - /// - /// Represents a MeetingInfo - /// - public class MeetingInfo - { - [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the Id - /// - public string Id { get; private set; } - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] - public string Name { get; private set; } - [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)] - public string Host { get; private set; } - [JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)] - public string Password { get; private set; } - [JsonProperty("shareStatus", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the ShareStatus - /// - public string ShareStatus { get; private set; } - [JsonProperty("isHost", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the IsHost - /// - public Boolean IsHost { get; private set; } - [JsonProperty("isSharingMeeting", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the IsSharingMeeting - /// - public Boolean IsSharingMeeting { get; private set; } - [JsonProperty("waitingForHost", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the WaitingForHost - /// - public Boolean WaitingForHost { get; private set; } - [JsonProperty("isLocked", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the IsLocked - /// - public Boolean IsLocked { get; private set; } - [JsonProperty("isRecording", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the IsRecording - /// - public Boolean IsRecording { get; private set; } - [JsonProperty("canRecord", NullValueHandling = NullValueHandling.Ignore)] - /// - /// Gets or sets the CanRecord - /// - public Boolean CanRecord { get; private set; } - - - public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost, bool isSharingMeeting, bool waitingForHost, bool isLocked, bool isRecording, bool canRecord) - { - Id = id; - Name = name; - Host = host; - Password = password; - ShareStatus = shareStatus; - IsHost = isHost; - IsSharingMeeting = isSharingMeeting; - WaitingForHost = waitingForHost; - IsLocked = isLocked; - IsRecording = isRecording; - CanRecord = CanRecord; - } - } - - /// - /// Represents a MeetingInfoEventArgs - /// - public class MeetingInfoEventArgs : EventArgs - { - /// - /// Gets or sets the Info - /// - public MeetingInfo Info { get; private set; } - - public MeetingInfoEventArgs(MeetingInfo info) - { - Info = info; - } - - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs index e7344818..b133eebd 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingLock.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { @@ -12,10 +7,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces /// public interface IHasMeetingLock { + /// + /// Feedback that indicates whether the meeting is locked + /// BoolFeedback MeetingIsLockedFeedback { get; } + /// + /// Locks the meeting + /// void LockMeeting(); + + /// + /// Unlocks the meeting + /// void UnLockMeeting(); + + /// + /// Toggles the meeting lock state + /// void ToggleMeetingLock(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs index 9946cdd1..96e23daa 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecording.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { @@ -12,24 +7,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces /// public interface IHasMeetingRecording { + /// + /// Feedback that indicates whether the meeting is being recorded + /// BoolFeedback MeetingIsRecordingFeedback { get; } + /// + /// Starts recording the meeting + /// void StartRecording(); - void StopRecording(); - void ToggleRecording(); - } - - /// - /// Defines the contract for IHasMeetingRecordingWithPrompt - /// - public interface IHasMeetingRecordingWithPrompt : IHasMeetingRecording - { - BoolFeedback RecordConsentPromptIsVisible { get; } /// - /// Used to agree or disagree to the meeting being recorded when prompted + /// Stops recording the meeting /// - /// - void RecordingPromptAcknowledgement(bool agree); + void StopRecording(); + + /// + /// Toggles recording the meeting + /// + void ToggleRecording(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecordingWithPrompt.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecordingWithPrompt.cs new file mode 100644 index 00000000..13d187c2 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasMeetingRecordingWithPrompt.cs @@ -0,0 +1,21 @@ +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +{ + /// + /// Defines the contract for IHasMeetingRecordingWithPrompt + /// + public interface IHasMeetingRecordingWithPrompt : IHasMeetingRecording + { + /// + /// Feedback that indicates whether the recording consent prompt is visible + /// + BoolFeedback RecordConsentPromptIsVisible { get; } + + /// + /// Used to agree or disagree to the meeting being recorded when prompted + /// + /// + void RecordingPromptAcknowledgement(bool agree); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantAudioMute.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantAudioMute.cs new file mode 100644 index 00000000..6ada2e46 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantAudioMute.cs @@ -0,0 +1,31 @@ +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +{ + /// + /// Defines the contract for IHasParticipantAudioMute + /// + public interface IHasParticipantAudioMute : IHasParticipantVideoMute + { + /// + /// Mute audio of all participants + /// + void MuteAudioForAllParticipants(); + + /// + /// Mute audio for participant + /// + /// The user ID of the participant to mute + void MuteAudioForParticipant(int userId); + + /// + /// Unmute audio for participant + /// + /// The user ID of the participant to unmute + void UnmuteAudioForParticipant(int userId); + + /// + /// Toggles audio for participant + /// + /// The user ID of the participant to toggle + void ToggleAudioForParticipant(int userId); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantPinUnpin.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantPinUnpin.cs new file mode 100644 index 00000000..9167e8a8 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantPinUnpin.cs @@ -0,0 +1,40 @@ +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +{ + /// + /// Defines the contract for IHasParticipantPinUnpin + /// + public interface IHasParticipantPinUnpin : IHasParticipants + { + /// + /// Feedback that indicates the number of screens available for pinning participants + /// + IntFeedback NumberOfScreensFeedback { get; } + + /// + /// Gets the screen index to pin the user to + /// + int ScreenIndexToPinUserTo { get; } + + /// + /// Pins a participant to a screen + /// + /// The user ID of the participant to pin + /// The screen index to pin the user to + void PinParticipant(int userId, int screenIndex); + + /// + /// Unpins a participant + /// + /// The user ID of the participant to unpin + void UnPinParticipant(int userId); + + /// + /// Toggles the pin state of a participant + /// + /// The user ID of the participant to toggle + /// The screen index to pin the user to + void ToggleParticipantPinState(int userId, int screenIndex); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantVideoMute.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantVideoMute.cs new file mode 100644 index 00000000..3e673cff --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipantVideoMute.cs @@ -0,0 +1,26 @@ +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +{ + /// + /// Describes the ability to mute and unmute a participant's video in a meeting + /// + public interface IHasParticipantVideoMute : IHasParticipants + { + /// + /// Mute video of all participants + /// + /// The user ID of the participant to mute + void MuteVideoForParticipant(int userId); + + /// + /// Unmute video of all participants + /// + /// The user ID of the participant to unmute + void UnmuteVideoForParticipant(int userId); + + /// + /// Toggles video of a participant + /// + /// The user ID of the participant to toggle + void ToggleVideoForParticipant(int userId); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs index 0f89eb91..6ff549af 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasParticipants.cs @@ -1,156 +1,31 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using PepperDash.Core; -using PepperDash.Essentials.Core; - -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Describes a device that has call participants /// public interface IHasParticipants { + /// + /// Gets the collection of participants + /// CodecParticipants Participants { get; } - /// - /// Removes the participant from the meeting - /// - /// - void RemoveParticipant(int userId); + /// + /// Removes the participant from the meeting + /// + /// + void RemoveParticipant(int userId); - /// - /// Sets the participant as the new host - /// - /// - void SetParticipantAsHost(int userId); + /// + /// Sets the participant as the new host + /// + /// + void SetParticipantAsHost(int userId); - /// - /// Admits a participant from the waiting room - /// - /// - void AdmitParticipantFromWaitingRoom(int userId); - } - - /// - /// Describes the ability to mute and unmute a participant's video in a meeting - /// - public interface IHasParticipantVideoMute : IHasParticipants - { - void MuteVideoForParticipant(int userId); - void UnmuteVideoForParticipant(int userId); - void ToggleVideoForParticipant(int userId); - } - - /// - /// Defines the contract for IHasParticipantAudioMute - /// - public interface IHasParticipantAudioMute : IHasParticipantVideoMute - { - /// - /// Mute audio of all participants - /// - void MuteAudioForAllParticipants(); - - void MuteAudioForParticipant(int userId); - void UnmuteAudioForParticipant(int userId); - void ToggleAudioForParticipant(int userId); - } - - /// - /// Defines the contract for IHasParticipantPinUnpin - /// - public interface IHasParticipantPinUnpin : IHasParticipants - { - IntFeedback NumberOfScreensFeedback { get; } - int ScreenIndexToPinUserTo { get; } - - void PinParticipant(int userId, int screenIndex); - void UnPinParticipant(int userId); - void ToggleParticipantPinState(int userId, int screenIndex); - } - - /// - /// Represents a CodecParticipants - /// - public class CodecParticipants - { - private List _currentParticipants; - - public List CurrentParticipants - { - get { return _currentParticipants; } - set - { - _currentParticipants = value; - OnParticipantsChanged(); - } - } - - public Participant Host - { - get - { - return _currentParticipants.FirstOrDefault(p => p.IsHost); - } - } - - public event EventHandler ParticipantsListHasChanged; - - public CodecParticipants() - { - _currentParticipants = new List(); - } - - /// - /// OnParticipantsChanged method - /// - public void OnParticipantsChanged() - { - var handler = ParticipantsListHasChanged; - - if (handler == null) return; - - handler(this, new EventArgs()); - } - } - - /// - /// Represents a Participant - /// - public class Participant - { - /// - /// Gets or sets the UserId - /// - public int UserId { get; set; } - /// - /// Gets or sets the IsHost - /// - public bool IsHost { get; set; } - public bool IsMyself { get; set; } - public string Name { get; set; } - public bool CanMuteVideo { get; set; } - public bool CanUnmuteVideo { get; set; } - public bool VideoMuteFb { get; set; } - public bool AudioMuteFb { get; set; } - /// - /// Gets or sets the HandIsRaisedFb - /// - public bool HandIsRaisedFb { get; set; } - /// - /// Gets or sets the IsPinnedFb - /// - public bool IsPinnedFb { get; set; } - /// - /// Gets or sets the ScreenIndexIsPinnedToFb - /// - public int ScreenIndexIsPinnedToFb { get; set; } - - public Participant() - { - // Initialize to -1 (no screen) - ScreenIndexIsPinnedToFb = -1; - } + /// + /// Admits a participant from the waiting room + /// + /// + void AdmitParticipantFromWaitingRoom(int userId); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs index cb52efc2..b2180c39 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasPresentationOnlyMeeting.cs @@ -5,10 +5,35 @@ /// public interface IHasPresentationOnlyMeeting { + /// + /// Starts a presentation only meeting + /// void StartSharingOnlyMeeting(); + + /// + /// Starts a presentation only meeting with specified display mode + /// + /// The display mode for the meeting void StartSharingOnlyMeeting(eSharingMeetingMode displayMode); + + /// + /// Starts a presentation only meeting with specified display mode and duration + /// + /// The display mode for the meeting + /// The duration for the meeting void StartSharingOnlyMeeting(eSharingMeetingMode displayMode, uint duration); + + /// + /// Starts a presentation only meeting with specified display mode, duration, and password + /// + /// The display mode for the meeting + /// The duration for the meeting + /// The password for the meeting void StartSharingOnlyMeeting(eSharingMeetingMode displayMode, uint duration, string password); + + /// + /// Starts a normal meeting from a sharing only meeting + /// void StartNormalMeetingFromSharingOnlyMeeting(); } @@ -17,8 +42,17 @@ /// public enum eSharingMeetingMode { + /// + /// No specific sharing mode + /// None, + /// + /// Laptop sharing mode + /// Laptop, + /// + /// iOS sharing mode + /// Ios, } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs index dbb6d0ef..46c3d8f7 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewPosition.cs @@ -1,5 +1,4 @@ -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Devices.Common.VideoCodec; +using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { @@ -8,10 +7,19 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces /// public interface IHasSelfviewPosition { + /// + /// Gets the SelfviewPipPositionFeedback + /// StringFeedback SelfviewPipPositionFeedback { get; } + /// + /// Sets the selfview position + /// void SelfviewPipPositionSet(CodecCommandWithLabel position); + /// + /// Toggles the selfview position + /// void SelfviewPipPositionToggle(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs index 45365ce1..ab08a414 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasSelfviewSize.cs @@ -2,15 +2,25 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces { - /// - /// Defines the contract for IHasSelfviewSize - /// + /// + /// Defines the contract for IHasSelfviewSize + /// public interface IHasSelfviewSize { + /// + /// Gets the SelfviewPipSizeFeedback + /// StringFeedback SelfviewPipSizeFeedback { get; } + /// + /// Sets the selfview size + /// + /// The new selfview size void SelfviewPipSizeSet(CodecCommandWithLabel size); + /// + /// Toggles the selfview size + /// void SelfviewPipSizeToggle(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs index 6b2ebe38..d0f1333b 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStandbyMode.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec { @@ -13,10 +7,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public interface IHasStandbyMode { + /// + /// Feedback that indicates whether Standby Mode is on + /// BoolFeedback StandbyIsOnFeedback { get; } + /// + /// Activates Standby Mode + /// void StandbyActivate(); + /// + /// Deactivates Standby Mode + /// void StandbyDeactivate(); } @@ -25,10 +28,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public interface IHasHalfWakeMode : IHasStandbyMode { + /// + /// Feedback that indicates whether Half Wake Mode is on + /// BoolFeedback HalfWakeModeIsOnFeedback { get; } + /// + /// Feedback that indicates whether the device is entering Standby Mode + /// BoolFeedback EnteringStandbyModeFeedback { get; } + /// + /// Activates Half Wake Mode + /// void HalfwakeActivate(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs index 6af59534..357416e2 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasStartMeeting.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces { /// /// Describes the ability to start an ad-hoc meeting diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs index f7b8f9ad..cdeb9190 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IHasVideoCodec.cs @@ -1,25 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// /// For rooms that have video codec /// - public interface IHasVideoCodec:IHasInCallFeedback,IPrivacy + public interface IHasVideoCodec : IHasInCallFeedback, IPrivacy { + /// + /// Gets the VideoCodecBase instance + /// VideoCodecBase VideoCodec { get; } - /// - /// Make this more specific - /// - //List ActiveCalls { get; } - /// /// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis /// diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs index 25a807a1..b2583a5d 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/IJoinCalls.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.Devices.Common.VideoCodec { @@ -13,7 +7,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public interface IJoinCalls { + /// + /// Joins a call + /// + /// The active call to join void JoinCall(CodecActiveCallItem activeCall); + + /// + /// Joins all calls + /// void JoinAllCalls(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/MeetingInfo.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/MeetingInfo.cs new file mode 100644 index 00000000..a65b6830 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/MeetingInfo.cs @@ -0,0 +1,106 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +{ + /// + /// Represents a MeetingInfo + /// + public class MeetingInfo + { + + /// + /// Gets or sets the Id + /// + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public string Id { get; private set; } + + /// + /// Gets or sets the Name + /// + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; private set; } + + /// + /// Gets or sets the Host + /// + [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)] + public string Host { get; private set; } + + /// + /// Gets or sets the Password + /// + [JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)] + public string Password { get; private set; } + + /// + /// Gets or sets the ShareStatus + /// + [JsonProperty("shareStatus", NullValueHandling = NullValueHandling.Ignore)] + public string ShareStatus { get; private set; } + + /// + /// Gets or sets the IsHost + /// + [JsonProperty("isHost", NullValueHandling = NullValueHandling.Ignore)] + public bool IsHost { get; private set; } + + /// + /// Gets or sets the IsSharingMeeting + /// + [JsonProperty("isSharingMeeting", NullValueHandling = NullValueHandling.Ignore)] + public bool IsSharingMeeting { get; private set; } + + /// + /// Gets or sets the WaitingForHost + /// + [JsonProperty("waitingForHost", NullValueHandling = NullValueHandling.Ignore)] + public bool WaitingForHost { get; private set; } + + /// + /// Gets or sets the IsLocked + /// + [JsonProperty("isLocked", NullValueHandling = NullValueHandling.Ignore)] + public bool IsLocked { get; private set; } + + /// + /// Gets or sets the IsRecording + /// + [JsonProperty("isRecording", NullValueHandling = NullValueHandling.Ignore)] + public bool IsRecording { get; private set; } + + /// + /// Gets or sets the CanRecord + /// + [JsonProperty("canRecord", NullValueHandling = NullValueHandling.Ignore)] + public bool CanRecord { get; private set; } + + /// + /// Constructor for MeetingInfo + /// + /// The unique identifier for the meeting + /// The name of the meeting + /// The host of the meeting + /// The password for the meeting + /// The share status of the meeting + /// Indicates whether the current user is the host + /// Indicates whether the meeting is currently being shared + /// Indicates whether the meeting is waiting for the host to join + /// Indicates whether the meeting is locked + /// Indicates whether the meeting is being recorded + /// Indicates whether the meeting can be recorded + public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost, bool isSharingMeeting, bool waitingForHost, bool isLocked, bool isRecording, bool canRecord) + { + Id = id; + Name = name; + Host = host; + Password = password; + ShareStatus = shareStatus; + IsHost = isHost; + IsSharingMeeting = isSharingMeeting; + WaitingForHost = waitingForHost; + IsLocked = isLocked; + IsRecording = isRecording; + CanRecord = CanRecord; + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/MeetingInfoEventArgs.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/MeetingInfoEventArgs.cs new file mode 100644 index 00000000..f483a564 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/MeetingInfoEventArgs.cs @@ -0,0 +1,27 @@ + + +using System; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +{ + /// + /// Represents a MeetingInfoEventArgs + /// + public class MeetingInfoEventArgs : EventArgs + { + /// + /// Gets or sets the Info + /// + public MeetingInfo Info { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The meeting information. + public MeetingInfoEventArgs(MeetingInfo info) + { + Info = info; + } + + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/Participant.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/Participant.cs new file mode 100644 index 00000000..2d266a95 --- /dev/null +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/Participant.cs @@ -0,0 +1,72 @@ +namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces +{ + /// + /// Represents a Participant + /// + public class Participant + { + /// + /// Gets or sets the UserId + /// + public int UserId { get; set; } + + /// + /// Gets or sets the IsHost + /// + public bool IsHost { get; set; } + + /// + /// Gets or sets the IsMyself + /// + public bool IsMyself { get; set; } + + /// + /// Gets or sets the Name + /// + public string Name { get; set; } + + /// + /// Gets or sets the Email + /// + public bool CanMuteVideo { get; set; } + + /// + /// Gets or sets the CanUnmuteVideo + /// + public bool CanUnmuteVideo { get; set; } + + /// + /// Gets or sets the CanMuteAudio + /// + public bool VideoMuteFb { get; set; } + + /// + /// Gets or sets the AudioMuteFb + /// + public bool AudioMuteFb { get; set; } + + /// + /// Gets or sets the HandIsRaisedFb + /// + public bool HandIsRaisedFb { get; set; } + + /// + /// Gets or sets the IsPinnedFb + /// + public bool IsPinnedFb { get; set; } + + /// + /// Gets or sets the ScreenIndexIsPinnedToFb + /// + public int ScreenIndexIsPinnedToFb { get; set; } + + /// + /// Initializes a new instance of the class + /// + public Participant() + { + // Initialize to -1 (no screen) + ScreenIndexIsPinnedToFb = -1; + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs index 8f004086..8b1be9e9 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/Interfaces/iVideoCodecInfo.cs @@ -1,12 +1,4 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using Newtonsoft.Json; +using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { @@ -15,6 +7,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public interface iVideoCodecInfo { + /// + /// Gets the codec information + /// VideoCodecInfo CodecInfo { get; } } @@ -23,18 +18,39 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public abstract class VideoCodecInfo { + /// + /// Gets a value indicating whether the multi-site option is enabled + /// [JsonProperty("multiSiteOptionIsEnabled", NullValueHandling = NullValueHandling.Ignore)] public abstract bool MultiSiteOptionIsEnabled { get; } + /// + /// Gets the IP address of the codec + /// [JsonProperty("ipAddress", NullValueHandling = NullValueHandling.Ignore)] public abstract string IpAddress { get; } + /// + /// Gets the SIP phone number for the codec + /// [JsonProperty("sipPhoneNumber", NullValueHandling = NullValueHandling.Ignore)] public abstract string SipPhoneNumber { get; } + /// + /// Gets the E164 alias for the codec + /// [JsonProperty("e164Alias", NullValueHandling = NullValueHandling.Ignore)] public abstract string E164Alias { get; } + /// + /// Gets the H323 ID for the codec + /// [JsonProperty("h323Id", NullValueHandling = NullValueHandling.Ignore)] public abstract string H323Id { get; } + /// + /// Gets the SIP URI for the codec + /// [JsonProperty("sipUri", NullValueHandling = NullValueHandling.Ignore)] public abstract string SipUri { get; } + /// + /// Gets a value indicating whether auto-answer is enabled + /// [JsonProperty("autoAnswerEnabled", NullValueHandling = NullValueHandling.Ignore)] public abstract bool AutoAnswerEnabled { get; } } diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs index 9b9aa8d7..185f089f 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockCodecDirectory.cs @@ -1,16 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Core; -using PepperDash.Essentials.Core; +using System.Collections.Generic; using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.Devices.Common.VideoCodec { + /// + /// Mock video codec directory structure + /// public static class MockVideoCodecDirectory { /// @@ -18,13 +14,37 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public enum eFolderId { + /// + /// The United States folder + /// UnitedStates, + /// + /// The Canada folder + /// Canada, + /// + /// The New York folder + /// NewYork, + /// + /// The Boston folder + /// Boston, + /// + /// The San Francisco folder + /// SanFrancisco, + /// + /// The Denver folder + /// Denver, + /// + /// The Austin folder + /// Austin, + /// + /// The Calgary folder + /// Calgary } @@ -51,16 +71,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } } - public static CodecDirectory DirectoryRoot + /// + /// The root of the directory structure + /// + public static CodecDirectory DirectoryRoot { get { var directory = new CodecDirectory(); - + directory.AddFoldersToDirectory - ( + ( new List() - { + { new DirectoryFolder() { FolderId = eFolderId.UnitedStates.ToString(), @@ -77,7 +100,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } } ); - + directory.AddContactsToDirectory ( new List() @@ -97,23 +120,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } } } - ); - + ); + return directory; - } + } } + /// + /// Contents of the United States folder + /// public static CodecDirectory UnitedStatesFolderContents { get { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.UnitedStates.ToString(); - directory.AddFoldersToDirectory - ( - new List() - { + var directory = new CodecDirectory + { + ResultsFolderId = eFolderId.UnitedStates.ToString() + }; + directory.AddFoldersToDirectory + ( + new List() + { new DirectoryFolder() { FolderId = eFolderId.NewYork.ToString(), @@ -149,24 +176,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec ParentFolderId = eFolderId.UnitedStates.ToString(), Contacts = null } - } - ); + } + ); return directory; } } + /// + /// Contents of the New York folder + /// public static CodecDirectory NewYorkFolderContents { get { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.NewYork.ToString(); + var directory = new CodecDirectory + { + ResultsFolderId = eFolderId.NewYork.ToString() + }; directory.AddContactsToDirectory - ( - new List() - { + ( + new List() + { new DirectoryContact() { ContactId = "nyc_1", @@ -215,24 +246,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } } } - } - ); + } + ); return directory; } } + /// + /// Contents of the Boston folder + /// public static CodecDirectory BostonFolderContents { get { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Boston.ToString(); + var directory = new CodecDirectory + { + ResultsFolderId = eFolderId.Boston.ToString() + }; directory.AddContactsToDirectory - ( - new List() - { + ( + new List() + { new DirectoryContact() { ContactId = "bos_1", @@ -249,24 +284,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } } } - } - ); + } + ); return directory; } } + /// + /// Contents of the San Francisco folder + /// public static CodecDirectory SanFranciscoFolderContents { get { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.SanFrancisco.ToString(); + var directory = new CodecDirectory + { + ResultsFolderId = eFolderId.SanFrancisco.ToString() + }; directory.AddContactsToDirectory - ( - new List() - { + ( + new List() + { new DirectoryContact() { ContactId = "sfo_1", @@ -282,25 +321,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec CallType = eContactMethodCallType.Video } } - } - } - ); + } + } + ); return directory; } } + /// + /// Contents of the Denver folder + /// public static CodecDirectory DenverFolderContents { get { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Denver.ToString(); + var directory = new CodecDirectory + { + ResultsFolderId = eFolderId.Denver.ToString() + }; directory.AddContactsToDirectory - ( - new List() - { + ( + new List() + { new DirectoryContact() { ContactId = "den_1", @@ -316,25 +359,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec CallType = eContactMethodCallType.Video } } - } - } - ); + } + } + ); return directory; } } + /// + /// Contents of the Austin folder + /// public static CodecDirectory AustinFolderContents { get { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Austin.ToString(); + var directory = new CodecDirectory + { + ResultsFolderId = eFolderId.Austin.ToString() + }; directory.AddContactsToDirectory - ( - new List() - { + ( + new List() + { new DirectoryContact() { ContactId = "atx_1", @@ -350,25 +397,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec CallType = eContactMethodCallType.Video } } - } - } - ); + } + } + ); return directory; } } + /// + /// Contents of the Canada folder + /// public static CodecDirectory CanadaFolderContents { get { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Canada.ToString(); + var directory = new CodecDirectory + { + ResultsFolderId = eFolderId.Canada.ToString() + }; directory.AddFoldersToDirectory - ( - new List() - { + ( + new List() + { new DirectoryFolder() { FolderId = eFolderId.Calgary.ToString(), @@ -376,24 +427,28 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec ParentFolderId = eFolderId.Canada.ToString(), Contacts = null } - } - ); + } + ); return directory; } } + /// + /// Contents of the Calgary folder + /// public static CodecDirectory CalgaryFolderContents { get { - var directory = new CodecDirectory(); - - directory.ResultsFolderId = eFolderId.Calgary.ToString(); + var directory = new CodecDirectory + { + ResultsFolderId = eFolderId.Calgary.ToString() + }; directory.AddContactsToDirectory - ( - new List() - { + ( + new List() + { new DirectoryContact() { ContactId = "cdn_1", @@ -409,14 +464,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec CallType = eContactMethodCallType.Video } } - } - } - ); + } + } + ); return directory; } } - - } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs index 0387c416..e9f7908c 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVC.cs @@ -3,19 +3,17 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Routing; -using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.Cameras; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using PepperDash.Essentials.Devices.Common.Codec; using Serilog.Events; namespace PepperDash.Essentials.Devices.Common.VideoCodec @@ -47,10 +45,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public RoutingOutputPort HdmiOut { get; private set; } - /// - /// Gets or sets the CallFavorites - /// - public CodecCallFavorites CallFavorites { get; private set; } + /// + /// Gets or sets the CallFavorites + /// + public CodecCallFavorites CallFavorites { get; private set; } /// /// @@ -62,22 +60,22 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec CodecInfo = new MockCodecInfo(); - // Get favoritesw + // Get favoritesw if (PropertiesConfig.Favorites != null) - { - CallFavorites = new CodecCallFavorites(); - CallFavorites.Favorites = PropertiesConfig.Favorites; - } + { + CallFavorites = new CodecCallFavorites(); + CallFavorites.Favorites = PropertiesConfig.Favorites; + } DirectoryBrowseHistory = new List(); // Debug helpers MuteFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Mute={0}", _IsMuted); PrivacyModeIsOnFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Privacy={0}", _PrivacyModeIsOn); - SharingSourceFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "SharingSource={0}", _SharingSource); + SharingSourceFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "SharingSource={0}", _SharingSource); VolumeLevelFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Debug, this, "Volume={0}", _VolumeLevel); - CurrentDirectoryResultIsNotDirectoryRoot = new BoolFeedback(() => DirectoryBrowseHistory.Count > 0); + CurrentDirectoryResultIsNotDirectoryRoot = new BoolFeedback("currentDirectoryResultIsNotDirectoryRoot", () => DirectoryBrowseHistory.Count > 0); CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); @@ -105,38 +103,44 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec CreateOsdSource(); SetIsReady(); - } + } + /// protected override Func MuteFeedbackFunc { get { return () => _IsMuted; } } bool _IsMuted; + /// protected override Func PrivacyModeIsOnFeedbackFunc { get { return () => _PrivacyModeIsOn; } } bool _PrivacyModeIsOn; - + + /// protected override Func SharingSourceFeedbackFunc { get { return () => _SharingSource; } } string _SharingSource; + /// protected override Func SharingContentIsOnFeedbackFunc { get { return () => _SharingIsOn; } } bool _SharingIsOn; + /// protected override Func VolumeLevelFeedbackFunc { get { return () => _VolumeLevel; } } int _VolumeLevel; + /// protected override Func StandbyIsOnFeedbackFunc { get { return () => _StandbyIsOn; } @@ -157,9 +161,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //foreach(var input in Status.Video. } - /// - /// Dial method - /// /// public override void Dial(string number) { @@ -177,9 +178,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec }, 2000); } - /// - /// Dial method - /// /// public override void Dial(Meeting meeting) { @@ -199,9 +197,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } - /// - /// EndCall method - /// /// public override void EndCall(CodecActiveCallItem call) { @@ -211,14 +206,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //ActiveCallCountFeedback.FireUpdate(); } - /// - /// EndAllCalls method - /// + /// public override void EndAllCalls() { Debug.LogMessage(LogEventLevel.Debug, this, "EndAllCalls"); - for(int i = ActiveCalls.Count - 1; i >= 0; i--) + for (int i = ActiveCalls.Count - 1; i >= 0; i--) { var call = ActiveCalls[i]; ActiveCalls.Remove(call); @@ -227,9 +220,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //ActiveCallCountFeedback.FireUpdate(); } - /// - /// AcceptCall method - /// + /// public override void AcceptCall(CodecActiveCallItem call) { @@ -239,9 +230,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec // should already be in active list } - /// - /// RejectCall method - /// /// public override void RejectCall(CodecActiveCallItem call) { @@ -251,65 +239,44 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //ActiveCallCountFeedback.FireUpdate(); } - /// - /// Makes horrible tones go out on the wire! - /// - /// - /// - /// SendDtmf method - /// + /// public override void SendDtmf(string s) { Debug.LogMessage(LogEventLevel.Debug, this, "SendDTMF: {0}", s); } - /// - /// - /// + /// public override void StartSharing() { _SharingIsOn = true; SharingContentIsOnFeedback.FireUpdate(); } - /// - /// - /// + /// public override void StopSharing() { _SharingIsOn = false; SharingContentIsOnFeedback.FireUpdate(); } + /// public override void StandbyActivate() { _StandbyIsOn = true; } - /// - /// StandbyDeactivate method - /// /// public override void StandbyDeactivate() { _StandbyIsOn = false; } - /// - /// LinkToApi method - /// + /// public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { throw new NotImplementedException(); } - /// - /// Called by routing to make it happen - /// - /// - /// - /// ExecuteSwitch method - /// /// public override void ExecuteSwitch(object selector) { @@ -317,40 +284,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec _SharingSource = selector.ToString(); } - /// - /// - /// + /// public override void MuteOff() { _IsMuted = false; MuteFeedback.FireUpdate(); } - /// - /// - /// + /// public override void MuteOn() { _IsMuted = true; MuteFeedback.FireUpdate(); } - /// - /// - /// + /// public override void MuteToggle() { _IsMuted = !_IsMuted; MuteFeedback.FireUpdate(); } - - /// - /// - /// - /// - /// - /// SetVolume method - /// + /// public override void SetVolume(ushort level) { @@ -358,29 +312,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec VolumeLevelFeedback.FireUpdate(); } - /// - /// - /// - /// - /// - /// VolumeDown method - /// /// public override void VolumeDown(bool pressRelease) { } - /// - /// - /// - /// + + /// public override void VolumeUp(bool pressRelease) { } - /// - /// - /// + /// public override void PrivacyModeOn() { Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteOn"); @@ -390,9 +333,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec PrivacyModeIsOnFeedback.FireUpdate(); } - /// - /// PrivacyModeOff method - /// + /// public override void PrivacyModeOff() { @@ -403,45 +344,37 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec PrivacyModeIsOnFeedback.FireUpdate(); } - /// - /// PrivacyModeToggle method - /// + /// public override void PrivacyModeToggle() { _PrivacyModeIsOn = !_PrivacyModeIsOn; - Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteToggle: {0}", _PrivacyModeIsOn); - PrivacyModeIsOnFeedback.FireUpdate(); + Debug.LogMessage(LogEventLevel.Debug, this, "PrivacyMuteToggle: {0}", _PrivacyModeIsOn); + PrivacyModeIsOnFeedback.FireUpdate(); } //******************************************************** // SIMULATION METHODS - /// - /// - /// - /// /// /// TestIncomingVideoCall method /// + /// public void TestIncomingVideoCall(string url) { Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingVideoCall from {0}", url); - var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type= eCodecCallType.Video, Direction = eCodecCallDirection.Incoming }; + var call = new CodecActiveCallItem() { Name = url, Id = url, Number = url, Type = eCodecCallType.Video, Direction = eCodecCallDirection.Incoming }; ActiveCalls.Add(call); SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Ringing, call); //OnCallStatusChange(eCodecCallStatus.Unknown, eCodecCallStatus.Ringing, call); - + } - /// - /// - /// - /// /// /// TestIncomingAudioCall method /// + /// public void TestIncomingAudioCall(string url) { Debug.LogMessage(LogEventLevel.Debug, this, "TestIncomingAudioCall from {0}", url); @@ -451,7 +384,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //OnCallStatusChange(eCodecCallStatus.Unknown, eCodecCallStatus.Ringing, call); } - + /// /// TestFarEndHangup method /// @@ -464,6 +397,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec #region IHasCallHistory Members + /// + /// CallHistory property + /// public CodecCallHistory CallHistory { get; private set; } /// @@ -471,12 +407,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry) { - + } #endregion - #region IHasScheduleAwareness Members + #region IHasScheduleAwareness Members /// /// GetSchedule method @@ -486,47 +422,59 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } - public CodecScheduleAwareness CodecSchedule - { - get { - // if the last meeting has past, generate a new list - if (_CodecSchedule == null || _CodecSchedule.Meetings.Count == 0 - || _CodecSchedule.Meetings[_CodecSchedule.Meetings.Count - 1].StartTime < DateTime.Now) - { - _CodecSchedule = new CodecScheduleAwareness(1000); - for (int i = 0; i < 5; i++) - { - var m = new Meeting(); + /// + /// CodecSchedule property + /// + public CodecScheduleAwareness CodecSchedule + { + get + { + // if the last meeting has past, generate a new list + if (_CodecSchedule == null || _CodecSchedule.Meetings.Count == 0 + || _CodecSchedule.Meetings[_CodecSchedule.Meetings.Count - 1].StartTime < DateTime.Now) + { + _CodecSchedule = new CodecScheduleAwareness(1000); + for (int i = 0; i < 5; i++) + { + var m = new Meeting(); m.MinutesBeforeMeeting = 5; m.Id = i.ToString(); m.Organizer = "Employee " + 1; - m.StartTime = DateTime.Now.AddMinutes(5).AddHours(i); - m.EndTime = DateTime.Now.AddHours(i).AddMinutes(50); - m.Title = "Meeting " + i; - m.Calls.Add(new Call() { Number = i + "meeting@fake.com"}); - _CodecSchedule.Meetings.Add(m); - } - } - return _CodecSchedule; - } - } - CodecScheduleAwareness _CodecSchedule; + m.StartTime = DateTime.Now.AddMinutes(5).AddHours(i); + m.EndTime = DateTime.Now.AddHours(i).AddMinutes(50); + m.Title = "Meeting " + i; + m.Calls.Add(new Call() { Number = i + "meeting@fake.com" }); + _CodecSchedule.Meetings.Add(m); + } + } + return _CodecSchedule; + } + } + CodecScheduleAwareness _CodecSchedule; - #endregion + #endregion #region IHasDirectory Members + /// + /// DirectoryResultReturned event. Fired when the directory result changes + /// public event EventHandler DirectoryResultReturned; - + /// + /// DirectoryRoot property. The root of the directory + /// public CodecDirectory DirectoryRoot { - get + get { return MockVideoCodecDirectory.DirectoryRoot; } } + /// + /// CurrentDirectoryResult property. The current directory result + /// public CodecDirectory CurrentDirectoryResult { get @@ -538,9 +486,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } } + /// + /// PhonebookSyncState property. The current state of the phonebook synchronization + /// public CodecPhonebookSyncState PhonebookSyncState { - get + get { var syncState = new CodecPhonebookSyncState(Key + "PhonebookSync"); @@ -554,8 +505,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } /// - /// SearchDirectory method + /// Search the directory for contacts that contain the search string /// + /// The search string to use public void SearchDirectory(string searchString) { var searchResults = new CodecDirectory(); @@ -577,8 +529,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } /// - /// GetDirectoryFolderContents method + /// Get the contents of the specified folder /// + /// The ID of the folder to get the contents of public void GetDirectoryFolderContents(string folderId) { var folderDirectory = new CodecDirectory(); @@ -606,7 +559,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } /// - /// SetCurrentDirectoryToRoot method + /// Set the current directory to the root /// public void SetCurrentDirectoryToRoot() { @@ -616,7 +569,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } /// - /// GetDirectoryParentFolderContents method + /// Get the contents of the parent folder /// public void GetDirectoryParentFolderContents() { @@ -656,16 +609,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public void OnDirectoryResultReturned(CodecDirectory result) { CurrentDirectoryResultIsNotDirectoryRoot.FireUpdate(); - - var handler = DirectoryResultReturned; - if (handler != null) + DirectoryResultReturned?.Invoke(this, new DirectoryEventArgs() { - handler(this, new DirectoryEventArgs() - { - Directory = result, - DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue - }); - } + Directory = result, + DirectoryIsOnRoot = !CurrentDirectoryResultIsNotDirectoryRoot.BoolValue + }); } #endregion @@ -686,11 +634,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec Cameras.Add(farEndCamera); - SelectedCameraFeedback = new StringFeedback(() => SelectedCamera.Key); + SelectedCameraFeedback = new StringFeedback("selectedCamera", () => SelectedCamera.Key); - ControllingFarEndCameraFeedback = new BoolFeedback(() => SelectedCamera is IAmFarEndCamera); + ControllingFarEndCameraFeedback = new BoolFeedback("controllingFarEndCamera", () => SelectedCamera is IAmFarEndCamera); - CameraAutoModeIsOnFeedback = new BoolFeedback(() => _CameraAutoModeIsOn); + CameraAutoModeIsOnFeedback = new BoolFeedback("cameraAutoModeIsOn", () => _CameraAutoModeIsOn); SupportsCameraAutoMode = true; @@ -728,10 +676,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec #region IHasCameras Members + /// + /// CameraSelected event. Fired when a camera is selected + /// public event EventHandler CameraSelected; /// - /// Gets or sets the Cameras + /// Gets the list of cameras associated with this codec /// public List Cameras { get; private set; } @@ -751,12 +702,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec _selectedCamera = value; SelectedCameraFeedback.FireUpdate(); ControllingFarEndCameraFeedback.FireUpdate(); - - var handler = CameraSelected; - if (handler != null) - { - handler(this, new CameraSelectedEventArgs(SelectedCamera)); - } + CameraSelected?.Invoke(this, new CameraSelectedEventArgs(SelectedCamera)); } } @@ -788,7 +734,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// Gets or sets the FarEndCamera /// public CameraBase FarEndCamera { get; private set; } - + /// /// Gets or sets the ControllingFarEndCameraFeedback /// @@ -823,7 +769,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public void CameraAutoModeToggle() { - if(_CameraAutoModeIsOn) + if (_CameraAutoModeIsOn) _CameraAutoModeIsOn = false; else _CameraAutoModeIsOn = true; @@ -835,12 +781,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// /// Gets or sets the CameraAutoModeIsOnFeedback /// - public BoolFeedback CameraAutoModeIsOnFeedback {get; private set;} + public BoolFeedback CameraAutoModeIsOnFeedback { get; private set; } #endregion #region IHasCameraPresets Members + /// + /// CodecRoomPresetsListHasChanged event. Fired when the presets list changes + /// public event EventHandler CodecRoomPresetsListHasChanged; /// @@ -883,11 +832,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec else NearEndPresets.Add(new CodecRoomPreset(preset, description, true, true)); - var handler = CodecRoomPresetsListHasChanged; - if (handler != null) - { - handler(this, new EventArgs()); - } + CodecRoomPresetsListHasChanged?.Invoke(this, new EventArgs()); // Update the config SetConfig(Config); @@ -903,6 +848,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec #endregion + /// protected override void CustomSetConfig(DeviceConfig config) { PropertiesConfig.Presets = NearEndPresets; @@ -920,11 +866,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public class MockCodecInfo : VideoCodecInfo { + /// public override bool MultiSiteOptionIsEnabled { get { return true; } } + /// public override string E164Alias { get { return "someE164alias"; } @@ -975,14 +923,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public class MockVCFactory : EssentialsDeviceFactory { + /// public MockVCFactory() { TypeNames = new List() { "mockvc" }; } - /// - /// BuildDevice method - /// /// public override EssentialsDevice BuildDevice(DeviceConfig dc) { diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs index 8b39e457..5c7e89d8 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVCCamera.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Devices.Common.VideoCodec; @@ -16,9 +11,17 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public class MockVCCamera : CameraBase, IHasCameraPtzControl, IHasCameraFocusControl, IBridgeAdvanced { + /// + /// Gets the parent video codec + /// protected VideoCodecBase ParentCodec { get; private set; } - + /// + /// Initializes a new instance of the MockVCCamera class + /// + /// The device key + /// The device name + /// The parent video codec public MockVCCamera(string key, string name, VideoCodecBase codec) : base(key, name) { @@ -173,9 +176,17 @@ namespace PepperDash.Essentials.Devices.Common.Cameras /// public class MockFarEndVCCamera : CameraBase, IHasCameraPtzControl, IAmFarEndCamera, IBridgeAdvanced { + /// + /// Gets the parent video codec + /// protected VideoCodecBase ParentCodec { get; private set; } - + /// + /// Initializes a new instance of the MockFarEndVCCamera class + /// + /// The device key + /// The device name + /// The parent video codec public MockFarEndVCCamera(string key, string name, VideoCodecBase codec) : base(key, name) { diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs index c34053fc..0c5654d6 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/MockVC/MockVcPropertiesConfig.cs @@ -1,14 +1,5 @@ - - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; +using System.Collections.Generic; using Newtonsoft.Json; - -using PepperDash.Core; -using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.Devices.Common.VideoCodec @@ -18,18 +9,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public class MockVcPropertiesConfig { - [JsonProperty("favorites")] /// /// Gets or sets the Favorites /// + [JsonProperty("favorites")] public List Favorites { get; set; } - [JsonProperty("presets")] /// /// Gets or sets the Presets /// + [JsonProperty("presets")] public List Presets { get; set; } + /// + /// Initializes a new instance of the class. + /// public MockVcPropertiesConfig() { Favorites = new List(); diff --git a/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs b/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs index 8de3afa5..b0b5ef55 100644 --- a/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs +++ b/src/PepperDash.Essentials.Devices.Common/VideoCodec/VideoCodecBase.cs @@ -1,57 +1,68 @@ using System; using System.Collections.Generic; using System.Linq; -using Crestron.SimplSharp.CrestronIO; -using Crestron.SimplSharp.Reflection; -using Crestron.SimplSharpPro.DeviceSupport; +using System.Text; using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharpPro.DeviceSupport; using PepperDash.Core; using PepperDash.Core.Intersystem; using PepperDash.Core.Intersystem.Tokens; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Bridges.JoinMaps; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; -using PepperDash.Essentials.Core.Bridges.JoinMaps; -using Feedback = PepperDash.Essentials.Core.Feedback; using Serilog.Events; -using PepperDash.Essentials.Core.Routing; -using System.Text; +using Feedback = PepperDash.Essentials.Core.Feedback; namespace PepperDash.Essentials.Devices.Common.VideoCodec { + /// + /// Base class for video codec devices + /// public abstract class VideoCodecBase : ReconfigurableDevice, IRoutingInputsOutputs, IUsageTracking, IHasDialer, IHasContentSharing, ICodecAudio, iVideoCodecInfo, IBridgeAdvanced, IHasStandbyMode { private const int XSigEncoding = 28591; - protected const int MaxParticipants = 50; + + /// + /// Maximum number of participants + /// + protected const int MaxParticipants = 50; private readonly byte[] _clearBytes = XSigHelpers.ClearOutputs(); - private readonly IHasDirectory _directoryCodec; - private readonly BasicTriList _directoryTrilist; - private readonly VideoCodecControllerJoinMap _directoryJoinmap; - - protected string _timeFormatSpecifier; - protected string _dateFormatSpecifier; + /// + /// Time format specifier + /// + protected string _timeFormatSpecifier; + /// + /// Date format specifier + /// + protected string _dateFormatSpecifier; + /// + /// Initializes a new instance of the class. + /// protected VideoCodecBase(DeviceConfig config) : base(config) { - StandbyIsOnFeedback = new BoolFeedback(StandbyIsOnFeedbackFunc); - PrivacyModeIsOnFeedback = new BoolFeedback(PrivacyModeIsOnFeedbackFunc); - VolumeLevelFeedback = new IntFeedback(VolumeLevelFeedbackFunc); - MuteFeedback = new BoolFeedback(MuteFeedbackFunc); - SharingSourceFeedback = new StringFeedback(SharingSourceFeedbackFunc); - SharingContentIsOnFeedback = new BoolFeedback(SharingContentIsOnFeedbackFunc); + StandbyIsOnFeedback = new BoolFeedback("standbyIsOn", StandbyIsOnFeedbackFunc); + PrivacyModeIsOnFeedback = new BoolFeedback("privacyModeIsOn", PrivacyModeIsOnFeedbackFunc); + VolumeLevelFeedback = new IntFeedback("volumeLevel", VolumeLevelFeedbackFunc); + MuteFeedback = new BoolFeedback("mute", MuteFeedbackFunc); + SharingSourceFeedback = new StringFeedback("sharingSource", SharingSourceFeedbackFunc); + SharingContentIsOnFeedback = new BoolFeedback("sharingContentIsOn", SharingContentIsOnFeedbackFunc); - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - MeetingsToDisplayFeedback = new IntFeedback(() => MeetingsToDisplay); + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + MeetingsToDisplayFeedback = new IntFeedback("meetingsToDisplay", () => MeetingsToDisplay); InputPorts = new RoutingPortCollection(); OutputPorts = new RoutingPortCollection(); @@ -59,115 +70,177 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec ActiveCalls = new List(); } - /// - /// Gets or sets the Communication - /// + /// + /// Gets or sets the Communication + /// public IBasicCommunication Communication { get; protected set; } - /// - /// Gets or sets the OsdSource - /// + /// + /// Gets or sets the OsdSource + /// public DummyRoutingInputsDevice OsdSource { get; protected set; } - /// - /// Gets or sets the StandbyIsOnFeedback - /// + /// + /// Gets or sets the StandbyIsOnFeedback + /// public BoolFeedback StandbyIsOnFeedback { get; private set; } + /// + /// Gets or sets the PrivacyModeIsOnFeedbackFunc + /// protected abstract Func PrivacyModeIsOnFeedbackFunc { get; } + + /// + /// Gets or sets the VolumeLevelFeedbackFunc + /// protected abstract Func VolumeLevelFeedbackFunc { get; } + + /// + /// Gets or sets the MuteFeedbackFunc + /// protected abstract Func MuteFeedbackFunc { get; } + + /// + /// Gets or sets the StandbyIsOnFeedbackFunc + /// protected abstract Func StandbyIsOnFeedbackFunc { get; } + /// + /// Gets or sets the ActiveCalls + /// public List ActiveCalls { get; set; } - /// - /// Gets or sets the ShowSelfViewByDefault - /// + /// + /// Gets or sets the ShowSelfViewByDefault + /// public bool ShowSelfViewByDefault { get; protected set; } - /// - /// Gets or sets the SupportsCameraOff - /// - public bool SupportsCameraOff { get; protected set; } - /// - /// Gets or sets the SupportsCameraAutoMode - /// - public bool SupportsCameraAutoMode { get; protected set; } + /// + /// Gets or sets the SupportsCameraOff + /// + public bool SupportsCameraOff { get; protected set; } + /// + /// Gets or sets the SupportsCameraAutoMode + /// + public bool SupportsCameraAutoMode { get; protected set; } - /// - /// Gets or sets the IsReady - /// + /// + /// Gets or sets the IsReady + /// public bool IsReady { get; protected set; } + /// public virtual List Feedbacks { get { return new List - { - PrivacyModeIsOnFeedback, - SharingSourceFeedback - }; + { + PrivacyModeIsOnFeedback, + SharingSourceFeedback + }; } } + /// + /// Gets or sets the MeetingsToDisplay + /// protected abstract Func SharingSourceFeedbackFunc { get; } + + /// + /// Gets or sets the SharingContentIsOnFeedbackFunc + /// protected abstract Func SharingContentIsOnFeedbackFunc { get; } #region ICodecAudio Members + /// + /// Set Privacy Mode On + /// public abstract void PrivacyModeOn(); + + /// + /// Set Privacy Mode Off + /// public abstract void PrivacyModeOff(); + + /// + /// Toggles the Privacy Mode + /// public abstract void PrivacyModeToggle(); - /// - /// Gets or sets the PrivacyModeIsOnFeedback - /// + + /// + /// Gets or sets the PrivacyModeIsOnFeedback + /// public BoolFeedback PrivacyModeIsOnFeedback { get; private set; } - - /// - /// Gets or sets the MuteFeedback - /// + /// + /// Gets or sets the MuteFeedback + /// public BoolFeedback MuteFeedback { get; private set; } + /// + /// Sets the Mute state to Off + /// public abstract void MuteOff(); + /// + /// Sets the Mute state to On + /// public abstract void MuteOn(); + /// + /// Sets the Volume level + /// public abstract void SetVolume(ushort level); - /// - /// Gets or sets the VolumeLevelFeedback - /// + /// + /// Gets or sets the VolumeLevelFeedback + /// public IntFeedback VolumeLevelFeedback { get; private set; } + /// + /// Toggles the Mute state + /// public abstract void MuteToggle(); + /// + /// Decreases the Volume level + /// public abstract void VolumeDown(bool pressRelease); - + /// + /// Increases the Volume level + /// public abstract void VolumeUp(bool pressRelease); #endregion #region IHasContentSharing Members + /// + /// Starts content sharing + /// public abstract void StartSharing(); + + /// + /// Stops content sharing + /// public abstract void StopSharing(); - /// - /// Gets or sets the AutoShareContentWhileInCall - /// + /// + /// Gets or sets the AutoShareContentWhileInCall + /// public bool AutoShareContentWhileInCall { get; protected set; } - /// - /// Gets or sets the SharingSourceFeedback - /// + /// + /// Gets or sets the SharingSourceFeedback + /// public StringFeedback SharingSourceFeedback { get; private set; } - /// - /// Gets or sets the SharingContentIsOnFeedback - /// + + /// + /// Gets or sets the SharingContentIsOnFeedback + /// public BoolFeedback SharingContentIsOnFeedback { get; private set; } #endregion @@ -191,60 +264,95 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } } + /// + /// Dials the specified number + /// public abstract void Dial(string number); + + /// + /// Ends the specified call + /// public abstract void EndCall(CodecActiveCallItem call); + + /// + /// Ends all active calls + /// public abstract void EndAllCalls(); + + /// + /// Accepts the specified call + /// public abstract void AcceptCall(CodecActiveCallItem call); + + /// + /// Rejects the specified call + /// public abstract void RejectCall(CodecActiveCallItem call); + + /// + /// Sends DTMF tones + /// public abstract void SendDtmf(string s); - /// - /// SendDtmf method - /// - /// - public virtual void SendDtmf(string s, CodecActiveCallItem call) { } + + /// + /// SendDtmf method + /// + public virtual void SendDtmf(string s, CodecActiveCallItem call) { } #endregion #region IRoutingInputsOutputs Members - /// - /// Gets or sets the InputPorts - /// + /// + /// Gets or sets the InputPorts + /// public RoutingPortCollection InputPorts { get; private set; } - /// - /// Gets or sets the OutputPorts - /// + /// + /// Gets or sets the OutputPorts + /// public RoutingPortCollection OutputPorts { get; private set; } #endregion #region IUsageTracking Members - /// - /// Gets or sets the UsageTracker - /// + /// + /// Gets or sets the UsageTracker + /// public UsageTracking UsageTracker { get; set; } #endregion #region iVideoCodecInfo Members + /// + /// Gets the CodecInfo + /// public VideoCodecInfo CodecInfo { get; protected set; } #endregion + /// + /// Fired when the Codec is ready to be used + /// public event EventHandler IsReadyChange; + + /// + /// Dials the specified meeting + /// + /// public abstract void Dial(Meeting meeting); - /// - /// Dial method - /// - /// + /// + /// Dial a contact + /// + /// The contact to dial public virtual void Dial(IInvitableContact contact) { } + /// public abstract void ExecuteSwitch(object selector); /// @@ -258,16 +366,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } /// - /// - /// - /// - /// + /// Sets the previous and new status for the call + /// /// protected virtual void OnCallStatusChange(CodecActiveCallItem item) { - CallStatusChange?.Invoke(this, new CodecCallStatusItemChangeEventArgs(item)); + CallStatusChange?.Invoke(this, new CodecCallStatusItemChangeEventArgs(item)); - PrivacyModeIsOnFeedback.FireUpdate(); + PrivacyModeIsOnFeedback.FireUpdate(); if (AutoShareContentWhileInCall) { @@ -297,8 +403,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec try { IsReady = true; - IsReadyChange?.Invoke(this, new EventArgs()); - } + IsReadyChange?.Invoke(this, new EventArgs()); + } catch (Exception e) { Debug.LogMessage(LogEventLevel.Verbose, this, "Error in SetIsReady() : {0}", e); @@ -307,13 +413,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } // **** DEBUGGING THINGS **** - /// - /// ListCalls method - /// - /// + /// + /// ListCalls method + /// public virtual void ListCalls() { - Debug.LogMessage(LogEventLevel.Debug, this, "Active Calls:"); + Debug.LogMessage(LogEventLevel.Debug, this, "Active Calls:"); var sb = new StringBuilder(); foreach (var c in ActiveCalls) @@ -323,22 +428,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec Debug.LogMessage(LogEventLevel.Debug, this, "\n{0}\n", sb.ToString()); } + /// + /// Activate standby + /// public abstract void StandbyActivate(); + /// + /// Deactivate standby + /// public abstract void StandbyDeactivate(); #region Implementation of IBridgeAdvanced + /// public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge); /// /// Use this method when using a plain VideoCodecControllerJoinMap /// - /// - /// - /// - /// - /// + /// codec to link + /// trilist to link + /// join to start with + /// key for custom join maps + /// bridge controller protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { @@ -355,18 +467,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec LinkVideoCodecToApi(codec, trilist, joinMap); - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; - }; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; + }; } /// /// Use this method when you need to pass in a join map that extends VideoCodecControllerJoinMap /// - /// - /// - /// + /// codec to link + /// trilist to link + /// join map to use protected void LinkVideoCodecToApi(VideoCodecBase codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { Debug.LogMessage(LogEventLevel.Debug, this, "Linking to Trilist {0}", trilist.ID.ToString("X")); @@ -381,16 +493,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec LinkVideoCodecVolumeToApi(trilist, joinMap); - LinkVideoCodecInfoToApi(trilist, joinMap); + LinkVideoCodecInfoToApi(trilist, joinMap); - // Register for this event to link any functions that require the codec to be ready first - codec.IsReadyChange += (o, a) => - { - if (codec is IHasCodecCameras) - { - LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); - } - }; + // Register for this event to link any functions that require the codec to be ready first + codec.IsReadyChange += (o, a) => + { + if (codec is IHasCodecCameras) + { + LinkVideoCodecCameraToApi(codec as IHasCodecCameras, trilist, joinMap); + } + }; if (codec is ICommunicationMonitor) { @@ -451,10 +563,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec LinkVideoCodecPhoneToApi(codec as IHasPhoneDialing, trilist, joinMap); } - if (codec is IHasCallHistory) - { - LinkVideoCodecCallHistoryToApi(codec as IHasCallHistory, trilist, joinMap); - } + if (codec is IHasCallHistory) + { + LinkVideoCodecCallHistoryToApi(codec as IHasCallHistory, trilist, joinMap); + } trilist.OnlineStatusChange += (device, args) => { @@ -502,39 +614,39 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec (codec as IHasPhoneDialing).PhoneOffHookFeedback.FireUpdate(); } - if (codec is IHasCallHistory) - { - UpdateCallHistory((codec as IHasCallHistory), trilist, joinMap); - } + if (codec is IHasCallHistory) + { + UpdateCallHistory((codec as IHasCallHistory), trilist, joinMap); + } SharingContentIsOnFeedback.FireUpdate(); }; } - private void LinkVideoCodecInfoToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); - trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); - trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); - trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); - trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); - trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); - trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); + private void LinkVideoCodecInfoToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); + trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); + trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); + trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); + trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); + trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); + trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); - trilist.OnlineStatusChange += (o, a) => - { - if (a.DeviceOnLine) - { - trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); - trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); - trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); - trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); - trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); - trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); - trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); - } - }; - } + trilist.OnlineStatusChange += (o, a) => + { + if (a.DeviceOnLine) + { + trilist.SetBool(joinMap.MultiSiteOptionIsEnabled.JoinNumber, this.CodecInfo.MultiSiteOptionIsEnabled); + trilist.SetBool(joinMap.AutoAnswerEnabled.JoinNumber, this.CodecInfo.AutoAnswerEnabled); + trilist.SetString(joinMap.DeviceIpAddresss.JoinNumber, this.CodecInfo.IpAddress); + trilist.SetString(joinMap.SipPhoneNumber.JoinNumber, this.CodecInfo.SipPhoneNumber); + trilist.SetString(joinMap.E164Alias.JoinNumber, this.CodecInfo.E164Alias); + trilist.SetString(joinMap.H323Id.JoinNumber, this.CodecInfo.H323Id); + trilist.SetString(joinMap.SipUri.JoinNumber, this.CodecInfo.SipUri); + } + }; + } private void LinkVideoCodecPhoneToApi(IHasPhoneDialing codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { @@ -570,9 +682,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - if (!(codec is IHasCameraAutoMode autoCodec)) return; + if (!(codec is IHasCameraAutoMode autoCodec)) return; - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoCodec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoCodec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoCodec.CameraAutoModeIsOnFeedback.BoolValue); }; @@ -587,9 +699,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - if (!(codec is IHasCameraAutoMode autoModeCodec)) return; + if (!(codec is IHasCameraAutoMode autoModeCodec)) return; - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !autoModeCodec.CameraAutoModeIsOnFeedback.BoolValue); } @@ -628,35 +740,35 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec private void LinkVideoCodecParticipantsToApi(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { - // make sure to update the values when the EISC comes online - trilist.OnlineStatusChange += (sender, args) => - { - if (sender.IsOnline) - { - UpdateParticipantsXSig(codec, trilist, joinMap); - } - }; + // make sure to update the values when the EISC comes online + trilist.OnlineStatusChange += (sender, args) => + { + if (sender.IsOnline) + { + UpdateParticipantsXSig(codec, trilist, joinMap); + } + }; - // set actions and update the values when the list changes + // set actions and update the values when the list changes codec.Participants.ParticipantsListHasChanged += (sender, args) => { - SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants); + SetParticipantActions(trilist, joinMap, codec.Participants.CurrentParticipants); - UpdateParticipantsXSig(codec, trilist, joinMap); + UpdateParticipantsXSig(codec, trilist, joinMap); }; - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; - // TODO [ ] Issue #868 - trilist.SetString(joinMap.CurrentParticipants.JoinNumber, "\xFC"); - UpdateParticipantsXSig(codec, trilist, joinMap); - }; + // TODO [ ] Issue #868 + trilist.SetString(joinMap.CurrentParticipants.JoinNumber, "\xFC"); + UpdateParticipantsXSig(codec, trilist, joinMap); + }; } - private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { + private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { string participantsXSig; if (codec.Participants.CurrentParticipants.Count == 0) @@ -672,48 +784,48 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetString(joinMap.CurrentParticipants.JoinNumber, participantsXSig); trilist.SetUshort(joinMap.ParticipantCount.JoinNumber, (ushort)codec.Participants.CurrentParticipants.Count); - } + } - /// - /// Sets the actions for each participant in the list - /// - private void SetParticipantActions(BasicTriList trilist, VideoCodecControllerJoinMap joinMap, List currentParticipants) - { - uint index = 0; // track the index of the participant in the + /// + /// Sets the actions for each participant in the list + /// + private void SetParticipantActions(BasicTriList trilist, VideoCodecControllerJoinMap joinMap, List currentParticipants) + { + uint index = 0; // track the index of the participant in the - foreach (var participant in currentParticipants) - { - var p = participant; - if (index > MaxParticipants) break; + foreach (var participant in currentParticipants) + { + var p = participant; + if (index > MaxParticipants) break; - if (this is IHasParticipantAudioMute audioMuteCodec) - { - trilist.SetSigFalseAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index, - () => audioMuteCodec.ToggleAudioForParticipant(p.UserId)); + if (this is IHasParticipantAudioMute audioMuteCodec) + { + trilist.SetSigFalseAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index, + () => audioMuteCodec.ToggleAudioForParticipant(p.UserId)); - trilist.SetSigFalseAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index, - () => audioMuteCodec.ToggleVideoForParticipant(p.UserId)); - } + trilist.SetSigFalseAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index, + () => audioMuteCodec.ToggleVideoForParticipant(p.UserId)); + } - if (this is IHasParticipantPinUnpin pinCodec) - { - trilist.SetSigFalseAction(joinMap.ParticipantPinToggleStart.JoinNumber + index, - () => pinCodec.ToggleParticipantPinState(p.UserId, pinCodec.ScreenIndexToPinUserTo)); - } + if (this is IHasParticipantPinUnpin pinCodec) + { + trilist.SetSigFalseAction(joinMap.ParticipantPinToggleStart.JoinNumber + index, + () => pinCodec.ToggleParticipantPinState(p.UserId, pinCodec.ScreenIndexToPinUserTo)); + } - index++; - } + index++; + } - // Clear out any previously set actions - while (index < MaxParticipants) - { - trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index); - trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index); - trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index); + // Clear out any previously set actions + while (index < MaxParticipants) + { + trilist.ClearBoolSigAction(joinMap.ParticipantAudioMuteToggleStart.JoinNumber + index); + trilist.ClearBoolSigAction(joinMap.ParticipantVideoMuteToggleStart.JoinNumber + index); + trilist.ClearBoolSigAction(joinMap.ParticipantPinToggleStart.JoinNumber + index); - index++; - } - } + index++; + } + } private string UpdateParticipantsXSig(List currentParticipants) { @@ -733,37 +845,37 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (meetingIndex >= maxParticipants * offset) break; - // Debug.LogMessage(LogEventLevel.Verbose, this, - //@"Updating Participant on xsig: - //Name: {0} (s{9}) - //AudioMute: {1} (d{10}) - //VideoMute: {2} (d{11}) - //CanMuteVideo: {3} (d{12}) - //CanUMuteVideo: {4} (d{13}) - //IsHost: {5} (d{14}) - //HandIsRaised: {6} (d{15}) - //IsPinned: {7} (d{16}) - //ScreenIndexIsPinnedTo: {8} (a{17}) - //", - // participant.Name, - // participant.AudioMuteFb, - // participant.VideoMuteFb, - // participant.CanMuteVideo, - // participant.CanUnmuteVideo, - // participant.IsHost, - // participant.HandIsRaisedFb, - // participant.IsPinnedFb, - // participant.ScreenIndexIsPinnedToFb, - // stringIndex + 1, - // digitalIndex + 1, - // digitalIndex + 2, - // digitalIndex + 3, - // digitalIndex + 4, - // digitalIndex + 5, - // digitalIndex + 6, - // digitalIndex + 7, - // analogIndex + 1 - // ); + // Debug.LogMessage(LogEventLevel.Verbose, this, + //@"Updating Participant on xsig: + //Name: {0} (s{9}) + //AudioMute: {1} (d{10}) + //VideoMute: {2} (d{11}) + //CanMuteVideo: {3} (d{12}) + //CanUMuteVideo: {4} (d{13}) + //IsHost: {5} (d{14}) + //HandIsRaised: {6} (d{15}) + //IsPinned: {7} (d{16}) + //ScreenIndexIsPinnedTo: {8} (a{17}) + //", + // participant.Name, + // participant.AudioMuteFb, + // participant.VideoMuteFb, + // participant.CanMuteVideo, + // participant.CanUnmuteVideo, + // participant.IsHost, + // participant.HandIsRaisedFb, + // participant.IsPinnedFb, + // participant.ScreenIndexIsPinnedToFb, + // stringIndex + 1, + // digitalIndex + 1, + // digitalIndex + 2, + // digitalIndex + 3, + // digitalIndex + 4, + // digitalIndex + 5, + // digitalIndex + 6, + // digitalIndex + 7, + // analogIndex + 1 + // ); //digitals @@ -772,10 +884,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec tokenArray[digitalIndex + 2] = new XSigDigitalToken(digitalIndex + 3, participant.CanMuteVideo); tokenArray[digitalIndex + 3] = new XSigDigitalToken(digitalIndex + 4, participant.CanUnmuteVideo); tokenArray[digitalIndex + 4] = new XSigDigitalToken(digitalIndex + 5, participant.IsHost); - tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, participant.HandIsRaisedFb); - tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, participant.IsPinnedFb); + tokenArray[digitalIndex + 5] = new XSigDigitalToken(digitalIndex + 6, participant.HandIsRaisedFb); + tokenArray[digitalIndex + 6] = new XSigDigitalToken(digitalIndex + 7, participant.IsPinnedFb); - Debug.LogMessage(LogEventLevel.Verbose, this, "Index: {0} byte value: {1}", digitalIndex + 7, ComTextHelper.GetEscapedText(tokenArray[digitalIndex + 6].GetBytes())); + Debug.LogMessage(LogEventLevel.Verbose, this, "Index: {0} byte value: {1}", digitalIndex + 7, ComTextHelper.GetEscapedText(tokenArray[digitalIndex + 6].GetBytes())); //serials tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, participant.Name); @@ -812,12 +924,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec analogIndex += maxAnalogs; } - var returnString = GetXSigString(tokenArray); + var returnString = GetXSigString(tokenArray); - //Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", ComTextHelper.GetEscapedText(Encoding.GetEncoding(28591).GetBytes(returnString))); + //Debug.LogMessage(LogEventLevel.Verbose, this, "{0}", ComTextHelper.GetEscapedText(Encoding.GetEncoding(28591).GetBytes(returnString))); - return returnString; + return returnString; } private void LinkVideoCodecContentSharingToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) @@ -833,7 +945,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetBoolSigAction(joinMap.SourceShareAutoStart.JoinNumber, b => AutoShareContentWhileInCall = b); } - private List _currentMeetings = new List(); + private List _currentMeetings = new List(); private void LinkVideoCodecScheduleToApi(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { @@ -841,25 +953,25 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetUShortSigAction(joinMap.MinutesBeforeMeetingStart.JoinNumber, (i) => { - codec.CodecSchedule.MeetingWarningMinutes = i; + codec.CodecSchedule.MeetingWarningMinutes = i; }); - for (uint i = 0; i < joinMap.DialMeetingStart.JoinSpan; i++) - { - Debug.LogMessage(LogEventLevel.Debug, this, "Setting action to Dial Meeting {0} to digital join {1}", i + 1, joinMap.DialMeetingStart.JoinNumber + i); - var joinNumber = joinMap.DialMeetingStart.JoinNumber + i; - var mtg = i + 1; - var index = (int)i; + for (uint i = 0; i < joinMap.DialMeetingStart.JoinSpan; i++) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Setting action to Dial Meeting {0} to digital join {1}", i + 1, joinMap.DialMeetingStart.JoinNumber + i); + var joinNumber = joinMap.DialMeetingStart.JoinNumber + i; + var mtg = i + 1; + var index = (int)i; - trilist.SetSigFalseAction(joinNumber, () => - { - Debug.LogMessage(LogEventLevel.Debug, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", - mtg, joinMap.DialMeetingStart.JoinNumber + i, index, _currentMeetings[index].Id, _currentMeetings[index].Title); - if (_currentMeetings[index] != null) - Dial(_currentMeetings[index]); - }); - } + trilist.SetSigFalseAction(joinNumber, () => + { + Debug.LogMessage(LogEventLevel.Debug, this, "Meeting {0} Selected (EISC dig-o{1}) > _currentMeetings[{2}].Id: {3}, Title: {4}", + mtg, joinMap.DialMeetingStart.JoinNumber + i, index, _currentMeetings[index].Id, _currentMeetings[index].Title); + if (_currentMeetings[index] != null) + Dial(_currentMeetings[index]); + }); + } codec.CodecSchedule.MeetingsListHasChanged += (sender, args) => UpdateMeetingsList(codec, trilist, joinMap); codec.CodecSchedule.MeetingEventChange += (sender, args) => @@ -870,20 +982,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } }; - trilist.SetUShortSigAction(joinMap.MeetingsToDisplay.JoinNumber, m => MeetingsToDisplay = m); - MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); + trilist.SetUShortSigAction(joinMap.MeetingsToDisplay.JoinNumber, m => MeetingsToDisplay = m); + MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; - // TODO [ ] Issue #868 - trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); - UpdateMeetingsList(codec, trilist, joinMap); - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); - }; - } + // TODO [ ] Issue #868 + trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); + UpdateMeetingsList(codec, trilist, joinMap); + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]); + }; + } private void UpdateMeetingsList(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { @@ -891,175 +1003,178 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec _currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); - if (_currentMeetings.Count == 0) - { - var emptyXSigByteArray = XSigHelpers.ClearOutputs(); - var emptyXSigString = Encoding.GetEncoding(XSigEncoding) - .GetString(emptyXSigByteArray, 0, emptyXSigByteArray.Length); + if (_currentMeetings.Count == 0) + { + var emptyXSigByteArray = XSigHelpers.ClearOutputs(); + var emptyXSigString = Encoding.GetEncoding(XSigEncoding) + .GetString(emptyXSigByteArray, 0, emptyXSigByteArray.Length); - trilist.SetString(joinMap.Schedule.JoinNumber, emptyXSigString); - return; - } + trilist.SetString(joinMap.Schedule.JoinNumber, emptyXSigString); + return; + } var meetingsData = UpdateMeetingsListXSig(_currentMeetings); trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData); trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)_currentMeetings.Count); - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; - // TODO [ ] Issue #868 - trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); - UpdateMeetingsListXSig(_currentMeetings); - }; + // TODO [ ] Issue #868 + trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC"); + UpdateMeetingsListXSig(_currentMeetings); + }; } - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - private int _meetingsToDisplay = 3; - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - protected int MeetingsToDisplay - { - get { return _meetingsToDisplay; } - set { - _meetingsToDisplay = (ushort) (value == 0 ? 3 : value); - MeetingsToDisplayFeedback.FireUpdate(); - } - } - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - /// - /// Gets or sets the MeetingsToDisplayFeedback - /// - public IntFeedback MeetingsToDisplayFeedback { get; set; } + private int _meetingsToDisplay = 3; - private string UpdateMeetingsListXSig(List meetings) - { - // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set - //const int _meetingsToDisplay = 3; - const int maxDigitals = 2; - const int maxStrings = 7; - const int offset = maxDigitals + maxStrings; - var digitalIndex = maxStrings * _meetingsToDisplay; //15 - var stringIndex = 0; - var meetingIndex = 0; + /// + /// Gets or sets the number of meetings to display on the XSIG + /// + protected int MeetingsToDisplay + { + get { return _meetingsToDisplay; } + set + { + _meetingsToDisplay = (ushort)(value == 0 ? 3 : value); + MeetingsToDisplayFeedback.FireUpdate(); + } + } - var tokenArray = new XSigToken[_meetingsToDisplay * offset]; - /* - * Digitals - * IsJoinable - 1 - * IsDialable - 2 - * - * Serials - * Organizer - 1 - * Title - 2 - * Start Date - 3 - * Start Time - 4 - * End Date - 5 - * End Time - 6 - * Id - 7 - */ - + /// + /// Gets or sets the MeetingsToDisplayFeedback + /// + public IntFeedback MeetingsToDisplayFeedback { get; set; } - foreach (var meeting in meetings) - { - var currentTime = DateTime.Now; + private string UpdateMeetingsListXSig(List meetings) + { + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + //const int _meetingsToDisplay = 3; + const int maxDigitals = 2; + const int maxStrings = 7; + const int offset = maxDigitals + maxStrings; + var digitalIndex = maxStrings * _meetingsToDisplay; //15 + var stringIndex = 0; + var meetingIndex = 0; - if (meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue; + var tokenArray = new XSigToken[_meetingsToDisplay * offset]; + /* + * Digitals + * IsJoinable - 1 + * IsDialable - 2 + * + * Serials + * Organizer - 1 + * Title - 2 + * Start Date - 3 + * Start Time - 4 + * End Date - 5 + * End Time - 6 + * Id - 7 + */ - if (meetingIndex >= _meetingsToDisplay * offset) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Max Meetings reached"); - break; - } - //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, meeting.Joinable); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, meeting.Dialable); + foreach (var meeting in meetings) + { + var currentTime = DateTime.Now; - //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer); - tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); - tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); - tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); - tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id); + if (meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue; - digitalIndex += maxDigitals; - meetingIndex += offset; - stringIndex += maxStrings; - } + if (meetingIndex >= _meetingsToDisplay * offset) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Max Meetings reached"); + break; + } - while (meetingIndex < _meetingsToDisplay * offset) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}", - meetingIndex, _meetingsToDisplay * offset); + //digitals + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, meeting.Joinable); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, meeting.Dialable); - //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, meeting.Organizer); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, meeting.Title); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, meeting.StartTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, meeting.StartTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, meeting.EndTime.ToString(_dateFormatSpecifier.NullIfEmpty() ?? "d", Global.Culture)); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, meeting.EndTime.ToString(_timeFormatSpecifier.NullIfEmpty() ?? "t", Global.Culture)); + tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, meeting.Id); - //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); - tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); - tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); - tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); - tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, String.Empty); + digitalIndex += maxDigitals; + meetingIndex += offset; + stringIndex += maxStrings; + } - digitalIndex += maxDigitals; - meetingIndex += offset; - stringIndex += maxStrings; - } + while (meetingIndex < _meetingsToDisplay * offset) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}", + meetingIndex, _meetingsToDisplay * offset); - return GetXSigString(tokenArray); - } + //digitals + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); + + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); + tokenArray[stringIndex + 6] = new XSigSerialToken(stringIndex + 7, String.Empty); + + digitalIndex += maxDigitals; + meetingIndex += offset; + stringIndex += maxStrings; + } + + return GetXSigString(tokenArray); + } private void LinkVideoCodecDirectoryToApi(IHasDirectory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { codec.CurrentDirectoryResultIsNotDirectoryRoot.LinkComplementInputSig( - trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]); + trilist.BooleanInput[joinMap.DirectoryIsRoot.JoinNumber]); trilist.SetStringSigAction(joinMap.DirectorySearchString.JoinNumber, codec.SearchDirectory); trilist.SetUShortSigAction(joinMap.DirectorySelectRow.JoinNumber, (i) => SelectDirectoryEntry(codec, i, trilist, joinMap)); - //Special Change for protected directory clear + //Special Change for protected directory clear - trilist.SetBoolSigAction(joinMap.DirectoryClearSelected.JoinNumber, (b) => SelectDirectoryEntry(_directoryCodec, 0, _directoryTrilist, _directoryJoinmap)); + trilist.SetBoolSigAction(joinMap.DirectoryClearSelected.JoinNumber, (b) => SelectDirectoryEntry(codec, 0, trilist, joinMap)); - // Report feedback for number of contact methods for selected contact + // Report feedback for number of contact methods for selected contact trilist.SetSigFalseAction(joinMap.DirectoryRoot.JoinNumber, codec.SetCurrentDirectoryToRoot); trilist.SetSigFalseAction(joinMap.DirectoryFolderBack.JoinNumber, codec.GetDirectoryParentFolderContents); - if (codec.DirectoryRoot != null) - { - var contactsCount = codec.DirectoryRoot.CurrentDirectoryResults.Where(c => c.ParentFolderId.Equals("root")).ToList().Count; - trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)contactsCount); + if (codec.DirectoryRoot != null) + { + var contactsCount = codec.DirectoryRoot.CurrentDirectoryResults.Where(c => c.ParentFolderId.Equals("root")).ToList().Count; + trilist.SetUshort(joinMap.DirectoryRowCount.JoinNumber, (ushort)contactsCount); Debug.LogMessage(LogEventLevel.Verbose, this, ">>> contactsCount: {0}", contactsCount); - var clearBytes = XSigHelpers.ClearOutputs(); + var clearBytes = XSigHelpers.ClearOutputs(); - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, - Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, - codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, + codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); - Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); + Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); - } + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); + } codec.DirectoryResultReturned += (sender, args) => { var isRoot = codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false; - var argsCount = isRoot + var argsCount = isRoot ? args.Directory.CurrentDirectoryResults.Where(a => a.ParentFolderId.Equals("root")).ToList().Count : args.Directory.CurrentDirectoryResults.Count; @@ -1070,159 +1185,159 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetString(joinMap.DirectoryEntries.JoinNumber, Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var directoryXSig = UpdateDirectoryXSig(args.Directory, - codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); - Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); + var directoryXSig = UpdateDirectoryXSig(args.Directory, + codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); + Debug.LogMessage(LogEventLevel.Verbose, this, "Directory XSig Length: {0}", directoryXSig.Length); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); }; - - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; - var clearBytes = XSigHelpers.ClearOutputs(); - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, - Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); - trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); - }; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; + + var clearBytes = XSigHelpers.ClearOutputs(); + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var directoryXSig = UpdateDirectoryXSig(codec.DirectoryRoot, codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue == false); + trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); + }; } private void SelectDirectoryEntry(IHasDirectory codec, ushort i, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { - if (i > codec.CurrentDirectoryResult.CurrentDirectoryResults.Count) return; - _selectedDirectoryItem = i == 0 ? null : codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; - trilist.SetUshort(joinMap.DirectorySelectRowFeedback.JoinNumber, i); + if (i > codec.CurrentDirectoryResult.CurrentDirectoryResults.Count) return; + _selectedDirectoryItem = i == 0 ? null : codec.CurrentDirectoryResult.CurrentDirectoryResults[i - 1]; + trilist.SetUshort(joinMap.DirectorySelectRowFeedback.JoinNumber, i); - if (_selectedDirectoryItem == null) trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); + if (_selectedDirectoryItem == null) trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); if (_selectedDirectoryItem is DirectoryFolder) { codec.GetDirectoryFolderContents(_selectedDirectoryItem.FolderId); - trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); - trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, _selectedDirectoryItem.Name); - trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); - trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); - trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); - return; + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); + trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, _selectedDirectoryItem.Name); + trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); + trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); + trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, false); + return; } - // not a folder. Clear this value - trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, string.Empty); + // not a folder. Clear this value + trilist.SetString(joinMap.DirectorySelectedFolderName.JoinNumber, string.Empty); - var selectedContact = _selectedDirectoryItem as DirectoryContact; + var selectedContact = _selectedDirectoryItem as DirectoryContact; - if (selectedContact != null && selectedContact.ContactMethods.Count >= 1) - { - trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, true); - } + if (selectedContact != null && selectedContact.ContactMethods.Count >= 1) + { + trilist.SetBool(joinMap.DirectoryEntryIsContact.JoinNumber, true); + } - trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, - selectedContact != null ? selectedContact.Name : string.Empty); + trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, + selectedContact != null ? selectedContact.Name : string.Empty); - // Allow auto dial of selected line. Always dials first contact method - if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber)) - { - if (_selectedDirectoryItem is IInvitableContact invitableEntry) - { - Dial(invitableEntry); - return; - } + // Allow auto dial of selected line. Always dials first contact method + if (!trilist.GetBool(joinMap.DirectoryDisableAutoDialSelectedLine.JoinNumber)) + { + if (_selectedDirectoryItem is IInvitableContact invitableEntry) + { + Dial(invitableEntry); + return; + } - trilist.SetString(joinMap.DirectoryEntrySelectedNumber.JoinNumber, - selectedContact != null ? selectedContact.ContactMethods[0].Number : string.Empty); + trilist.SetString(joinMap.DirectoryEntrySelectedNumber.JoinNumber, + selectedContact != null ? selectedContact.ContactMethods[0].Number : string.Empty); - if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) return; + if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) return; - Dial(entryToDial.ContactMethods[0].Number); - } - else - { - // If auto dial is disabled... + Dial(entryToDial.ContactMethods[0].Number); + } + else + { + // If auto dial is disabled... - if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) - { - // Clear out values and actions from last selected item - trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); - trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); - trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); - return; - } + if (!(_selectedDirectoryItem is DirectoryContact entryToDial)) + { + // Clear out values and actions from last selected item + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, 0); + trilist.SetString(joinMap.DirectoryEntrySelectedName.JoinNumber, string.Empty); + trilist.ClearUShortSigAction(joinMap.SelectContactMethod.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedLine.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber); + return; + } - trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count); + trilist.SetUshort(joinMap.SelectedContactMethodCount.JoinNumber, (ushort)entryToDial.ContactMethods.Count); - // Update the action to dial the selected contact method - trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) => - { - if (u < 1 || u > entryToDial.ContactMethods.Count) return; + // Update the action to dial the selected contact method + trilist.SetUShortSigAction(joinMap.SelectContactMethod.JoinNumber, (u) => + { + if (u < 1 || u > entryToDial.ContactMethods.Count) return; - trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u - 1].Number)); - }); + trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedContactMethod.JoinNumber, () => Dial(entryToDial.ContactMethods[u - 1].Number)); + }); - // Sets DirectoryDialSelectedLine join action to dial first contact method - trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); + // Sets DirectoryDialSelectedLine join action to dial first contact method + trilist.SetSigFalseAction(joinMap.DirectoryDialSelectedLine.JoinNumber, () => Dial(entryToDial.ContactMethods[0].Number)); - var clearBytes = XSigHelpers.ClearOutputs(); + var clearBytes = XSigHelpers.ClearOutputs(); - trilist.SetString(joinMap.ContactMethods.JoinNumber, - Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); - var contactMethodsXSig = UpdateContactMethodsXSig(entryToDial); + trilist.SetString(joinMap.ContactMethods.JoinNumber, + Encoding.GetEncoding(XSigEncoding).GetString(clearBytes, 0, clearBytes.Length)); + var contactMethodsXSig = UpdateContactMethodsXSig(entryToDial); - trilist.SetString(joinMap.ContactMethods.JoinNumber, contactMethodsXSig); - } + trilist.SetString(joinMap.ContactMethods.JoinNumber, contactMethodsXSig); + } } - /// - /// Generates the XSig data representing the available contact methods for the selected DirectoryContact - /// - /// - /// - private string UpdateContactMethodsXSig(DirectoryContact contact) - { - const int maxMethods = 10; - const int maxStrings = 3; - const int offset = maxStrings; - var stringIndex = 0; - var arrayIndex = 0; - // Create a new token array and set the size to the number of methods times the total number of signals - var tokenArray = new XSigToken[maxMethods * offset]; + /// + /// Generates the XSig data representing the available contact methods for the selected DirectoryContact + /// + /// + /// + private string UpdateContactMethodsXSig(DirectoryContact contact) + { + const int maxMethods = 10; + const int maxStrings = 3; + const int offset = maxStrings; + var stringIndex = 0; + var arrayIndex = 0; + // Create a new token array and set the size to the number of methods times the total number of signals + var tokenArray = new XSigToken[maxMethods * offset]; - Debug.LogMessage(LogEventLevel.Verbose, this, "Creating XSIG token array with size {0}", maxMethods * offset); + Debug.LogMessage(LogEventLevel.Verbose, this, "Creating XSIG token array with size {0}", maxMethods * offset); - // TODO: Add code to generate XSig data - foreach (var method in contact.ContactMethods) - { - if (arrayIndex >= maxMethods * offset) - break; + // TODO: Add code to generate XSig data + foreach (var method in contact.ContactMethods) + { + if (arrayIndex >= maxMethods * offset) + break; - //serials - tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, method.Number); - tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, method.ContactMethodId.ToString()); - tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, method.Device.ToString()); + //serials + tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, method.Number); + tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, method.ContactMethodId.ToString()); + tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, method.Device.ToString()); arrayIndex += offset; stringIndex += maxStrings; - } + } - while (arrayIndex < maxMethods) - { - tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); - tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); - tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); + while (arrayIndex < maxMethods) + { + tokenArray[arrayIndex + 1] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[arrayIndex + 2] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[arrayIndex + 3] = new XSigSerialToken(stringIndex + 3, String.Empty); arrayIndex += offset; stringIndex += maxStrings; - } + } - return GetXSigString(tokenArray); - } + return GetXSigString(tokenArray); + } private string UpdateDirectoryXSig(CodecDirectory directory, bool isRoot) { @@ -1267,7 +1382,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec return GetXSigString(tokenArray); } - private void LinkVideoCodecCallControlsToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + private void LinkVideoCodecCallControlsToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { trilist.SetSigFalseAction(joinMap.ManualDial.JoinNumber, () => Dial(trilist.StringOutput[joinMap.CurrentDialString.JoinNumber].StringValue)); @@ -1275,31 +1390,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec //End All calls trilist.SetSigFalseAction(joinMap.EndAllCalls.JoinNumber, EndAllCalls); - //End a specific call, specified by index. Maximum 8 calls supported - for (int i = 0; i < joinMap.EndCallStart.JoinSpan; i++) - { - var callIndex = i; + //End a specific call, specified by index. Maximum 8 calls supported + for (int i = 0; i < joinMap.EndCallStart.JoinSpan; i++) + { + var callIndex = i; - trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () => - { + trilist.SetSigFalseAction((uint)(joinMap.EndCallStart.JoinNumber + i), () => + { - if (callIndex < 0 || callIndex >= ActiveCalls.Count) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Cannot end call. No call found at index: {0}", callIndex); - return; - } + if (callIndex < 0 || callIndex >= ActiveCalls.Count) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Cannot end call. No call found at index: {0}", callIndex); + return; + } - var call = ActiveCalls[callIndex]; - if (call != null) - { - EndCall(call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "[End Call] Unable to find call at index '{0}'", i); - } - }); - } + var call = ActiveCalls[callIndex]; + if (call != null) + { + EndCall(call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "[End Call] Unable to find call at index '{0}'", i); + } + }); + } trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); @@ -1311,18 +1426,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec Debug.LogMessage(LogEventLevel.Debug, this, "Call is incoming: {0}", args.CallItem.Direction == eCodecCallDirection.Incoming); trilist.SetBool(joinMap.IncomingCall.JoinNumber, args.CallItem.Direction == eCodecCallDirection.Incoming && args.CallItem.Status == eCodecCallStatus.Ringing); - if (args.CallItem.Direction == eCodecCallDirection.Incoming) - { - trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); - trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); - trilist.SetString(joinMap.IncomingCallName.JoinNumber, args.CallItem.Name); - trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, args.CallItem.Number); - } - else - { - trilist.SetString(joinMap.IncomingCallName.JoinNumber, string.Empty); - trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, string.Empty); - } + if (args.CallItem.Direction == eCodecCallDirection.Incoming) + { + trilist.SetSigFalseAction(joinMap.IncomingAnswer.JoinNumber, () => AcceptCall(args.CallItem)); + trilist.SetSigFalseAction(joinMap.IncomingReject.JoinNumber, () => RejectCall(args.CallItem)); + trilist.SetString(joinMap.IncomingCallName.JoinNumber, args.CallItem.Name); + trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, args.CallItem.Number); + } + else + { + trilist.SetString(joinMap.IncomingCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.IncomingCallNumber.JoinNumber, string.Empty); + } trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); @@ -1330,92 +1445,92 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.SetUshort(joinMap.ConnectedCallCount.JoinNumber, (ushort)ActiveCalls.Count); }; - if (this is IJoinCalls joinCodec) - { - trilist.SetSigFalseAction(joinMap.JoinAllCalls.JoinNumber, () => joinCodec.JoinAllCalls()); - - for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++) - { - trilist.SetSigFalseAction((uint)(joinMap.JoinCallStart.JoinNumber + i), () => - { - var call = ActiveCalls[i]; - if (call != null) - { - joinCodec.JoinCall(call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "[Join Call] Unable to find call at index '{0}'", i); - } - }); - } - } - - if (this is IHasCallHold holdCodec) - { - trilist.SetSigFalseAction(joinMap.HoldAllCalls.JoinNumber, () => - { - foreach (var call in ActiveCalls) - { - holdCodec.HoldCall(call); - } - }); - - for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) - { - var index = i; - - trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + index), () => - { - if (index < 0 || index >= ActiveCalls.Count) return; - - var call = ActiveCalls[index]; - if (call != null) - { - holdCodec.HoldCall(call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "[Hold Call] Unable to find call at index '{0}'", i); - } - }); - - trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + index), () => - { - if (index < 0 || index >= ActiveCalls.Count) return; - - var call = ActiveCalls[index]; - if (call != null) - { - holdCodec.ResumeCall(call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "[Resume Call] Unable to find call at index '{0}'", i); - } - }); - } - } - - - - trilist.OnlineStatusChange += (device, args) => + if (this is IJoinCalls joinCodec) { - if (!args.DeviceOnLine) return; + trilist.SetSigFalseAction(joinMap.JoinAllCalls.JoinNumber, () => joinCodec.JoinAllCalls()); - // TODO [ ] #983 - Debug.LogMessage(LogEventLevel.Information, this, "LinkVideoCodecCallControlsToApi: device is {0}, IsInCall {1}", args.DeviceOnLine ? "online" : "offline", IsInCall); - trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); - trilist.SetString(joinMap.CurrentCallData.JoinNumber, "\xFC"); - trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); - }; + for (int i = 0; i < joinMap.JoinCallStart.JoinSpan; i++) + { + trilist.SetSigFalseAction((uint)(joinMap.JoinCallStart.JoinNumber + i), () => + { + var call = ActiveCalls[i]; + if (call != null) + { + joinCodec.JoinCall(call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "[Join Call] Unable to find call at index '{0}'", i); + } + }); + } + } + + if (this is IHasCallHold holdCodec) + { + trilist.SetSigFalseAction(joinMap.HoldAllCalls.JoinNumber, () => + { + foreach (var call in ActiveCalls) + { + holdCodec.HoldCall(call); + } + }); + + for (int i = 0; i < joinMap.HoldCallsStart.JoinSpan; i++) + { + var index = i; + + trilist.SetSigFalseAction((uint)(joinMap.HoldCallsStart.JoinNumber + index), () => + { + if (index < 0 || index >= ActiveCalls.Count) return; + + var call = ActiveCalls[index]; + if (call != null) + { + holdCodec.HoldCall(call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "[Hold Call] Unable to find call at index '{0}'", i); + } + }); + + trilist.SetSigFalseAction((uint)(joinMap.ResumeCallsStart.JoinNumber + index), () => + { + if (index < 0 || index >= ActiveCalls.Count) return; + + var call = ActiveCalls[index]; + if (call != null) + { + holdCodec.ResumeCall(call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "[Resume Call] Unable to find call at index '{0}'", i); + } + }); + } + } + + + + trilist.OnlineStatusChange += (device, args) => +{ + if (!args.DeviceOnLine) return; + + // TODO [ ] #983 + Debug.LogMessage(LogEventLevel.Information, this, "LinkVideoCodecCallControlsToApi: device is {0}, IsInCall {1}", args.DeviceOnLine ? "online" : "offline", IsInCall); + trilist.SetBool(joinMap.HookState.JoinNumber, IsInCall); + trilist.SetString(joinMap.CurrentCallData.JoinNumber, "\xFC"); + trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); +}; } private string UpdateCallStatusXSig() { const int maxCalls = 8; const int maxStrings = 6; - const int maxDigitals = 2; + const int maxDigitals = 2; const int offset = maxStrings + maxDigitals; var stringIndex = 0; var digitalIndex = maxStrings * maxCalls; @@ -1428,40 +1543,40 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec if (arrayIndex >= maxCalls * offset) break; //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold); + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, call.IsActiveCall); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, call.IsOnHold); //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); - tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, call.Number ?? String.Empty); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString()); - tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, call.Type.ToString()); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, call.Status.ToString()); - if(call.Duration != null) - { - // May need to verify correct string format here - var dur = string.Format("{0:c}", call.Duration); - tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, dur); - } + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, call.Name ?? String.Empty); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, call.Number ?? String.Empty); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, call.Direction.ToString()); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, call.Type.ToString()); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, call.Status.ToString()); + if (call.Duration != null) + { + // May need to verify correct string format here + var dur = string.Format("{0:c}", call.Duration); + tokenArray[arrayIndex + 6] = new XSigSerialToken(stringIndex + 6, dur); + } arrayIndex += offset; stringIndex += maxStrings; - digitalIndex += maxDigitals; + digitalIndex += maxDigitals; } - while (arrayIndex < maxCalls * offset) + while (arrayIndex < maxCalls * offset) { //digitals - tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); - tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); + tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); + tokenArray[digitalIndex + 1] = new XSigDigitalToken(digitalIndex + 2, false); - //serials - tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); - tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); - tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); - tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); - tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); - tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); + //serials + tokenArray[stringIndex] = new XSigSerialToken(stringIndex + 1, String.Empty); + tokenArray[stringIndex + 1] = new XSigSerialToken(stringIndex + 2, String.Empty); + tokenArray[stringIndex + 2] = new XSigSerialToken(stringIndex + 3, String.Empty); + tokenArray[stringIndex + 3] = new XSigSerialToken(stringIndex + 4, String.Empty); + tokenArray[stringIndex + 4] = new XSigSerialToken(stringIndex + 5, String.Empty); + tokenArray[stringIndex + 5] = new XSigSerialToken(stringIndex + 6, String.Empty); arrayIndex += offset; stringIndex += maxStrings; @@ -1473,55 +1588,55 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec private void LinkVideoCodecDtmfToApi(BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { - trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmfAction("0", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmfAction("1", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmfAction("2", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmfAction("3", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmfAction("4", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmfAction("5", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmfAction("6", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmfAction("7", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmfAction("8", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmfAction("9", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmfAction("*", trilist, joinMap)); - trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmfAction("#", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf0.JoinNumber, () => SendDtmfAction("0", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf1.JoinNumber, () => SendDtmfAction("1", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf2.JoinNumber, () => SendDtmfAction("2", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf3.JoinNumber, () => SendDtmfAction("3", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf4.JoinNumber, () => SendDtmfAction("4", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf5.JoinNumber, () => SendDtmfAction("5", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf6.JoinNumber, () => SendDtmfAction("6", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf7.JoinNumber, () => SendDtmfAction("7", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf8.JoinNumber, () => SendDtmfAction("8", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.Dtmf9.JoinNumber, () => SendDtmfAction("9", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.DtmfStar.JoinNumber, () => SendDtmfAction("*", trilist, joinMap)); + trilist.SetSigFalseAction(joinMap.DtmfPound.JoinNumber, () => SendDtmfAction("#", trilist, joinMap)); } - /// - /// Sends the specified string as a DTMF command. - /// Reads the value of the SendDtmfToSpecificCallInstance digital join and SelectCall analog join to determine - /// Whther to send to a specific call index or to the last connected call - /// - /// - /// - /// - private void SendDtmfAction(string s, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - if (!trilist.GetBool(joinMap.SendDtmfToSpecificCallIndex.JoinNumber)) - { - SendDtmf(s); - } - else - { - var callIndex = trilist.GetUshort(joinMap.SelectCall.JoinNumber); - if (callIndex > 0 && callIndex <= 8) - { - var call = ActiveCalls[callIndex - 1]; - if (call != null && call.IsActiveCall) - { - SendDtmf(s, call); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Warning: No call found at index {0} or call is not active.", callIndex); - } - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Warning: Invalid call index specified. Please use a value of 1-8."); - } - } - } + /// + /// Sends the specified string as a DTMF command. + /// Reads the value of the SendDtmfToSpecificCallInstance digital join and SelectCall analog join to determine + /// Whther to send to a specific call index or to the last connected call + /// + /// + /// + /// + private void SendDtmfAction(string s, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + if (!trilist.GetBool(joinMap.SendDtmfToSpecificCallIndex.JoinNumber)) + { + SendDtmf(s); + } + else + { + var callIndex = trilist.GetUshort(joinMap.SelectCall.JoinNumber); + if (callIndex > 0 && callIndex <= 8) + { + var call = ActiveCalls[callIndex - 1]; + if (call != null && call.IsActiveCall) + { + SendDtmf(s, call); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Warning: No call found at index {0} or call is not active.", callIndex); + } + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Warning: Invalid call index specified. Please use a value of 1-8."); + } + } + } private void LinkVideoCodecCameraLayoutsToApi(IHasCodecLayouts codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) { @@ -1537,45 +1652,45 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec codec.CameraAutoModeIsOnFeedback.OutputChange += (o, a) => { - if (codec is IHasCameraOff offCodec) - { - if (offCodec.CameraIsOffFeedback.BoolValue) - { - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); - return; - } + if (codec is IHasCameraOff offCodec) + { + if (offCodec.CameraIsOffFeedback.BoolValue) + { + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); + return; + } - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - return; - } + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + return; + } - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, a.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !a.BoolValue); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); }; - if (codec is IHasCameraOff offModeCodec) - { - if (offModeCodec.CameraIsOffFeedback.BoolValue) - { - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); - return; - } + if (codec is IHasCameraOff offModeCodec) + { + if (offModeCodec.CameraIsOffFeedback.BoolValue) + { + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, false); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, true); + return; + } - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); - trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); - return; - } + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); + return; + } - trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); + trilist.SetBool(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeManual.JoinNumber, !codec.CameraAutoModeIsOnFeedback.BoolValue); trilist.SetBool(joinMap.CameraModeOff.JoinNumber, false); } @@ -1595,9 +1710,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.TiltUp(); + if (b) camera.TiltUp(); else camera.TiltStop(); }); @@ -1605,27 +1720,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.TiltDown(); + if (b) camera.TiltDown(); else camera.TiltStop(); }); trilist.SetBoolSigAction(joinMap.CameraPanLeft.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.PanLeft(); + if (b) camera.PanLeft(); else camera.PanStop(); }); trilist.SetBoolSigAction(joinMap.CameraPanRight.JoinNumber, (b) => { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.PanRight(); + if (b) camera.PanRight(); else camera.PanStop(); }); @@ -1633,9 +1748,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.ZoomIn(); + if (b) camera.ZoomIn(); else camera.ZoomStop(); }); @@ -1643,83 +1758,83 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec { if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraPtzControl camera)) return; - if (b) camera.ZoomOut(); + if (b) camera.ZoomOut(); else camera.ZoomStop(); }); - trilist.SetBoolSigAction(joinMap.CameraFocusNear.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; + trilist.SetBoolSigAction(joinMap.CameraFocusNear.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; - if (b) camera.FocusNear(); - else camera.FocusStop(); - }); + if (b) camera.FocusNear(); + else camera.FocusStop(); + }); - trilist.SetBoolSigAction(joinMap.CameraFocusFar.JoinNumber, (b) => - { - if (codec.SelectedCamera == null) return; + trilist.SetBoolSigAction(joinMap.CameraFocusFar.JoinNumber, (b) => + { + if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; - if (b) camera.FocusFar(); - else camera.FocusStop(); - }); + if (b) camera.FocusFar(); + else camera.FocusStop(); + }); - trilist.SetSigFalseAction(joinMap.CameraFocusAuto.JoinNumber, () => - { - if (codec.SelectedCamera == null) return; + trilist.SetSigFalseAction(joinMap.CameraFocusAuto.JoinNumber, () => + { + if (codec.SelectedCamera == null) return; - if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; + if (!(codec.SelectedCamera is IHasCameraFocusControl camera)) return; - camera.TriggerAutoFocus(); - }); + camera.TriggerAutoFocus(); + }); - // Camera count - trilist.SetUshort(joinMap.CameraCount.JoinNumber, (ushort)codec.Cameras.Count); + // Camera count + trilist.SetUshort(joinMap.CameraCount.JoinNumber, (ushort)codec.Cameras.Count); - // Camera names - for (uint i = 0; i < joinMap.CameraNamesFb.JoinSpan; i++) - { - //Check the count first - if (i < codec.Cameras.Count && codec.Cameras[(int)i] != null) - { - trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, codec.Cameras[(int)i].Name); - } - else - { - trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, ""); - } - } + // Camera names + for (uint i = 0; i < joinMap.CameraNamesFb.JoinSpan; i++) + { + //Check the count first + if (i < codec.Cameras.Count && codec.Cameras[(int)i] != null) + { + trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, codec.Cameras[(int)i].Name); + } + else + { + trilist.SetString(joinMap.CameraNamesFb.JoinNumber + i, ""); + } + } //Camera Select trilist.SetUShortSigAction(joinMap.CameraNumberSelect.JoinNumber, (i) => { - if (i > 0 && i <= codec.Cameras.Count) - { - codec.SelectCamera(codec.Cameras[i - 1].Key); - } - else - { - Debug.LogMessage(LogEventLevel.Information, this, "Unable to select. No camera found at index {0}", i); - } + if (i > 0 && i <= codec.Cameras.Count) + { + codec.SelectCamera(codec.Cameras[i - 1].Key); + } + else + { + Debug.LogMessage(LogEventLevel.Information, this, "Unable to select. No camera found at index {0}", i); + } }); - // Set initial selected camera feedback - if (codec.SelectedCamera != null) - { - trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)codec.Cameras.FindIndex((c) => c.Key == codec.SelectedCamera.Key)); - } + // Set initial selected camera feedback + if (codec.SelectedCamera != null) + { + trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)codec.Cameras.FindIndex((c) => c.Key == codec.SelectedCamera.Key)); + } codec.CameraSelected += (sender, args) => { var i = (ushort)codec.Cameras.FindIndex((c) => c.Key == args.SelectedCamera.Key); - trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)(i + 1)); + trilist.SetUshort(joinMap.CameraNumberSelect.JoinNumber, (ushort)(i + 1)); if (codec is IHasCodecRoomPresets) { @@ -1766,11 +1881,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec }); - // Far End Presets - trilist.SetUShortSigAction(joinMap.FarEndPresetSelect.JoinNumber, (i) => - { - presetCodec.SelectFarEndPreset(i); - }); + // Far End Presets + trilist.SetUShortSigAction(joinMap.FarEndPresetSelect.JoinNumber, (i) => + { + presetCodec.SelectFarEndPreset(i); + }); trilist.SetSigFalseAction(joinMap.CameraPresetSave.JoinNumber, @@ -1781,105 +1896,105 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); }); - trilist.OnlineStatusChange += (device, args) => - { - if (!args.DeviceOnLine) return; + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; - // TODO [ ] Issue #868 - trilist.SetString(joinMap.CameraPresetNames.JoinNumber, "\xFC"); - SetCameraPresetNames(presetCodec.NearEndPresets); - }; + // TODO [ ] Issue #868 + trilist.SetString(joinMap.CameraPresetNames.JoinNumber, "\xFC"); + SetCameraPresetNames(presetCodec.NearEndPresets); + }; } - // Following fields only used for Bridging - private int _selectedRecentCallItemIndex; - private DirectoryItem _selectedDirectoryItem; + // Following fields only used for Bridging + private int _selectedRecentCallItemIndex; + private DirectoryItem _selectedDirectoryItem; - private void LinkVideoCodecCallHistoryToApi(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - codec.CallHistory.RecentCallsListHasChanged += (o, a) => - { - UpdateCallHistory(codec, trilist, joinMap); - }; + private void LinkVideoCodecCallHistoryToApi(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + codec.CallHistory.RecentCallsListHasChanged += (o, a) => + { + UpdateCallHistory(codec, trilist, joinMap); + }; - // Selected item action and feedback - trilist.SetUShortSigAction(joinMap.SelectRecentCallItem.JoinNumber, (u) => - { - if (u == 0 || u > codec.CallHistory.RecentCalls.Count) - { - Debug.LogMessage(LogEventLevel.Verbose, this, "Recent Call History index out of range"); - return; - } + // Selected item action and feedback + trilist.SetUShortSigAction(joinMap.SelectRecentCallItem.JoinNumber, (u) => + { + if (u == 0 || u > codec.CallHistory.RecentCalls.Count) + { + Debug.LogMessage(LogEventLevel.Verbose, this, "Recent Call History index out of range"); + return; + } - _selectedRecentCallItemIndex = (int)(u - 1); - trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); + _selectedRecentCallItemIndex = (int)(u - 1); + trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, u); - var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex]; - - if (_selectedRecentCallItem != null) - { - trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name); - trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, _selectedRecentCallItem.Number); - trilist.SetSigFalseAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber, () => codec.RemoveCallHistoryEntry(_selectedRecentCallItem)); - trilist.SetSigFalseAction(joinMap.DialSelectedRecentCallItem.JoinNumber, () => this.Dial(_selectedRecentCallItem.Number)); - } - else - { - trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); - trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); - trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); - trilist.ClearBoolSigAction(joinMap.DialSelectedRecentCallItem.JoinNumber); - } - }); - } + var _selectedRecentCallItem = codec.CallHistory.RecentCalls[_selectedRecentCallItemIndex]; + + if (_selectedRecentCallItem != null) + { + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, _selectedRecentCallItem.Name); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, _selectedRecentCallItem.Number); + trilist.SetSigFalseAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber, () => codec.RemoveCallHistoryEntry(_selectedRecentCallItem)); + trilist.SetSigFalseAction(joinMap.DialSelectedRecentCallItem.JoinNumber, () => this.Dial(_selectedRecentCallItem.Number)); + } + else + { + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); + trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); + trilist.ClearBoolSigAction(joinMap.DialSelectedRecentCallItem.JoinNumber); + } + }); + } - private void UpdateCallHistory(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) - { - // Clear out selected item - _selectedRecentCallItemIndex = 0; + private void UpdateCallHistory(IHasCallHistory codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) + { + // Clear out selected item + _selectedRecentCallItemIndex = 0; - trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, 0); - trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); - trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); - trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); - // + trilist.SetUshort(joinMap.SelectRecentCallItem.JoinNumber, 0); + trilist.SetString(joinMap.SelectedRecentCallName.JoinNumber, string.Empty); + trilist.SetString(joinMap.SelectedRecentCallNumber.JoinNumber, string.Empty); + trilist.ClearBoolSigAction(joinMap.RemoveSelectedRecentCallItem.JoinNumber); + // - trilist.SetUshort(joinMap.RecentCallCount.JoinNumber, (ushort)codec.CallHistory.RecentCalls.Count); + trilist.SetUshort(joinMap.RecentCallCount.JoinNumber, (ushort)codec.CallHistory.RecentCalls.Count); - // Update the call history joins - var maxItems = joinMap.RecentCallNamesStart.JoinSpan; + // Update the call history joins + var maxItems = joinMap.RecentCallNamesStart.JoinSpan; - // Create history - uint index = 0; - for (uint i = 0; i < maxItems && i < codec.CallHistory.RecentCalls.Count; i++) - { - trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].Name); - trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].StartTime.ToShortTimeString()); - trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)codec.CallHistory.RecentCalls[(int)i].OccurrenceType); - //i++; - index = i; - } - - //foreach(var item in codec.CallHistory.RecentCalls) - //{ - // trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name); - // trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString()); - // trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType); - // i++; - //} + // Create history + uint index = 0; + for (uint i = 0; i < maxItems && i < codec.CallHistory.RecentCalls.Count; i++) + { + trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].Name); + trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, codec.CallHistory.RecentCalls[(int)i].StartTime.ToShortTimeString()); + trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)codec.CallHistory.RecentCalls[(int)i].OccurrenceType); + //i++; + index = i; + } - // Clears existing items - for (uint j = index; j < maxItems; j++) - { - trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + j, string.Empty); - trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + j, string.Empty); - trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + j, 0); - } - } + //foreach(var item in codec.CallHistory.RecentCalls) + //{ + // trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + i, item.Name); + // trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + i, item.StartTime.ToShortTimeString()); + // trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + i, (ushort)item.OccurrenceType); + // i++; + //} - private string SetCameraPresetNames(IEnumerable presets) + // Clears existing items + for (uint j = index; j < maxItems; j++) + { + trilist.SetString(joinMap.RecentCallNamesStart.JoinNumber + j, string.Empty); + trilist.SetString(joinMap.RecentCallTimesStart.JoinNumber + j, string.Empty); + trilist.SetUshort(joinMap.RecentCallOccurrenceType.JoinNumber + j, 0); + } + } + + private string SetCameraPresetNames(IEnumerable presets) { return SetCameraPresetNames(presets.Select(p => p.Description).ToList()); } @@ -1925,159 +2040,4 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec #endregion } - - - /// - /// Represents a CodecPhonebookSyncState - /// - public class CodecPhonebookSyncState : IKeyed - { - private bool _InitialSyncComplete; - - public CodecPhonebookSyncState(string key) - { - Key = key; - - CodecDisconnected(); - } - - public bool InitialSyncComplete - { - get { return _InitialSyncComplete; } - private set - { - if (value == true) - { - InitialSyncCompleted?.Invoke(this, new EventArgs()); - } - _InitialSyncComplete = value; - } - } - - /// - /// Gets or sets the InitialPhonebookFoldersWasReceived - /// - public bool InitialPhonebookFoldersWasReceived { get; private set; } - - /// - /// Gets or sets the NumberOfContactsWasReceived - /// - public bool NumberOfContactsWasReceived { get; private set; } - - /// - /// Gets or sets the PhonebookRootEntriesWasRecieved - /// - public bool PhonebookRootEntriesWasRecieved { get; private set; } - - /// - /// Gets or sets the PhonebookHasFolders - /// - public bool PhonebookHasFolders { get; private set; } - - /// - /// Gets or sets the NumberOfContacts - /// - public int NumberOfContacts { get; private set; } - - #region IKeyed Members - - /// - /// Gets or sets the Key - /// - public string Key { get; private set; } - - #endregion - - public event EventHandler InitialSyncCompleted; - - /// - /// InitialPhonebookFoldersReceived method - /// - public void InitialPhonebookFoldersReceived() - { - InitialPhonebookFoldersWasReceived = true; - - CheckSyncStatus(); - } - - /// - /// PhonebookRootEntriesReceived method - /// - public void PhonebookRootEntriesReceived() - { - PhonebookRootEntriesWasRecieved = true; - - CheckSyncStatus(); - } - - /// - /// SetPhonebookHasFolders method - /// - public void SetPhonebookHasFolders(bool value) - { - PhonebookHasFolders = value; - - Debug.LogMessage(LogEventLevel.Debug, this, "Phonebook has folders: {0}", PhonebookHasFolders); - } - - /// - /// SetNumberOfContacts method - /// - public void SetNumberOfContacts(int contacts) - { - NumberOfContacts = contacts; - NumberOfContactsWasReceived = true; - - Debug.LogMessage(LogEventLevel.Debug, this, "Phonebook contains {0} contacts.", NumberOfContacts); - - CheckSyncStatus(); - } - - /// - /// CodecDisconnected method - /// - public void CodecDisconnected() - { - InitialPhonebookFoldersWasReceived = false; - PhonebookHasFolders = false; - NumberOfContacts = 0; - NumberOfContactsWasReceived = false; - } - - private void CheckSyncStatus() - { - if (InitialPhonebookFoldersWasReceived && NumberOfContactsWasReceived && PhonebookRootEntriesWasRecieved) - { - InitialSyncComplete = true; - Debug.LogMessage(LogEventLevel.Debug, this, "Initial Phonebook Sync Complete!"); - } - else - { - InitialSyncComplete = false; - } - } - } - /// - /// Represents a CodecCommandWithLabel - /// - public class CodecCommandWithLabel - { - /// - /// Gets or sets the Command - /// - public string Command { get; private set; } - /// - /// Gets or sets the Label - /// - public string Label { get; private set; } - - public CodecCommandWithLabel(string command, string label) - { - Command = command; - Label = label; - } - } - - - } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs index 9a42141e..a1b30341 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/AudioCodecBaseMessenger.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json.Linq; +using System; +using System.Linq; +using Newtonsoft.Json.Linq; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Codec; -using System; -using System.Linq; namespace PepperDash.Essentials.AppServer.Messengers { @@ -29,12 +29,16 @@ namespace PepperDash.Essentials.AppServer.Messengers codec.CallStatusChange += Codec_CallStatusChange; } + /// protected override void RegisterActions() { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendAtcFullMessageObject()); + AddAction("/fullStatus", (id, content) => SendAtcFullMessageObject(id)); + + AddAction("/audioDialerStatus", (id, content) => SendAtcFullMessageObject(id)); + AddAction("/dial", (id, content) => { var msg = content.ToObject>(); @@ -97,7 +101,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// Helper method to build call status for vtc /// /// - private void SendAtcFullMessageObject() + private void SendAtcFullMessageObject(string id = null) { var info = Codec.CodecInfo; @@ -109,7 +113,7 @@ namespace PepperDash.Essentials.AppServer.Messengers { phoneNumber = info.PhoneNumber } - }) + }), id ); } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs index cb3f77a5..8c9f0451 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Devices.Common.Cameras; @@ -9,12 +11,12 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Messenger for a CameraBase device /// - public class CameraBaseMessenger : MessengerBase + public class CameraBaseMessenger : MessengerBase where T : IKeyed { /// /// Gets or sets the Camera /// - public CameraBase Camera { get; set; } + public T Camera { get; set; } /// /// Constructor @@ -22,10 +24,13 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// /// - public CameraBaseMessenger(string key, CameraBase camera, string messagePath) - : base(key, messagePath, camera) + public CameraBaseMessenger(string key, T camera, string messagePath) + : base(key, messagePath, camera as IKeyName) { - Camera = camera ?? throw new ArgumentNullException("camera"); + if (camera == null) + throw new ArgumentNullException(nameof(camera)); + + Camera = camera; if (Camera is IHasCameraPresets presetsCamera) @@ -55,7 +60,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject()); + AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject(id)); + + AddAction("/cameraStatus", (id, content) => SendCameraFullMessageObject(id)); if (Camera is IHasCameraPtzControl ptzCamera) @@ -173,22 +180,47 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Helper method to update the full status of the camera /// - private void SendCameraFullMessageObject() + private void SendCameraFullMessageObject(string id = null) { var presetList = new List(); + CameraCapabilities capabilities = null; if (Camera is IHasCameraPresets presetsCamera) presetList = presetsCamera.Presets; - PostStatusMessage(JToken.FromObject(new + if (Camera is ICameraCapabilities cameraCapabilities) + capabilities = new CameraCapabilities + { + CanPan = cameraCapabilities.CanPan, + CanTilt = cameraCapabilities.CanTilt, + CanZoom = cameraCapabilities.CanZoom, + CanFocus = cameraCapabilities.CanFocus + + }; + + if (Camera is CameraBase cameraBase) + capabilities = new CameraCapabilities + { + CanPan = cameraBase.CanPan, + CanTilt = cameraBase.CanTilt, + CanZoom = cameraBase.CanZoom, + CanFocus = cameraBase.CanFocus + + }; + + var message = new CameraStateMessage { - cameraManualSupported = Camera is IHasCameraControls, - cameraAutoSupported = Camera is IHasCameraAutoMode, - cameraOffSupported = Camera is IHasCameraOff, - cameraMode = GetCameraMode(), - hasPresets = Camera is IHasCameraPresets, - presets = presetList - }) + CameraManualSupported = Camera is IHasCameraControls, + CameraAutoSupported = Camera is IHasCameraAutoMode, + CameraOffSupported = Camera is IHasCameraOff, + CameraMode = (eCameraControlMode)Enum.Parse(typeof(eCameraControlMode), GetCameraMode(), true), + HasPresets = Camera is IHasCameraPresets, + Presets = presetList, + Capabilities = capabilities, + IsFarEnd = Camera is IAmFarEndCamera + }; + + PostStatusMessage(message, id ); } @@ -208,4 +240,59 @@ namespace PepperDash.Essentials.AppServer.Messengers return m; } } + + /// + /// State message for a camera device + /// + public class CameraStateMessage : DeviceStateMessageBase + { + /// + /// Indicates whether the camera supports manual control + /// + [JsonProperty("cameraManualSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool CameraManualSupported { get; set; } + + /// + /// Indicates whether the camera supports auto control + /// + [JsonProperty("cameraAutoSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool CameraAutoSupported { get; set; } + + /// + /// Indicates whether the camera supports off control + /// + [JsonProperty("cameraOffSupported", NullValueHandling = NullValueHandling.Ignore)] + public bool CameraOffSupported { get; set; } + + /// + /// Indicates the current camera control mode + /// + [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] + [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public eCameraControlMode CameraMode { get; set; } + + /// + /// Indicates whether the camera has presets + /// + [JsonProperty("hasPresets", NullValueHandling = NullValueHandling.Ignore)] + public bool HasPresets { get; set; } + + /// + /// List of presets if the camera supports them + /// + [JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)] + public List Presets { get; set; } + + /// + /// Indicates the capabilities of the camera + /// + [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] + public CameraCapabilities Capabilities { get; set; } + + /// + /// Indicates whether the camera is a far end camera + /// + [JsonProperty("isFarEnd", NullValueHandling = NullValueHandling.Ignore)] + public bool IsFarEnd { get; set; } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs index 5b220256..9643a607 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CurrentSourcesMessenger.cs @@ -33,16 +33,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => - { - var message = new CurrentSourcesStateMessage - { - CurrentSourceKeys = sourceDevice.CurrentSourceKeys, - CurrentSources = sourceDevice.CurrentSources - }; + AddAction("/fullStatus", (id, content) => SendCurrentSourceStatus(id)); - PostStatusMessage(message); - }); + AddAction("/currentSourceStatus", (id, content) => SendCurrentSourceStatus(id)); sourceDevice.CurrentSourcesChanged += (sender, e) => { @@ -53,6 +46,17 @@ namespace PepperDash.Essentials.AppServer.Messengers })); }; } + + private void SendCurrentSourceStatus(string id = null) + { + var message = new CurrentSourcesStateMessage + { + CurrentSourceKeys = sourceDevice.CurrentSourceKeys, + CurrentSources = sourceDevice.CurrentSources + }; + + PostStatusMessage(message, id); + } } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceEventMessageBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceEventMessageBase.cs new file mode 100644 index 00000000..0960758c --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceEventMessageBase.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Base class for event messages that include the type of message and an event type + /// + public abstract class DeviceEventMessageBase : DeviceMessageBase + { + /// + /// The event type + /// + [JsonProperty("eventType")] + public string EventType { get; set; } + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs index 6537b143..876bcafe 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceInfoMessenger.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json; +using System.Timers; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceInfo; -using System.Timers; namespace PepperDash.Essentials.AppServer.Messengers { @@ -67,13 +67,20 @@ namespace PepperDash.Essentials.AppServer.Messengers debounceTimer.Start(); }; - AddAction("/fullStatus", (id, context) => PostStatusMessage(new DeviceInfoStateMessage - { - DeviceInfo = _deviceInfoProvider.DeviceInfo - })); + AddAction("/fullStatus", (id, context) => SendFullStatus(id)); + + AddAction("/deviceInfo", (id, content) => SendFullStatus(id)); AddAction("/update", (id, context) => _deviceInfoProvider.UpdateDeviceInfo()); } + + private void SendFullStatus(string id = null) + { + PostStatusMessage(new DeviceInfoStateMessage + { + DeviceInfo = _deviceInfoProvider.DeviceInfo + }, id); + } } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceMessageBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceMessageBase.cs new file mode 100644 index 00000000..54a6ec36 --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceMessageBase.cs @@ -0,0 +1,39 @@ +using Newtonsoft.Json; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Base class for device messages that include the type of message + /// + public abstract class DeviceMessageBase + { + /// + /// The device key + /// + [JsonProperty("key")] + /// + /// Gets or sets the Key + /// + public string Key { get; set; } + + /// + /// The device name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The type of the message class + /// + [JsonProperty("messageType")] + public string MessageType => GetType().Name; + + /// + /// Gets or sets the MessageBasePath + /// + [JsonProperty("messageBasePath")] + + public string MessageBasePath { get; set; } + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs index fb8ccef3..833a781b 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DevicePresetsModelMessenger.cs @@ -1,11 +1,11 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Presets; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -16,18 +16,24 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly ITvPresetsProvider _presetsDevice; + /// + /// Constructor for DevicePresetsModelMessenger + /// + /// The key. + /// The message path. + /// The presets device. public DevicePresetsModelMessenger(string key, string messagePath, ITvPresetsProvider presetsDevice) : base(key, messagePath, presetsDevice as Device) { _presetsDevice = presetsDevice; } - private void SendPresets() + private void SendPresets(string id = null) { PostStatusMessage(new PresetStateMessage { Favorites = _presetsDevice.TvPresets.PresetsList - }); + }, id); } private void RecallPreset(ISetTopBoxNumericKeypad device, string channel) @@ -43,6 +49,7 @@ namespace PepperDash.Essentials.AppServer.Messengers #region Overrides of MessengerBase + /// protected override void RegisterActions() { @@ -51,7 +58,7 @@ namespace PepperDash.Essentials.AppServer.Messengers this.LogInformation("getting full status for client {id}", id); try { - SendPresets(); + SendPresets(id); } catch (Exception ex) { @@ -59,6 +66,8 @@ namespace PepperDash.Essentials.AppServer.Messengers } }); + AddAction("/presetsStatus", (id, content) => SendPresets(id)); + AddAction("/recall", (id, content) => { var p = content.ToObject(); @@ -91,16 +100,16 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class PresetChannelMessage { - [JsonProperty("preset")] /// /// Gets or sets the Preset /// + [JsonProperty("preset")] public PresetChannel Preset; - [JsonProperty("deviceKey")] /// /// Gets or sets the DeviceKey /// + [JsonProperty("deviceKey")] public string DeviceKey; } @@ -109,10 +118,11 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class PresetStateMessage : DeviceStateMessageBase { - [JsonProperty("favorites", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Favorites /// + [JsonProperty("favorites", NullValueHandling = NullValueHandling.Ignore)] public List Favorites { get; set; } = new List(); } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceStateMessageBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceStateMessageBase.cs new file mode 100644 index 00000000..87f19e3f --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceStateMessageBase.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Represents a DeviceStateMessageBase + /// + public class DeviceStateMessageBase : DeviceMessageBase + { + /// + /// The interfaces implmented by the device sending the messsage + /// + [JsonProperty("interfaces")] + public List Interfaces { get; private set; } + + /// + /// Sets the interfaces implemented by the device sending the message + /// + /// + public void SetInterfaces(List interfaces) + { + Interfaces = interfaces; + } + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs index b6c9b18e..fba7c643 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs @@ -1,9 +1,10 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; +using PepperDash.Core.Logging; using PepperDash.Essentials.Core; -using System; namespace PepperDash.Essentials.AppServer.Messengers { @@ -12,35 +13,46 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class DeviceVolumeMessenger : MessengerBase { - private readonly IBasicVolumeWithFeedback _localDevice; + private readonly IBasicVolumeControls device; - public DeviceVolumeMessenger(string key, string messagePath, IBasicVolumeWithFeedback device) + /// + /// Initializes a new instance of the class. + /// + /// The key. + /// The message path. + /// The device. + public DeviceVolumeMessenger(string key, string messagePath, IBasicVolumeControls device) : base(key, messagePath, device as IKeyName) { - _localDevice = device; + this.device = device; } - private void SendStatus() + private void SendStatus(string id = null) { try { + if (!(device is IBasicVolumeWithFeedback feedbackDevice)) + { + return; + } + var messageObj = new VolumeStateMessage { Volume = new Volume { - Level = _localDevice?.VolumeLevelFeedback.IntValue ?? -1, - Muted = _localDevice?.MuteFeedback.BoolValue ?? false, + Level = feedbackDevice?.VolumeLevelFeedback.IntValue ?? -1, + Muted = feedbackDevice?.MuteFeedback.BoolValue ?? false, HasMute = true, // assume all devices have mute for now } }; - if (_localDevice is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) + if (device is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) { messageObj.Volume.RawValue = volumeAdvanced.RawVolumeLevel.ToString(); messageObj.Volume.Units = volumeAdvanced.Units; } - PostStatusMessage(messageObj); + PostStatusMessage(messageObj, id); } catch (Exception ex) { @@ -50,47 +62,26 @@ namespace PepperDash.Essentials.AppServer.Messengers #region Overrides of MessengerBase - + /// protected override void RegisterActions() { - AddAction("/fullStatus", (id, content) => SendStatus()); - - AddAction("/level", (id, content) => - { - var volume = content.ToObject>(); - - _localDevice.SetVolume(volume.Value); - }); + AddAction("/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => + { + Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Calling {localDevice} volume up with {value}", DeviceKey, b); + try + { + device.VolumeUp(b); + } + catch (Exception ex) + { + Debug.LogMessage(ex, "Got exception during volume up: {Exception}", null, ex); + } + })); AddAction("/muteToggle", (id, content) => - { - _localDevice.MuteToggle(); - }); - - AddAction("/muteOn", (id, content) => - { - _localDevice.MuteOn(); - }); - - AddAction("/muteOff", (id, content) => - { - _localDevice.MuteOff(); - }); - - AddAction("/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Calling {localDevice} volume up with {value}", DeviceKey, b); - try - { - _localDevice.VolumeUp(b); - } - catch (Exception ex) - { - Debug.LogMessage(ex, "Got exception during volume up: {Exception}", null, ex); - } - })); - - + { + device.MuteToggle(); + }); AddAction("/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => { @@ -98,7 +89,7 @@ namespace PepperDash.Essentials.AppServer.Messengers try { - _localDevice.VolumeDown(b); + device.VolumeDown(b); } catch (Exception ex) { @@ -106,7 +97,38 @@ namespace PepperDash.Essentials.AppServer.Messengers } })); - _localDevice.MuteFeedback.OutputChange += (sender, args) => + if (!(device is IBasicVolumeWithFeedback feedback)) + { + this.LogDebug("Skipping feedback methods for {deviceKey}", (device as IKeyName)?.Key); + return; + } + + AddAction("/fullStatus", (id, content) => SendStatus(id)); + + AddAction("/volumeStatus", (id, content) => SendStatus(id)); + + AddAction("/level", (id, content) => + { + var volume = content.ToObject>(); + + feedback.SetVolume(volume.Value); + }); + + + + AddAction("/muteOn", (id, content) => + { + feedback.MuteOn(); + }); + + AddAction("/muteOff", (id, content) => + { + feedback.MuteOff(); + }); + + + + feedback.MuteFeedback.OutputChange += (sender, args) => { PostStatusMessage(JToken.FromObject( new @@ -119,10 +141,10 @@ namespace PepperDash.Essentials.AppServer.Messengers ); }; - _localDevice.VolumeLevelFeedback.OutputChange += (sender, args) => + feedback.VolumeLevelFeedback.OutputChange += (sender, args) => { var rawValue = ""; - if (_localDevice is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) + if (feedback is IBasicVolumeWithFeedbackAdvanced volumeAdvanced) { rawValue = volumeAdvanced.RawVolumeLevel.ToString(); } @@ -138,8 +160,6 @@ namespace PepperDash.Essentials.AppServer.Messengers PostStatusMessage(JToken.FromObject(message)); }; - - } #endregion diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs index eb0611c7..83def192 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/GenericMessenger.cs @@ -7,22 +7,29 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class GenericMessenger : MessengerBase { + /// + /// Initializes a new instance of the class. + /// + /// The key. + /// The device. + /// The message path. public GenericMessenger(string key, EssentialsDevice device, string messagePath) : base(key, messagePath, device) { } + /// protected override void RegisterActions() { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); } - private void SendFullStatus() + private void SendFullStatus(string id = null) { var state = new DeviceStateMessageBase(); - PostStatusMessage(state); + PostStatusMessage(state, id); } } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IBasicVideoMuteWithFeedbackMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IBasicVideoMuteWithFeedbackMessenger.cs index 70d59aa4..5977be6e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IBasicVideoMuteWithFeedbackMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IBasicVideoMuteWithFeedbackMessenger.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -13,6 +13,12 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly IBasicVideoMuteWithFeedback device; + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// public IBasicVideoMuteWithFeedbackMessenger(string key, string messagePath, IBasicVideoMuteWithFeedback device) : base(key, messagePath, device as IKeyName) { @@ -22,21 +28,24 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// SendFullStatus method /// - public void SendFullStatus() + public void SendFullStatus(string id = null) { var messageObj = new IBasicVideoMuteWithFeedbackMessage { VideoMuteState = device.VideoMuteIsOn.BoolValue }; - PostStatusMessage(messageObj); + PostStatusMessage(messageObj, id); } + /// protected override void RegisterActions() { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/videoMuteStatus", (id, content) => SendFullStatus(id)); AddAction("/videoMuteToggle", (id, content) => { diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs index 9399aacb..79622a41 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ICommunicationMonitorMessenger.cs @@ -24,14 +24,12 @@ namespace PepperDash.Essentials.AppServer.Messengers AddAction("/fullStatus", (id, content) => { - PostStatusMessage(new CommunicationMonitorState - { - CommunicationMonitor = new CommunicationMonitorProps - { - IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, - Status = _communicationMonitor.CommunicationMonitor.Status - } - }); + SendFullStatus(id); + }); + + AddAction("/commStatus", (id, content) => + { + SendFullStatus(id); }); _communicationMonitor.CommunicationMonitor.StatusChange += (sender, args) => @@ -46,6 +44,18 @@ namespace PepperDash.Essentials.AppServer.Messengers })); }; } + + private void SendFullStatus(string id = null) + { + PostStatusMessage(new CommunicationMonitorState + { + CommunicationMonitor = new CommunicationMonitorProps + { + IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline, + Status = _communicationMonitor.CommunicationMonitor.Status + }, + }, id); + } } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs index 8096c4e9..92674574 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IDspPresetsMessenger.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -22,15 +22,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => - { - var message = new IHasDspPresetsStateMessage - { - Presets = device.Presets - }; + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); - PostStatusMessage(message); - }); + AddAction("/dspPresetStatus", (id, content) => SendFullStatus(id)); AddAction("/recallPreset", (id, content) => { @@ -43,6 +37,16 @@ namespace PepperDash.Essentials.AppServer.Messengers } }); } + + private void SendFullStatus(string id = null) + { + var message = new IHasDspPresetsStateMessage + { + Presets = device.Presets + }; + + PostStatusMessage(message, id); + } } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs index ab2ff259..966d8d77 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IEssentialsRoomCombinerMessenger.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -46,7 +46,9 @@ namespace PepperDash.Essentials.AppServer.Messengers /// partition states. protected override void RegisterActions() { - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/combinerStatus", (id, content) => SendFullStatus(id)); AddAction("/setAutoMode", (id, content) => { @@ -120,7 +122,7 @@ namespace PepperDash.Essentials.AppServer.Messengers } } - private void SendFullStatus() + private void SendFullStatus(string id = null) { try { @@ -141,7 +143,7 @@ namespace PepperDash.Essentials.AppServer.Messengers Partitions = _roomCombiner.Partitions }; - PostStatusMessage(message); + PostStatusMessage(message, id); } catch (Exception e) { diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs index 4fa0c5b1..00c2c2fe 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs @@ -1,17 +1,14 @@ using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using PepperDash.Essentials.Devices.Common.Cameras; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Messenger for devices that implement the IHasCameras interface. /// + [Obsolete("Use IHasCamerasWithControlsMessenger instead. This class will be removed in a future version")] public class IHasCamerasMessenger : MessengerBase { /// @@ -26,7 +23,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// /// - public IHasCamerasMessenger(string key, string messagePath , IHasCameras cameraController) + public IHasCamerasMessenger(string key, string messagePath, IHasCameras cameraController) : base(key, messagePath, cameraController) { CameraController = cameraController ?? throw new ArgumentNullException("cameraController"); @@ -49,10 +46,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, context) => - { - SendFullStatus(id); - }); + AddAction("/fullStatus", (id, context) => SendFullStatus(id)); + + AddAction("/cameraListStatus", (id, content) => SendFullStatus(id)); AddAction("/selectCamera", (id, content) => { diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasWithControlMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasWithControlMessenger.cs new file mode 100644 index 00000000..cce07dcd --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasWithControlMessenger.cs @@ -0,0 +1,137 @@ +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Core.Logging; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Devices.Common.Cameras; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Messenger for devices that implement the IHasCameras interface. + /// + public class IHasCamerasWithControlMessenger : MessengerBase + { + /// + /// Device being bridged that implements IHasCameras interface. + /// + public IHasCamerasWithControls CameraController { get; private set; } + + /// + /// Messenger for devices that implement IHasCameras interface. + /// + /// + /// + /// + /// + public IHasCamerasWithControlMessenger(string key, string messagePath, IHasCamerasWithControls cameraController) + : base(key, messagePath, cameraController) + { + CameraController = cameraController ?? throw new ArgumentNullException("cameraController"); + CameraController.CameraSelected += CameraController_CameraSelected; + } + + private void CameraController_CameraSelected(object sender, CameraSelectedEventArgs e) + { + var selectedCamera = new KeyName + { + Key = e.SelectedCamera.Key, + Name = e.SelectedCamera.Name + }; + + PostStatusMessage(new IHasCamerasWithControlsStateMessage + { + SelectedCamera = selectedCamera + }); + } + + /// + /// Registers the actions for this messenger. + /// + /// + protected override void RegisterActions() + { + base.RegisterActions(); + + AddAction("/fullStatus", (id, context) => SendFullStatus(id)); + + AddAction("/cameraListStatus", (id, content) => SendFullStatus(id)); + + AddAction("/selectCamera", (id, content) => + { + var cameraKey = content?.ToObject(); + + if (!string.IsNullOrEmpty(cameraKey)) + { + CameraController.SelectCamera(cameraKey); + } + else + { + throw new ArgumentException("Content must be a string representing the camera key"); + } + }); + } + + private void SendFullStatus(string clientId) + { + var cameraList = new List(); + KeyName selectedCamera = null; + + foreach (var cam in CameraController.Cameras) + { + cameraList.Add(new KeyName{ + Key = cam.Key, + Name = cam.Name + }); + } + + if (CameraController.SelectedCamera != null) + { + selectedCamera = new KeyName + { + Key = CameraController.SelectedCamera.Key, + Name = CameraController.SelectedCamera.Name + }; + } + + var state = new IHasCamerasWithControlsStateMessage + { + CameraList = cameraList, + SelectedCamera = selectedCamera + }; + + PostStatusMessage(state, clientId); + } + } + + /// + /// State message for devices that implement the IHasCameras interface. + /// + public class IHasCamerasWithControlsStateMessage : DeviceStateMessageBase + { + /// + /// List of cameras available in the device. + /// + [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] + public List CameraList { get; set; } + + /// + /// The currently selected camera on the device. + /// + [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] + public IKeyName SelectedCamera { get; set; } + } + + class KeyName : IKeyName + { + public string Key { get; set; } + public string Name { get; set; } + public KeyName() + { + Key = ""; + Name = ""; + } + } +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs index 04130776..6c0f1a0a 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCurrentSourceInfoMessenger.cs @@ -11,6 +11,7 @@ namespace PepperDash.Essentials.AppServer.Messengers public class IHasCurrentSourceInfoMessenger : MessengerBase { private readonly IHasCurrentSourceInfoChange sourceDevice; + public IHasCurrentSourceInfoMessenger(string key, string messagePath, IHasCurrentSourceInfoChange device) : base(key, messagePath, device as IKeyName) { sourceDevice = device; @@ -20,16 +21,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => - { - var message = new CurrentSourceStateMessage - { - CurrentSourceKey = sourceDevice.CurrentSourceInfoKey, - CurrentSource = sourceDevice.CurrentSourceInfo - }; + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); - PostStatusMessage(message); - }); + AddAction("/currentSourceInfoStatus", (id, content) => SendFullStatus(id)); sourceDevice.CurrentSourceChange += (sender, e) => { @@ -47,6 +41,17 @@ namespace PepperDash.Essentials.AppServer.Messengers } }; } + + private void SendFullStatus(string id = null) + { + var message = new CurrentSourceStateMessage + { + CurrentSourceKey = sourceDevice.CurrentSourceInfoKey, + CurrentSource = sourceDevice.CurrentSourceInfo + }; + + PostStatusMessage(message, id); + } } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs index bff3ca85..57ab2617 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasInputsMessenger.cs @@ -1,9 +1,9 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -11,8 +11,8 @@ namespace PepperDash.Essentials.AppServer.Messengers /// Represents a IHasInputsMessenger /// public class IHasInputsMessenger : MessengerBase - { - private readonly IHasInputs itemDevice; + { + private readonly IHasInputs itemDevice; /// @@ -23,17 +23,16 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public IHasInputsMessenger(string key, string messagePath, IHasInputs device) : base(key, messagePath, device) { - itemDevice = device; + itemDevice = device; } protected override void RegisterActions() { base.RegisterActions(); - AddAction("/fullStatus", (id, context) => - { - SendFullStatus(); - }); + AddAction("/fullStatus", (id, context) => SendFullStatus(id)); + + AddAction("/inputStatus", (id, content) => SendFullStatus(id)); itemDevice.Inputs.ItemsUpdated += (sender, args) => { @@ -62,7 +61,7 @@ namespace PepperDash.Essentials.AppServer.Messengers } } - private void SendFullStatus() + private void SendFullStatus(string id = null) { try { @@ -77,7 +76,7 @@ namespace PepperDash.Essentials.AppServer.Messengers } }; - PostStatusMessage(stateObject); + PostStatusMessage(stateObject, id); } catch (Exception e) { diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs index 66e97352..525a6d6d 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasPowerControlWithFeedbackMessenger.cs @@ -12,6 +12,12 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly IHasPowerControlWithFeedback _powerControl; + /// + /// Initializes a new instance of the class. + /// + /// The key. + /// The message path. + /// The power control device public IHasPowerControlWithFeedbackMessenger(string key, string messagePath, IHasPowerControlWithFeedback powerControl) : base(key, messagePath, powerControl as IKeyName) { @@ -21,21 +27,24 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// SendFullStatus method /// - public void SendFullStatus() + public void SendFullStatus(string id = null) { var messageObj = new PowerControlWithFeedbackStateMessage { PowerState = _powerControl.PowerIsOnFeedback.BoolValue }; - PostStatusMessage(messageObj); + PostStatusMessage(messageObj, id); } + /// protected override void RegisterActions() { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/powerStatus", (id, content) => SendFullStatus(id)); _powerControl.PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; ; } @@ -55,6 +64,9 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class PowerControlWithFeedbackStateMessage : DeviceStateMessageBase { + /// + /// Power State + /// [JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] public bool? PowerState { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs index 6329a25c..76598cee 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasScheduleAwarenessMessenger.cs @@ -1,9 +1,9 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Devices.Common.Codec; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -27,7 +27,9 @@ namespace PepperDash.Essentials.AppServer.Messengers protected override void RegisterActions() { - AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject()); + AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject(id)); + + AddAction("/schedule/status", (id, content) => SendFullScheduleObject(id)); } private void CodecSchedule_MeetingEventChange(object sender, MeetingEventArgs e) @@ -51,13 +53,13 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Helper method to send the full schedule data /// - private void SendFullScheduleObject() + private void SendFullScheduleObject(string id = null) { PostStatusMessage(new FullScheduleMessage { Meetings = ScheduleSource.CodecSchedule.Meetings, MeetingWarningMinutes = ScheduleSource.CodecSchedule.MeetingWarningMinutes - }); + }, id); } } @@ -66,16 +68,18 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class FullScheduleMessage : DeviceStateMessageBase { - [JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Meetings /// + [JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)] public List Meetings { get; set; } - [JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the MeetingWarningMinutes /// + [JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)] public int MeetingWarningMinutes { get; set; } } @@ -84,10 +88,11 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class MeetingChangeMessage { - [JsonProperty("meetingChange", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the MeetingChange /// + [JsonProperty("meetingChange", NullValueHandling = NullValueHandling.Ignore)] public MeetingChange MeetingChange { get; set; } } @@ -96,16 +101,18 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class MeetingChange { - [JsonProperty("changeType", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the ChangeType /// + [JsonProperty("changeType", NullValueHandling = NullValueHandling.Ignore)] public string ChangeType { get; set; } - [JsonProperty("meeting", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Meeting /// + [JsonProperty("meeting", NullValueHandling = NullValueHandling.Ignore)] public Meeting Meeting { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs index 4b274270..6bd04a74 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHumiditySensor.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System; namespace PepperDash.Essentials.AppServer.Messengers { @@ -22,19 +22,21 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/humidityStatus", (id, content) => SendFullStatus(id)); device.HumidityFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); } - private void SendFullStatus() + private void SendFullStatus(string id = null) { var state = new IHumiditySensorStateMessage { Humidity = string.Format("{0}%", device.HumidityFeedback.UShortValue) }; - PostStatusMessage(state); + PostStatusMessage(state, id); } } @@ -43,10 +45,11 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class IHumiditySensorStateMessage : DeviceStateMessageBase { - [JsonProperty("humidity")] + /// /// Gets or sets the Humidity /// + [JsonProperty("humidity")] public string Humidity { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs index 946c0bfd..03bfc80f 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ILevelControlsMessenger.cs @@ -1,9 +1,9 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System.Collections.Generic; -using System.Linq; namespace PepperDash.Essentials.AppServer.Messengers { @@ -13,6 +13,7 @@ namespace PepperDash.Essentials.AppServer.Messengers public class ILevelControlsMessenger : MessengerBase { private ILevelControls levelControlsDevice; + public ILevelControlsMessenger(string key, string messagePath, ILevelControls device) : base(key, messagePath, device as IKeyName) { levelControlsDevice = device; @@ -22,15 +23,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, context) => - { - var message = new LevelControlStateMessage - { - Levels = levelControlsDevice.LevelControlPoints.ToDictionary(kv => kv.Key, kv => new Volume { Level = kv.Value.VolumeLevelFeedback.IntValue, Muted = kv.Value.MuteFeedback.BoolValue }) - }; + AddAction("/fullStatus", (id, context) => SendFullStatus(id)); - PostStatusMessage(message); - }); + AddAction("/levelStats", (id, content) => SendFullStatus(id)); foreach (var levelControl in levelControlsDevice.LevelControlPoints) { @@ -75,6 +70,16 @@ namespace PepperDash.Essentials.AppServer.Messengers })); } } + + private void SendFullStatus(string id = null) + { + var message = new LevelControlStateMessage + { + Levels = levelControlsDevice.LevelControlPoints.ToDictionary(kv => kv.Key, kv => new Volume { Level = kv.Value.VolumeLevelFeedback.IntValue, Muted = kv.Value.MuteFeedback.BoolValue }) + }; + + PostStatusMessage(message, id); + } } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs index c63bd0e4..3a1b6a27 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IMatrixRoutingMessenger.cs @@ -1,12 +1,12 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Routing; using Serilog.Events; -using System; -using System.Collections.Generic; -using System.Linq; namespace PepperDash.Essentials.AppServer.Messengers { @@ -25,25 +25,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => - { - try - { - Debug.LogMessage(LogEventLevel.Verbose, "InputCount: {inputCount}, OutputCount: {outputCount}", this, matrixDevice.InputSlots.Count, matrixDevice.OutputSlots.Count); - var message = new MatrixStateMessage - { - Outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)), - Inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)), - }; + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); - - PostStatusMessage(message); - } - catch (Exception e) - { - Debug.LogMessage(e, "Exception Getting full status: {@exception}", this, e); - } - }); + AddAction("/matrixStatus", (id, content) => SendFullStatus(id)); AddAction("/route", (id, content) => { @@ -80,6 +64,26 @@ namespace PepperDash.Essentials.AppServer.Messengers }; } } + + private void SendFullStatus(string id = null) + { + try + { + Debug.LogMessage(LogEventLevel.Verbose, "InputCount: {inputCount}, OutputCount: {outputCount}", this, matrixDevice.InputSlots.Count, matrixDevice.OutputSlots.Count); + var message = new MatrixStateMessage + { + Outputs = matrixDevice.OutputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingOutput(kvp.Value)), + Inputs = matrixDevice.InputSlots.ToDictionary(kvp => kvp.Key, kvp => new RoutingInput(kvp.Value)), + }; + + + PostStatusMessage(message, id); + } + catch (Exception e) + { + Debug.LogMessage(e, "Exception Getting full status: {@exception}", this, e); + } + } } /// diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs index f0840b5f..f63b4834 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IProjectorScreenLiftControlMessenger.cs @@ -1,9 +1,9 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System; namespace PepperDash.Essentials.AppServer.Messengers { @@ -14,17 +14,28 @@ namespace PepperDash.Essentials.AppServer.Messengers { private readonly IProjectorScreenLiftControl device; + /// + /// Initializes a new instance of the class. + /// + /// message key + /// message path + /// screen lift device public IProjectorScreenLiftControlMessenger(string key, string messagePath, IProjectorScreenLiftControl screenLiftDevice) : base(key, messagePath, screenLiftDevice as IKeyName) { device = screenLiftDevice; } + /// + /// Registers the actions for the messenger. + /// protected override void RegisterActions() { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/screenliftStatus", (id, content) => SendFullStatus(id)); AddAction("/raise", (id, content) => { @@ -53,7 +64,7 @@ namespace PepperDash.Essentials.AppServer.Messengers PostStatusMessage(JToken.FromObject(state)); } - private void SendFullStatus() + private void SendFullStatus(string id = null) { var state = new ScreenLiftStateMessage { @@ -62,7 +73,7 @@ namespace PepperDash.Essentials.AppServer.Messengers DisplayDeviceKey = device.DisplayDeviceKey }; - PostStatusMessage(state); + PostStatusMessage(state, id); } } @@ -71,20 +82,23 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class ScreenLiftStateMessage : DeviceStateMessageBase { + /// + /// Gets or sets the InUpPosition + /// [JsonProperty("inUpPosition", NullValueHandling = NullValueHandling.Ignore)] public bool? InUpPosition { get; set; } - [JsonProperty("displayDeviceKey", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the DisplayDeviceKey /// + [JsonProperty("displayDeviceKey", NullValueHandling = NullValueHandling.Ignore)] public string DisplayDeviceKey { get; set; } - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Type /// + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)] public eScreenLiftControlType Type { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs index 9bfb8b39..d5038d91 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IRunRouteActionMessenger.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; -using System; namespace PepperDash.Essentials.AppServer.Messengers @@ -36,7 +36,9 @@ namespace PepperDash.Essentials.AppServer.Messengers protected override void RegisterActions() { - AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject()); + AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject(id)); + + AddAction("/routingStatus", (id, content) => SendRoutingFullMessageObject(id)); AddAction("/source", (id, content) => { @@ -62,7 +64,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Helper method to update full status of the routing device /// - private void SendRoutingFullMessageObject() + private void SendRoutingFullMessageObject(string id = null) { if (RoutingDevice is IRoutingSink sinkDevice) { @@ -84,10 +86,10 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class RoutingStateMessage : DeviceStateMessageBase { - [JsonProperty("selectedSourceKey")] /// /// Gets or sets the SelectedSourceKey /// + [JsonProperty("selectedSourceKey")] public string SelectedSourceKey { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs index 54f1e314..8e2f8f3e 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISelectableItemsMessenger.cs @@ -1,9 +1,9 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -11,11 +11,13 @@ namespace PepperDash.Essentials.AppServer.Messengers /// Represents a ISelectableItemsMessenger /// public class ISelectableItemsMessenger : MessengerBase - { + { private readonly ISelectableItems itemDevice; private readonly string _propName; + private List _itemKeys = new List(); + /// /// Constructs a messenger for a device that implements ISelectableItems /// @@ -34,13 +36,40 @@ namespace PepperDash.Essentials.AppServer.Messengers base.RegisterActions(); AddAction("/fullStatus", (id, context) => + SendFullStatus(id) + ); + + AddAction("/itemsStatus", (id, content) => SendFullStatus(id)); + + AddAction("/selectItem", (id, content) => { - SendFullStatus(); + try + { + var key = content.ToObject(); + + if (key == null) + { + this.LogError("No key specified to select"); + return; + } + if (itemDevice.Items.ContainsKey((TKey)Convert.ChangeType(key, typeof(TKey)))) + { + itemDevice.Items[(TKey)Convert.ChangeType(key, typeof(TKey))].Select(); + } + else + { + this.LogError("Key {0} not found in items", key); + } + } + catch (Exception e) + { + this.LogError("Error selecting item: {0}", e.Message); + } }); itemDevice.ItemsUpdated += (sender, args) => { - SendFullStatus(); + SetItems(); }; itemDevice.CurrentItemChanged += (sender, args) => @@ -48,24 +77,48 @@ namespace PepperDash.Essentials.AppServer.Messengers SendFullStatus(); }; - foreach (var input in itemDevice.Items) + SetItems(); + } + + /// + /// Sets the items and registers their update events + /// + private void SetItems() + { + if (_itemKeys != null && _itemKeys.Count > 0) { - var key = input.Key; - var localItem = input.Value; + /// Clear out any existing item actions + foreach (var item in _itemKeys) + { + RemoveAction($"/{item}"); + } + + _itemKeys.Clear(); + } + + foreach (var item in itemDevice.Items) + { + var key = item.Key; + var localItem = item.Value; AddAction($"/{key}", (id, content) => { localItem.Select(); }); - localItem.ItemUpdated += (sender, args) => - { - SendFullStatus(); - }; + _itemKeys.Add(key.ToString()); + + localItem.ItemUpdated -= LocalItem_ItemUpdated; + localItem.ItemUpdated += LocalItem_ItemUpdated; } } - private void SendFullStatus() + private void LocalItem_ItemUpdated(object sender, EventArgs e) + { + SendFullStatus(); + } + + private void SendFullStatus(string id = null) { try { @@ -77,7 +130,7 @@ namespace PepperDash.Essentials.AppServer.Messengers CurrentItem = itemDevice.CurrentItem }; - PostStatusMessage(stateObject); + PostStatusMessage(stateObject, id); } catch (Exception e) { @@ -91,13 +144,17 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class ISelectableItemsStateMessage : DeviceStateMessageBase { + /// + /// Gets or sets the Items + /// [JsonProperty("items")] public Dictionary Items { get; set; } - [JsonProperty("currentItem")] + /// /// Gets or sets the CurrentItem /// + [JsonProperty("currentItem")] public TKey CurrentItem { get; set; } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs index 600779f9..516e77c6 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IShutdownPromptTimerMessenger.cs @@ -20,10 +20,9 @@ namespace PepperDash.Essentials.AppServer.Messengers protected override void RegisterActions() { - AddAction("/status", (id, content) => - { - SendFullStatus(); - }); + AddAction("/status", (id, content) => SendFullStatus(id)); + + AddAction("/shutdownPromptStatus", (id, content) => SendFullStatus(id)); AddAction("/setShutdownPromptSeconds", (id, content) => { @@ -68,7 +67,7 @@ namespace PepperDash.Essentials.AppServer.Messengers }; } - private void SendFullStatus() + private void SendFullStatus(string id = null) { var status = new IShutdownPromptTimerStateMessage { @@ -77,7 +76,7 @@ namespace PepperDash.Essentials.AppServer.Messengers PercentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue }; - PostStatusMessage(status); + PostStatusMessage(status, id); } } @@ -87,22 +86,22 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class IShutdownPromptTimerStateMessage : DeviceStateMessageBase { - [JsonProperty("secondsRemaining")] /// /// Gets or sets the SecondsRemaining /// + [JsonProperty("secondsRemaining")] public int SecondsRemaining { get; set; } - [JsonProperty("percentageRemaining")] /// /// Gets or sets the PercentageRemaining /// + [JsonProperty("percentageRemaining")] public int PercentageRemaining { get; set; } - [JsonProperty("shutdownPromptSeconds")] /// /// Gets or sets the ShutdownPromptSeconds /// + [JsonProperty("shutdownPromptSeconds")] public int ShutdownPromptSeconds { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs index 6efd182b..98223188 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ISwitchedOutputMessenger.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.CrestronIO; -using System; namespace PepperDash.Essentials.AppServer.Messengers { @@ -23,7 +23,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/switchedOutputStatus", (id, content) => SendFullStatus(id)); AddAction("/on", (id, content) => { @@ -42,14 +44,14 @@ namespace PepperDash.Essentials.AppServer.Messengers device.OutputIsOnFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); } - private void SendFullStatus() + private void SendFullStatus(string id = null) { var state = new ISwitchedOutputStateMessage { IsOn = device.OutputIsOnFeedback.BoolValue }; - PostStatusMessage(state); + PostStatusMessage(state, id); } } @@ -58,10 +60,10 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class ISwitchedOutputStateMessage : DeviceStateMessageBase { - [JsonProperty("isOn")] /// /// Gets or sets the IsOn /// + [JsonProperty("isOn")] public bool IsOn { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs index 783bee7c..283ef0c8 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITechPasswordMessenger.cs @@ -20,10 +20,9 @@ namespace PepperDash.Essentials.AppServer.Messengers protected override void RegisterActions() { - AddAction("/status", (id, content) => - { - SendFullStatus(); - }); + AddAction("/status", (id, content) => SendFullStatus(id)); + + AddAction("/techPasswordStatus", (id, content) => SendFullStatus(id)); AddAction("/validateTechPassword", (id, content) => { @@ -55,14 +54,14 @@ namespace PepperDash.Essentials.AppServer.Messengers }; } - private void SendFullStatus() + private void SendFullStatus(string id = null) { var status = new ITechPasswordStateMessage { TechPasswordLength = _room.TechPasswordLength }; - PostStatusMessage(status); + PostStatusMessage(status, id); } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs index 9f3b56eb..5963bba5 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ITemperatureSensorMessenger.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System; namespace PepperDash.Essentials.AppServer.Messengers { @@ -22,7 +22,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/temperatureStatus", (id, content) => SendFullStatus(id)); AddAction("/setTemperatureUnitsToCelcius", (id, content) => { @@ -38,7 +40,7 @@ namespace PepperDash.Essentials.AppServer.Messengers device.TemperatureInCFeedback.OutputChange += new EventHandler((o, a) => SendFullStatus()); } - private void SendFullStatus() + private void SendFullStatus(string id = null) { // format the temperature to a string with one decimal place var tempString = string.Format("{0}.{1}", device.TemperatureFeedback.UShortValue / 10, device.TemperatureFeedback.UShortValue % 10); @@ -49,7 +51,7 @@ namespace PepperDash.Essentials.AppServer.Messengers TemperatureInCelsius = device.TemperatureInCFeedback.BoolValue }; - PostStatusMessage(state); + PostStatusMessage(state, id); } } @@ -58,16 +60,16 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class ITemperatureSensorStateMessage : DeviceStateMessageBase { - [JsonProperty("temperature")] /// /// Gets or sets the Temperature /// + [JsonProperty("temperature")] public string Temperature { get; set; } - [JsonProperty("temperatureInCelsius")] /// /// Gets or sets the TemperatureInCelsius /// + [JsonProperty("temperatureInCelsius")] public bool TemperatureInCelsius { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs index 9c0672fb..71c6349f 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/LightingBaseMessenger.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Lighting; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -35,7 +35,9 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/lightingStatus", (id, content) => SendFullStatus(id)); AddAction("/selectScene", (id, content) => { @@ -43,14 +45,14 @@ namespace PepperDash.Essentials.AppServer.Messengers lightingScenesDevice.SelectScene(s); }); - if(!(lightingScenesDevice is ILightingScenesDynamic lightingScenesDynamic)) + if (!(lightingScenesDevice is ILightingScenesDynamic lightingScenesDynamic)) return; lightingScenesDynamic.LightingScenesUpdated += (s, e) => SendFullStatus(); } - private void SendFullStatus() + private void SendFullStatus(string id = null) { var state = new LightingBaseStateMessage { @@ -58,7 +60,7 @@ namespace PepperDash.Essentials.AppServer.Messengers CurrentLightingScene = lightingScenesDevice.CurrentLightingScene }; - PostStatusMessage(state); + PostStatusMessage(state, id); } } @@ -67,16 +69,17 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class LightingBaseStateMessage : DeviceStateMessageBase { - [JsonProperty("scenes", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Scenes /// + [JsonProperty("scenes", NullValueHandling = NullValueHandling.Ignore)] public List Scenes { get; set; } - [JsonProperty("currentLightingScene", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the CurrentLightingScene /// + [JsonProperty("currentLightingScene", NullValueHandling = NullValueHandling.Ignore)] public LightingScene CurrentLightingScene { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs index 491ebb67..a7210a13 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/MessengerBase.cs @@ -1,26 +1,45 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using Crestron.SimplSharp.Net; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using System; -using System.Collections.Generic; -using System.Linq; namespace PepperDash.Essentials.AppServer.Messengers { /// /// Provides a messaging bridge /// - public abstract class MessengerBase : EssentialsDevice, IMobileControlMessenger + public abstract class MessengerBase : EssentialsDevice, IMobileControlMessengerWithSubscriptions { + /// + /// The device this messenger is associated with + /// protected IKeyName _device; + /// + /// Enable subscriptions + /// + protected bool enableMessengerSubscriptions; + + /// + /// List of clients subscribed to this messenger + /// + /// + /// Unsoliciited feedback from a device in a messenger will ONLY be sent to devices in this subscription list. When a client disconnects, it's ID will be removed from the collection. + /// + protected HashSet SubscriberIds = new HashSet(); + private readonly List _deviceInterfaces; private readonly Dictionary> _actions = new Dictionary>(); + /// + /// Gets the DeviceKey + /// public string DeviceKey => _device?.Key ?? ""; @@ -50,6 +69,12 @@ namespace PepperDash.Essentials.AppServer.Messengers MessagePath = messagePath; } + /// + /// Constructor for a messenger associated with a device + /// + /// + /// + /// protected MessengerBase(string key, string messagePath, IKeyName device) : this(key, messagePath) { @@ -81,6 +106,21 @@ namespace PepperDash.Essentials.AppServer.Messengers RegisterActions(); } + /// + /// Register this messenger with appserver controller + /// + /// Parent controller for this messenger + /// Enable subscriptions + public void RegisterWithAppServer(IMobileControl appServerController, bool enableMessengerSubscriptions) + { + this.enableMessengerSubscriptions = enableMessengerSubscriptions; + AppServerController = appServerController ?? throw new ArgumentNullException("appServerController"); + + AppServerController.AddAction(this, HandleMessage); + + RegisterActions(); + } + private void HandleMessage(string path, string id, JToken content) { // replace base path with empty string. Should leave something like /fullStatus @@ -91,16 +131,20 @@ namespace PepperDash.Essentials.AppServer.Messengers return; } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Executing action for path {path}", this, path); + this.LogDebug("Executing action for path {path}", path); action(id, content); } + /// + /// Adds an action for a given path + /// + /// + /// protected void AddAction(string path, Action action) { if (_actions.ContainsKey(path)) { - //Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Messenger {Key} already has action registered at {path}", this); return; } @@ -115,6 +159,10 @@ namespace PepperDash.Essentials.AppServer.Messengers return _actions.Keys.ToList(); } + /// + /// Removes an action for a given path + /// + /// protected void RemoveAction(string path) { if (!_actions.ContainsKey(path)) @@ -128,17 +176,62 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Implemented in extending classes. Wire up API calls and feedback here /// - /// protected virtual void RegisterActions() { } + /// + /// Add client to the susbscription list for unsolicited feedback + /// + /// Client ID to add + protected void SubscribeClient(string clientId) + { + if (!enableMessengerSubscriptions) + { + this.LogWarning("Messenger subscriptions not enabled"); + return; + } + + if (SubscriberIds.Any(id => id == clientId)) + { + this.LogVerbose("Client {clientId} already subscribed", clientId); + return; + } + + SubscriberIds.Add(clientId); + + this.LogDebug("Client {clientId} subscribed", clientId); + } + + /// + /// Remove a client from the subscription list + /// + /// Client ID to remove + public void UnsubscribeClient(string clientId) + { + if (!enableMessengerSubscriptions) + { + this.LogWarning("Messenger subscriptions not enabled"); + return; + } + + if (!SubscriberIds.Any(i => i == clientId)) + { + this.LogVerbose("Client with ID {clientId} is not subscribed", clientId); + return; + } + + SubscriberIds.RemoveWhere((i) => i == clientId); + + this.LogInformation("Client with ID {clientId} unsubscribed", clientId); + } + /// /// Helper for posting status message /// - /// /// + /// Optional client id that will direct the message back to only that client protected void PostStatusMessage(DeviceStateMessageBase message, string clientId = null) { try @@ -159,16 +252,22 @@ namespace PepperDash.Essentials.AppServer.Messengers message.Name = _device.Name; - var token = JToken.FromObject(message); - + var token = JToken.FromObject(message); + PostStatusMessage(token, MessagePath, clientId); } catch (Exception ex) { - this.LogError(ex, "Exception posting status message for {messagePath} to {clientId}", MessagePath, clientId ?? "all clients"); + this.LogError(ex, "Exception posting status message for {messagePath} to {clientId}", MessagePath, clientId ?? "all clients"); } } + /// + /// Helper for posting status message + /// + /// + /// + /// Optional client id that will direct the message back to only that client protected void PostStatusMessage(string type, DeviceStateMessageBase deviceState, string clientId = null) { try @@ -188,22 +287,54 @@ namespace PepperDash.Essentials.AppServer.Messengers } catch (Exception ex) { - this.LogError(ex, "Exception posting status message for {type} to {clientId}", type, clientId ?? "all clients"); + this.LogError(ex, "Exception posting status message for {type} to {clientId}", type, clientId ?? "all clients"); } } + /// + /// Helper for posting status message + /// + /// + /// + /// Optional client id that will direct the message back to only that client protected void PostStatusMessage(JToken content, string type = "", string clientId = null) { try { + // Allow for legacy method to continue without subscriptions + if (!enableMessengerSubscriptions) + { + AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content }); + return; + } + + // handle subscription feedback + // If client is null or empty, this message is unsolicited feedback. Iterate through the subscriber list and send to all interested parties + if (string.IsNullOrEmpty(clientId)) + { + foreach (var client in SubscriberIds) + { + AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = client, Content = content }); + } + + return; + } + + SubscribeClient(clientId); + AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = clientId, Content = content }); } catch (Exception ex) { - Debug.LogMessage(ex, "Exception posting status message", this); + this.LogError("Exception posting status message: {message}", ex.Message); + this.LogDebug(ex, "Stack Trace: "); } } + /// + /// Helper for posting event message + /// + /// protected void PostEventMessage(DeviceEventMessageBase message) { message.Key = _device.Key; @@ -217,6 +348,11 @@ namespace PepperDash.Essentials.AppServer.Messengers }); } + /// + /// Helper for posting event message + /// + /// + /// protected void PostEventMessage(DeviceEventMessageBase message, string eventType) { message.Key = _device.Key; @@ -232,6 +368,10 @@ namespace PepperDash.Essentials.AppServer.Messengers }); } + /// + /// Helper for posting event message with no content + /// + /// protected void PostEventMessage(string eventType) { AppServerController?.SendMessageObject(new MobileControlMessage @@ -242,64 +382,4 @@ namespace PepperDash.Essentials.AppServer.Messengers } } - - public abstract class DeviceMessageBase - { - /// - /// The device key - /// - [JsonProperty("key")] - /// - /// Gets or sets the Key - /// - public string Key { get; set; } - - /// - /// The device name - /// - [JsonProperty("name")] - public string Name { get; set; } - - /// - /// The type of the message class - /// - [JsonProperty("messageType")] - public string MessageType => GetType().Name; - - [JsonProperty("messageBasePath")] - /// - /// Gets or sets the MessageBasePath - /// - public string MessageBasePath { get; set; } - } - - /// - /// Represents a DeviceStateMessageBase - /// - public class DeviceStateMessageBase : DeviceMessageBase - { - /// - /// The interfaces implmented by the device sending the messsage - /// - [JsonProperty("interfaces")] - public List Interfaces { get; private set; } - - public void SetInterfaces(List interfaces) - { - Interfaces = interfaces; - } - } - - /// - /// Base class for event messages that include the type of message and an event type - /// - public abstract class DeviceEventMessageBase : DeviceMessageBase - { - /// - /// The event type - /// - [JsonProperty("eventType")] - public string EventType { get; set; } - } - -} \ No newline at end of file +} diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs index 46728dba..b076566b 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/PressAndHoldHandler.cs @@ -1,11 +1,14 @@ -using Crestron.SimplSharp; +using System; +using System.Collections.Generic; +using Crestron.SimplSharp; using Newtonsoft.Json.Linq; using PepperDash.Core; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { + /// + /// Handler for press/hold/release messages + /// public static class PressAndHoldHandler { private const long ButtonHeartbeatInterval = 1000; @@ -26,21 +29,21 @@ namespace PepperDash.Essentials.AppServer.Messengers private static void AddTimer(string deviceKey, Action action) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to add timer for {deviceKey}", deviceKey); + Debug.LogDebug("Attempting to add timer for {deviceKey}", deviceKey); if (_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} already exists", deviceKey); + Debug.LogDebug("Timer for {deviceKey} already exists", deviceKey); return; } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Adding timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); + Debug.LogDebug("Adding timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); action(true); cancelTimer = new CTimer(o => { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer expired for {deviceKey}", deviceKey); + Debug.LogDebug("Timer expired for {deviceKey}", deviceKey); action(false); @@ -52,30 +55,30 @@ namespace PepperDash.Essentials.AppServer.Messengers private static void ResetTimer(string deviceKey, Action action) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to reset timer for {deviceKey}", deviceKey); + Debug.LogDebug("Attempting to reset timer for {deviceKey}", deviceKey); if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} not found", deviceKey); + Debug.LogDebug("Timer for {deviceKey} not found", deviceKey); return; } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Resetting timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); + Debug.LogDebug("Resetting timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); cancelTimer.Reset(ButtonHeartbeatInterval); } private static void StopTimer(string deviceKey, Action action) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to stop timer for {deviceKey}", deviceKey); + Debug.LogDebug("Attempting to stop timer for {deviceKey}", deviceKey); if (!_pushedActions.TryGetValue(deviceKey, out CTimer cancelTimer)) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Timer for {deviceKey} not found", deviceKey); + Debug.LogDebug("Timer for {deviceKey} not found", deviceKey); return; } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Stopping timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); + Debug.LogDebug("Stopping timer for {deviceKey} with due time {dueTime}", deviceKey, ButtonHeartbeatInterval); action(false); cancelTimer.Stop(); @@ -84,15 +87,15 @@ namespace PepperDash.Essentials.AppServer.Messengers public static Action> GetPressAndHoldHandler(string value) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting press and hold handler for {value}", value); + Debug.LogDebug("Getting press and hold handler for {value}", value); if (!_pushedActionHandlers.TryGetValue(value, out Action> handler)) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Press and hold handler for {value} not found", value); + Debug.LogDebug("Press and hold handler for {value} not found", value); return null; } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Got handler for {value}", value); + Debug.LogDebug("Got handler for {value}", value); return handler; } @@ -104,7 +107,7 @@ namespace PepperDash.Essentials.AppServer.Messengers { var msg = content.ToObject>(); - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Handling press and hold message of {type} for {deviceKey}", msg.Value, deviceKey); + Debug.LogDebug("Handling press and hold message of {type} for {deviceKey}", msg.Value, deviceKey); var timerHandler = GetPressAndHoldHandler(msg.Value); diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs index f5c019d1..2e10d0f3 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/RoomEventScheduleMessenger.cs @@ -1,10 +1,10 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.Core; using PepperDash.Essentials.Room.Config; -using System; -using System.Collections.Generic; namespace PepperDash.Essentials.AppServer.Messengers { @@ -31,7 +31,14 @@ namespace PepperDash.Essentials.AppServer.Messengers { var events = _room.GetScheduledEvents(); - SendFullStatus(events); + SendFullStatus(events, id); + }); + + AddAction("/scheduledEventsStatus", (id, content) => + { + var events = _room.GetScheduledEvents(); + + SendFullStatus(events, id); }); _room.ScheduledEventsChanged += (sender, args) => SendFullStatus(args.ScheduledEvents); @@ -55,11 +62,11 @@ namespace PepperDash.Essentials.AppServer.Messengers } catch (Exception ex) { - this.LogException(ex,"Exception saving event"); + this.LogException(ex, "Exception saving event"); } } - private void SendFullStatus(List events) + private void SendFullStatus(List events, string id = null) { var message = new RoomEventScheduleStateMessage @@ -67,7 +74,7 @@ namespace PepperDash.Essentials.AppServer.Messengers ScheduleEvents = events, }; - PostStatusMessage(message); + PostStatusMessage(message, id); } } diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs index 8a071409..5492cc2b 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/ShadeBaseMessenger.cs @@ -1,7 +1,7 @@ -using Newtonsoft.Json; +using System; +using Newtonsoft.Json; using PepperDash.Core; using PepperDash.Essentials.Core.Shades; -using System; namespace PepperDash.Essentials.AppServer.Messengers { @@ -22,7 +22,8 @@ namespace PepperDash.Essentials.AppServer.Messengers { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + AddAction("/shadesStatus", (id, content) => SendFullStatus(id)); AddAction("/shadeUp", (id, content) => { @@ -75,7 +76,7 @@ namespace PepperDash.Essentials.AppServer.Messengers } - private void SendFullStatus() + private void SendFullStatus(string id = null) { var state = new ShadeBaseStateMessage(); @@ -85,7 +86,7 @@ namespace PepperDash.Essentials.AppServer.Messengers state.IsClosed = feedbackDevice.ShadeIsClosedFeedback.BoolValue; } - PostStatusMessage(state); + PostStatusMessage(state, id); } } @@ -94,10 +95,11 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class ShadeBaseStateMessage : DeviceStateMessageBase { - [JsonProperty("middleButtonLabel", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the MiddleButtonLabel /// + [JsonProperty("middleButtonLabel", NullValueHandling = NullValueHandling.Ignore)] public string MiddleButtonLabel { get; set; } [JsonProperty("isOpen", NullValueHandling = NullValueHandling.Ignore)] diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs index 0080153c..63869ae0 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/SystemMonitorMessenger.cs @@ -1,10 +1,10 @@ -using Crestron.SimplSharp; +using System; +using System.Threading.Tasks; +using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core.Monitoring; -using System; -using System.Threading.Tasks; namespace PepperDash.Essentials.AppServer.Messengers { @@ -56,36 +56,37 @@ namespace PepperDash.Essentials.AppServer.Messengers SendSystemMonitorStatusMessage(); } - private void SendFullStatusMessage() + private void SendFullStatusMessage(string id = null) { - SendSystemMonitorStatusMessage(); + SendSystemMonitorStatusMessage(id); foreach (var p in systemMonitor.ProgramStatusFeedbackCollection) { - PostStatusMessage(JToken.FromObject(p.Value.ProgramInfo)); + PostStatusMessage(JToken.FromObject(p.Value.ProgramInfo), id); } } - private void SendSystemMonitorStatusMessage() + private void SendSystemMonitorStatusMessage(string id = null) { // This takes a while, launch a new thread - + Task.Run(() => PostStatusMessage(JToken.FromObject(new SystemMonitorStateMessage { - TimeZone = systemMonitor.TimeZoneFeedback.IntValue, TimeZoneName = systemMonitor.TimeZoneTextFeedback.StringValue, IoControllerVersion = systemMonitor.IoControllerVersionFeedback.StringValue, SnmpVersion = systemMonitor.SnmpVersionFeedback.StringValue, BacnetVersion = systemMonitor.BaCnetAppVersionFeedback.StringValue, ControllerVersion = systemMonitor.ControllerVersionFeedback.StringValue - }) + }), id )); } protected override void RegisterActions() { - AddAction("/fullStatus", (id, content) => SendFullStatusMessage()); + AddAction("/fullStatus", (id, content) => SendFullStatusMessage(id)); + + AddAction("/systemStatus", (id, content) => SendFullStatusMessage(id)); } } @@ -94,40 +95,45 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class SystemMonitorStateMessage { - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the TimeZone /// + [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] public int TimeZone { get; set; } - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the TimeZoneName /// + [JsonProperty("timeZoneName", NullValueHandling = NullValueHandling.Ignore)] public string TimeZoneName { get; set; } - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the IoControllerVersion /// + [JsonProperty("ioControllerVersion", NullValueHandling = NullValueHandling.Ignore)] public string IoControllerVersion { get; set; } - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the SnmpVersion /// + [JsonProperty("snmpVersion", NullValueHandling = NullValueHandling.Ignore)] public string SnmpVersion { get; set; } - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the BacnetVersion /// + [JsonProperty("bacnetVersion", NullValueHandling = NullValueHandling.Ignore)] public string BacnetVersion { get; set; } - [JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the ControllerVersion /// + [JsonProperty("controllerVersion", NullValueHandling = NullValueHandling.Ignore)] public string ControllerVersion { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs index 9bc4c12b..5147da4d 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/TwoWayDisplayBaseMessenger.cs @@ -23,7 +23,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// SendFullStatus method /// - public void SendFullStatus() + public void SendFullStatus(string id = null) { var messageObj = new TwoWayDisplayBaseStateMessage { @@ -31,16 +31,17 @@ namespace PepperDash.Essentials.AppServer.Messengers CurrentInput = _display.CurrentInputFeedback.StringValue }; - PostStatusMessage(messageObj); + PostStatusMessage(messageObj, id); } protected override void RegisterActions() { base.RegisterActions(); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + + AddAction("/displayStatus", (id, content) => SendFullStatus(id)); - //_display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange; _display.CurrentInputFeedback.OutputChange += CurrentInputFeedbackOnOutputChange; _display.IsCoolingDownFeedback.OutputChange += IsCoolingFeedbackOnOutputChange; _display.IsWarmingUpFeedback.OutputChange += IsWarmingFeedbackOnOutputChange; @@ -55,16 +56,6 @@ namespace PepperDash.Essentials.AppServer.Messengers ); } - - //private void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) - //{ - // PostStatusMessage(JToken.FromObject(new - // { - // powerState = feedbackEventArgs.BoolValue - // }) - // ); - //} - private void IsWarmingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) { PostStatusMessage(JToken.FromObject(new @@ -96,10 +87,11 @@ namespace PepperDash.Essentials.AppServer.Messengers //[JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)] //public bool? PowerState { get; set; } - [JsonProperty("currentInput", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the CurrentInput /// + [JsonProperty("currentInput", NullValueHandling = NullValueHandling.Ignore)] public string CurrentInput { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs index 58300f55..071eaf27 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/VideoCodecBaseMessenger.cs @@ -1,4 +1,8 @@ -using Crestron.SimplSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Crestron.SimplSharp; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; @@ -9,9 +13,6 @@ using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; -using System; -using System.Collections.Generic; -using System.Linq; namespace PepperDash.Essentials.AppServer.Messengers { @@ -151,7 +152,8 @@ namespace PepperDash.Essentials.AppServer.Messengers PostStatusMessage(state); SendFullStatus(); - } catch (Exception ex) + } + catch (Exception ex) { this.LogError(ex, "Error sending codec ready status"); } @@ -169,7 +171,8 @@ namespace PepperDash.Essentials.AppServer.Messengers AddAction("/isReady", (id, content) => SendIsReady()); - AddAction("/fullStatus", (id, content) => SendFullStatus()); + AddAction("/fullStatus", (id, content) => SendFullStatus(id)); + AddAction("/codecStatus", (id, content) => SendFullStatus(id)); AddAction("/dial", (id, content) => { @@ -369,7 +372,8 @@ namespace PepperDash.Essentials.AppServer.Messengers }; PostStatusMessage(state); - } catch (Exception ex) + } + catch (Exception ex) { this.LogError(ex, "Error posting sharing source"); } @@ -385,7 +389,8 @@ namespace PepperDash.Essentials.AppServer.Messengers }; PostStatusMessage(state); - } catch (Exception ex) + } + catch (Exception ex) { this.LogError(ex, "Error posting sharing content"); } @@ -435,7 +440,8 @@ namespace PepperDash.Essentials.AppServer.Messengers { MapCameraActions(); PostSelectedCamera(); - } catch(Exception ex) + } + catch (Exception ex) { this.LogError(ex, "Exception handling camera selected event"); } @@ -780,14 +786,14 @@ namespace PepperDash.Essentials.AppServer.Messengers } } - protected virtual void SendFullStatus() + protected virtual void SendFullStatus(string id = null) { if (!Codec.IsReady) { return; } - CrestronInvoke.BeginInvoke((o) => PostStatusMessage(GetStatus())); + Task.Run(() => PostStatusMessage(GetStatus(), id)); } private void PostReceivingContent(bool receivingContent) @@ -800,7 +806,8 @@ namespace PepperDash.Essentials.AppServer.Messengers }; PostStatusMessage(state); - } catch(Exception ex) + } + catch (Exception ex) { this.LogError(ex, "Error posting receiving content"); } @@ -949,22 +956,25 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("cameraSupportsOffMode", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraSupportsOffMode { get; set; } - [JsonProperty("currentDialString", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the CurrentDialString /// + [JsonProperty("currentDialString", NullValueHandling = NullValueHandling.Ignore)] public string CurrentDialString { get; set; } - [JsonProperty("currentDirectory", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the CurrentDirectory /// + [JsonProperty("currentDirectory", NullValueHandling = NullValueHandling.Ignore)] public CodecDirectory CurrentDirectory { get; set; } - [JsonProperty("directorySelectedFolderName", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the DirectorySelectedFolderName /// + [JsonProperty("directorySelectedFolderName", NullValueHandling = NullValueHandling.Ignore)] public string DirectorySelectedFolderName { get; set; } [JsonProperty("hasCameras", NullValueHandling = NullValueHandling.Ignore)] @@ -985,10 +995,11 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("initialPhonebookSyncComplete", NullValueHandling = NullValueHandling.Ignore)] public bool? InitialPhonebookSyncComplete { get; set; } - [JsonProperty("info", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Info /// + [JsonProperty("info", NullValueHandling = NullValueHandling.Ignore)] public VideoCodecInfo Info { get; set; } [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] @@ -1000,16 +1011,18 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("isZoomRoom", NullValueHandling = NullValueHandling.Ignore)] public bool? IsZoomRoom { get; set; } - [JsonProperty("meetingInfo", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the MeetingInfo /// + [JsonProperty("meetingInfo", NullValueHandling = NullValueHandling.Ignore)] public MeetingInfo MeetingInfo { get; set; } - [JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Presets /// + [JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)] public List Presets { get; set; } [JsonProperty("privacyModeIsOn", NullValueHandling = NullValueHandling.Ignore)] @@ -1024,10 +1037,11 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("sharingContentIsOn", NullValueHandling = NullValueHandling.Ignore)] public bool? SharingContentIsOn { get; set; } - [JsonProperty("sharingSource", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the SharingSource /// + [JsonProperty("sharingSource", NullValueHandling = NullValueHandling.Ignore)] public string SharingSource { get; set; } [JsonProperty("showCamerasWhenNotInCall", NullValueHandling = NullValueHandling.Ignore)] @@ -1057,23 +1071,26 @@ namespace PepperDash.Essentials.AppServer.Messengers [JsonProperty("cameraOffSupported", NullValueHandling = NullValueHandling.Ignore)] public bool? CameraOffIsSupported { get; set; } - [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the CameraMode /// + [JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)] public string CameraMode { get; set; } - [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Cameras /// + [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] public List Cameras { get; set; } - [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the SelectedCamera /// - public Camera SelectedCamera { get; set; } + [JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)] + public Camera SelectedCamera { get; set; } } /// @@ -1081,25 +1098,28 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class Camera { - [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Key /// + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key { get; set; } - [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Name /// + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } [JsonProperty("isFarEnd", NullValueHandling = NullValueHandling.Ignore)] public bool? IsFarEnd { get; set; } - [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Capabilities /// + [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] public CameraCapabilities Capabilities { get; set; } } @@ -1135,27 +1155,31 @@ namespace PepperDash.Essentials.AppServer.Messengers /// public class PasswordPromptEventMessage : VideoCodecBaseEventMessage { - [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the Message /// + [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)] public string Message { get; set; } - [JsonProperty("lastAttemptWasIncorrect", NullValueHandling = NullValueHandling.Ignore)] + + /// /// Gets or sets the LastAttemptWasIncorrect /// + [JsonProperty("lastAttemptWasIncorrect", NullValueHandling = NullValueHandling.Ignore)] public bool LastAttemptWasIncorrect { get; set; } - [JsonProperty("loginAttemptFailed", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the LoginAttemptFailed /// + [JsonProperty("loginAttemptFailed", NullValueHandling = NullValueHandling.Ignore)] public bool LoginAttemptFailed { get; set; } - [JsonProperty("loginAttemptCancelled", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the LoginAttemptCancelled /// + [JsonProperty("loginAttemptCancelled", NullValueHandling = NullValueHandling.Ignore)] public bool LoginAttemptCancelled { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs b/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs index 69684f47..7ba130bc 100644 --- a/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs +++ b/src/PepperDash.Essentials.MobileControl/AuthorizationResponse.cs @@ -7,16 +7,18 @@ namespace PepperDash.Essentials /// public class AuthorizationResponse { - [JsonProperty("authorized")] + /// /// Gets or sets the Authorized /// + [JsonProperty("authorized")] public bool Authorized { get; set; } - [JsonProperty("reason", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Reason /// + [JsonProperty("reason", NullValueHandling = NullValueHandling.Ignore)] public string Reason { get; set; } = null; } @@ -25,10 +27,11 @@ namespace PepperDash.Essentials /// public class AuthorizationRequest { - [JsonProperty("grantCode")] + /// /// Gets or sets the GrantCode /// + [JsonProperty("grantCode")] public string GrantCode { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl/ClientSpecificUpdateRequest.cs b/src/PepperDash.Essentials.MobileControl/ClientSpecificUpdateRequest.cs new file mode 100644 index 00000000..beddd2f6 --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl/ClientSpecificUpdateRequest.cs @@ -0,0 +1,20 @@ +using System; + +namespace PepperDash.Essentials +{ + /// + /// Represents a ClientSpecificUpdateRequest + /// + public class ClientSpecificUpdateRequest + { + public ClientSpecificUpdateRequest(Action action) + { + ResponseMethod = action; + } + + /// + /// Gets or sets the ResponseMethod + /// + public Action ResponseMethod { get; private set; } + } +} diff --git a/src/PepperDash.Essentials.MobileControl/Interfaces.cs b/src/PepperDash.Essentials.MobileControl/IDelayedConfiguration.cs similarity index 100% rename from src/PepperDash.Essentials.MobileControl/Interfaces.cs rename to src/PepperDash.Essentials.MobileControl/IDelayedConfiguration.cs diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs b/src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs index 6c130f6d..ec7219a3 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlConfig.cs @@ -38,6 +38,12 @@ namespace PepperDash.Essentials /// [JsonProperty("enableApiServer")] public bool EnableApiServer { get; set; } = true; + + /// + /// Enable subscriptions for Messengers + /// + [JsonProperty("enableMessengerSubscriptions")] + public bool EnableMessengerSubscriptions { get; set; } } /// @@ -78,6 +84,15 @@ namespace PepperDash.Essentials [JsonProperty("csLanUiDeviceKeys")] public List CSLanUiDeviceKeys { get; set; } + /// + /// Get or set the Secure property + /// + /// + /// Indicates whether the connection is secure (HTTPS). + /// + [JsonProperty("Secure")] + public bool Secure { get; set; } + /// /// Initializes a new instance of the MobileControlDirectServerPropertiesConfig class. /// diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs b/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs index d27a8449..7183ec84 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlEssentialsConfig.cs @@ -1,6 +1,6 @@ -using Newtonsoft.Json; +using System.Collections.Generic; +using Newtonsoft.Json; using PepperDash.Essentials.Core.Config; -using System.Collections.Generic; namespace PepperDash.Essentials @@ -39,10 +39,11 @@ namespace PepperDash.Essentials /// public class MobileControlRuntimeInfo { - [JsonProperty("pluginVersion")] + /// /// Gets or sets the PluginVersion /// + [JsonProperty("pluginVersion")] public string PluginVersion { get; set; } [JsonProperty("essentialsVersion")] @@ -51,10 +52,11 @@ namespace PepperDash.Essentials [JsonProperty("pepperDashCoreVersion")] public string PepperDashCoreVersion { get; set; } - [JsonProperty("essentialsPlugins")] + /// /// Gets or sets the EssentialsPlugins /// + [JsonProperty("essentialsPlugins")] public List EssentialsPlugins { get; set; } } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs index 49e71010..d6a40ede 100644 --- a/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs +++ b/src/PepperDash.Essentials.MobileControl/MobileControlSystemController.cs @@ -54,7 +54,10 @@ namespace PepperDash.Essentials StringComparer.InvariantCultureIgnoreCase ); - public Dictionary> ActionDictionary => _actionDictionary; + /// + /// Actions + /// + public ReadOnlyDictionary> ActionDictionary => new ReadOnlyDictionary>(_actionDictionary); private readonly GenericQueue _receiveQueue; private readonly List _roomBridges = @@ -66,6 +69,16 @@ namespace PepperDash.Essentials private readonly Dictionary _defaultMessengers = new Dictionary(); + /// + /// Get the custom messengers with subscriptions + /// + public ReadOnlyDictionary Messengers => new ReadOnlyDictionary(_messengers.Values.OfType().ToDictionary(k => k.Key, v => v)); + + /// + /// Get the default messengers + /// + public ReadOnlyDictionary DefaultMessengers => new ReadOnlyDictionary(_defaultMessengers.Values.OfType().ToDictionary(k => k.Key, v => v)); + private readonly GenericQueue _transmitToServerQueue; private readonly GenericQueue _transmitToClientsQueue; @@ -244,7 +257,7 @@ namespace PepperDash.Essentials CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - ApiOnlineAndAuthorized = new BoolFeedback(() => + ApiOnlineAndAuthorized = new BoolFeedback("apiOnlineAndAuthorized", () => { if (_wsClient2 == null) return false; @@ -392,14 +405,15 @@ namespace PepperDash.Essentials messengerAdded = true; } - if (device is CameraBase cameraDevice) + // Default to IHasCameraControls if CameraBase and IHasCameraControls + if (device is CameraBase cameraDevice && !(device is IHasCameraControls)) { this.LogVerbose( "Adding CameraBaseMessenger for {deviceKey}", device.Key ); - var cameraMessenger = new CameraBaseMessenger( + var cameraMessenger = new CameraBaseMessenger( $"{device.Key}-cameraBase-{Key}", cameraDevice, $"/device/{device.Key}" @@ -410,6 +424,21 @@ namespace PepperDash.Essentials messengerAdded = true; } + if (device is IHasCameraControls cameraControlDev) + { + this.LogVerbose( + "Adding IHasCamerasWithControlMessenger for {deviceKey}", + device.Key + ); + var cameraControlMessenger = new CameraBaseMessenger( + $"{device.Key}-hasCamerasWithControls-{Key}", + cameraControlDev, + $"/device/{device.Key}" + ); + AddDefaultDeviceMessenger(cameraControlMessenger); + messengerAdded = true; + } + if (device is BlueJeansPc) { this.LogVerbose( @@ -486,15 +515,15 @@ namespace PepperDash.Essentials messengerAdded = true; } - if (device is IBasicVolumeWithFeedback) + if (device is IBasicVolumeControls) { var deviceKey = device.Key; this.LogVerbose( - "Adding IBasicVolumeControlWithFeedback for {deviceKey}", + "Adding IBasicVolumeControls for {deviceKey}", deviceKey ); - var volControlDevice = device as IBasicVolumeWithFeedback; + var volControlDevice = device as IBasicVolumeControls; var messenger = new DeviceVolumeMessenger( $"{device.Key}-volume-{Key}", string.Format("/device/{0}", deviceKey), @@ -962,6 +991,19 @@ namespace PepperDash.Essentials messengerAdded = true; } + if (device is IHasCamerasWithControls cameras2) + { + this.LogVerbose("Adding IHasCamerasWithControlsMessenger for {deviceKey}", device.Key + ); + var messenger = new IHasCamerasWithControlMessenger( + $"{device.Key}-cameras-{Key}", + $"/device/{device.Key}", + cameras2 + ); + AddDefaultDeviceMessenger(messenger); + messengerAdded = true; + } + this.LogVerbose("Trying to cast to generic device for device: {key}", device.Key); if (device is EssentialsDevice) @@ -1199,8 +1241,7 @@ namespace PepperDash.Essentials if (_initialized) { - this.LogDebug("Registering messenger {messengerKey} AFTER initialization", messenger.Key); - messenger.RegisterWithAppServer(this); + RegisterMessengerWithServer(messenger); } } @@ -1241,6 +1282,12 @@ namespace PepperDash.Essentials messenger.MessagePath ); + if (messenger is IMobileControlMessengerWithSubscriptions subMessenger) + { + subMessenger.RegisterWithAppServer(this, Config.EnableMessengerSubscriptions); + return; + } + messenger.RegisterWithAppServer(this); } @@ -1335,11 +1382,30 @@ namespace PepperDash.Essentials { Log = { - Output = (data, s) => - this.LogDebug( - "Message from websocket: {message}", - data - ) + Output = (data, message) => + { + switch (data.Level) + { + case LogLevel.Trace: + this.LogVerbose(data.Message); + break; + case LogLevel.Debug: + this.LogDebug(data.Message); + break; + case LogLevel.Info: + this.LogInformation(data.Message); + break; + case LogLevel.Warn: + this.LogWarning(data.Message); + break; + case LogLevel.Error: + this.LogError(data.Message); + break; + case LogLevel.Fatal: + this.LogFatal(data.Message); + break; + } + } } }; @@ -1383,13 +1449,13 @@ namespace PepperDash.Essentials private void SetWebsocketDebugLevel(string cmdparameters) { - if (CrestronEnvironment.ProgramCompatibility == eCrestronSeries.Series4) - { - this.LogInformation( - "Setting websocket log level not currently allowed on 4 series." - ); - return; // Web socket log level not currently allowed in series4 - } + // if (CrestronEnvironment.ProgramCompatibility == eCrestronSeries.Series4) + // { + // this.LogInformation( + // "Setting websocket log level not currently allowed on 4 series." + // ); + // return; // Web socket log level not currently allowed in series4 + // } if (string.IsNullOrEmpty(cmdparameters)) { @@ -1415,6 +1481,8 @@ namespace PepperDash.Essentials _wsClient2.Log.Level = _wsLogLevel; } + _directServer?.SetWebsocketLogLevel(_wsLogLevel); + CrestronConsole.ConsoleCommandResponse($"Websocket log level set to {debugLevel}"); } catch @@ -1484,7 +1552,7 @@ namespace PepperDash.Essentials /// /// Adds an action to the dictionary /// - /// The path of the API command + /// The messenger for the API command /// The action to be triggered by the commmand public void AddAction(T messenger, Action action) where T : IMobileControlMessenger @@ -2194,8 +2262,21 @@ namespace PepperDash.Essentials return; } + if (_roomCombiner.CurrentScenario == null) + { + var message = new MobileControlMessage + { + Type = "/system/roomKey", + ClientId = clientId, + Content = roomKey + }; + SendMessageObject(message); + return; + } + if (!_roomCombiner.CurrentScenario.UiMap.ContainsKey(roomKey)) { + this.LogWarning( "Unable to find correct roomKey for {roomKey} in current scenario. Returning {roomKey} as roomKey", roomKey); @@ -2420,33 +2501,4 @@ namespace PepperDash.Essentials CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r"); } } - - /// - /// Represents a ClientSpecificUpdateRequest - /// - public class ClientSpecificUpdateRequest - { - public ClientSpecificUpdateRequest(Action action) - { - ResponseMethod = action; - } - - /// - /// Gets or sets the ResponseMethod - /// - public Action ResponseMethod { get; private set; } - } - - /// - /// Represents a UserCodeChanged - /// - public class UserCodeChanged - { - public Action UpdateUserCode { get; private set; } - - public UserCodeChanged(Action updateMethod) - { - UpdateUserCode = updateMethod; - } - } } diff --git a/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs b/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs index a3485aec..f0463f27 100644 --- a/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs +++ b/src/PepperDash.Essentials.MobileControl/RoomBridges/MobileControlEssentialsRoomBridge.cs @@ -1,4 +1,7 @@ -using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; @@ -17,9 +20,6 @@ using PepperDash.Essentials.Devices.Common.Room; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Room.Config; using PepperDash.Essentials.WebSocketServer; -using System; -using System.Collections.Generic; -using System.Linq; using IShades = PepperDash.Essentials.Core.Shades.IShades; using ShadeBase = PepperDash.Essentials.Devices.Common.Shades.ShadeBase; @@ -485,6 +485,7 @@ namespace PepperDash.Essentials.RoomBridges /// Sends the full status of the room to the server /// /// + /// private void SendFullStatusForClientId(string id, IEssentialsRoom room) { //Parent.SendMessageObject(GetFullStatus(room)); @@ -554,6 +555,7 @@ namespace PepperDash.Essentials.RoomBridges /// /// Determines the configuration of the room and the details about the devices associated with the room + /// /// /// private RoomConfiguration GetRoomConfiguration(IEssentialsRoom room) @@ -798,31 +800,38 @@ namespace PepperDash.Essentials.RoomBridges /// public class RoomStateMessage : DeviceStateMessageBase { - [JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Configuration /// + [JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)] public RoomConfiguration Configuration { get; set; } [JsonProperty("activityMode", NullValueHandling = NullValueHandling.Ignore)] public int? ActivityMode { get; set; } + [JsonProperty("advancedSharingActive", NullValueHandling = NullValueHandling.Ignore)] public bool? AdvancedSharingActive { get; set; } + [JsonProperty("isOn", NullValueHandling = NullValueHandling.Ignore)] public bool? IsOn { get; set; } + [JsonProperty("isWarmingUp", NullValueHandling = NullValueHandling.Ignore)] public bool? IsWarmingUp { get; set; } + [JsonProperty("isCoolingDown", NullValueHandling = NullValueHandling.Ignore)] public bool? IsCoolingDown { get; set; } - [JsonProperty("selectedSourceKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the SelectedSourceKey /// + [JsonProperty("selectedSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string SelectedSourceKey { get; set; } - [JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Share /// + [JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)] public ShareState Share { get; set; } [JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)] @@ -837,13 +846,16 @@ namespace PepperDash.Essentials.RoomBridges /// public class ShareState { - [JsonProperty("currentShareText", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the CurrentShareText /// + [JsonProperty("currentShareText", NullValueHandling = NullValueHandling.Ignore)] public string CurrentShareText { get; set; } + [JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)] public bool? Enabled { get; set; } + [JsonProperty("isSharing", NullValueHandling = NullValueHandling.Ignore)] public bool? IsSharing { get; set; } } @@ -853,131 +865,156 @@ namespace PepperDash.Essentials.RoomBridges /// public class RoomConfiguration { - //[JsonProperty("shutdownPromptSeconds", NullValueHandling = NullValueHandling.Ignore)] - //public int? ShutdownPromptSeconds { get; set; } - [JsonProperty("hasVideoConferencing", NullValueHandling = NullValueHandling.Ignore)] public bool? HasVideoConferencing { get; set; } + [JsonProperty("videoCodecIsZoomRoom", NullValueHandling = NullValueHandling.Ignore)] public bool? VideoCodecIsZoomRoom { get; set; } + [JsonProperty("hasAudioConferencing", NullValueHandling = NullValueHandling.Ignore)] public bool? HasAudioConferencing { get; set; } + [JsonProperty("hasEnvironmentalControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasEnvironmentalControls { get; set; } + [JsonProperty("hasCameraControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasCameraControls { get; set; } + [JsonProperty("hasSetTopBoxControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasSetTopBoxControls { get; set; } + [JsonProperty("hasRoutingControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasRoutingControls { get; set; } - [JsonProperty("touchpanelKeys", NullValueHandling = NullValueHandling.Ignore)] /// /// Gets or sets the TouchpanelKeys /// + [JsonProperty("touchpanelKeys", NullValueHandling = NullValueHandling.Ignore)] public List TouchpanelKeys { get; set; } - [JsonProperty("zoomRoomControllerKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the ZoomRoomControllerKey /// + [JsonProperty("zoomRoomControllerKey", NullValueHandling = NullValueHandling.Ignore)] public string ZoomRoomControllerKey { get; set; } - [JsonProperty("ciscoNavigatorKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the CiscoNavigatorKey /// + [JsonProperty("ciscoNavigatorKey", NullValueHandling = NullValueHandling.Ignore)] public string CiscoNavigatorKey { get; set; } - [JsonProperty("videoCodecKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the VideoCodecKey /// + [JsonProperty("videoCodecKey", NullValueHandling = NullValueHandling.Ignore)] public string VideoCodecKey { get; set; } - [JsonProperty("audioCodecKey", NullValueHandling = NullValueHandling.Ignore)] + + /// /// Gets or sets the AudioCodecKey /// + [JsonProperty("audioCodecKey", NullValueHandling = NullValueHandling.Ignore)] public string AudioCodecKey { get; set; } - [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] + + /// /// Gets or sets the MatrixRoutingKey /// + [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] public string MatrixRoutingKey { get; set; } - [JsonProperty("endpointKeys", NullValueHandling = NullValueHandling.Ignore)] + + /// /// Gets or sets the EndpointKeys /// + [JsonProperty("endpointKeys", NullValueHandling = NullValueHandling.Ignore)] public List EndpointKeys { get; set; } - [JsonProperty("accessoryDeviceKeys", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the AccessoryDeviceKeys /// + [JsonProperty("accessoryDeviceKeys", NullValueHandling = NullValueHandling.Ignore)] public List AccessoryDeviceKeys { get; set; } - [JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the DefaultDisplayKey /// + [JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultDisplayKey { get; set; } + [JsonProperty("destinations", NullValueHandling = NullValueHandling.Ignore)] public Dictionary Destinations { get; set; } - [JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)] + + /// /// Gets or sets the EnvironmentalDevices /// + [JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)] public List EnvironmentalDevices { get; set; } + [JsonProperty("sourceList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary SourceList { get; set; } [JsonProperty("destinationList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary DestinationList { get; set; } - [JsonProperty("audioControlPointList", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the AudioControlPointList /// + [JsonProperty("audioControlPointList", NullValueHandling = NullValueHandling.Ignore)] public AudioControlPointListItem AudioControlPointList { get; set; } [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary CameraList { get; set; } - [JsonProperty("defaultPresentationSourceKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the DefaultPresentationSourceKey /// + [JsonProperty("defaultPresentationSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultPresentationSourceKey { get; set; } - [JsonProperty("helpMessage", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the HelpMessage /// + [JsonProperty("helpMessage", NullValueHandling = NullValueHandling.Ignore)] public string HelpMessage { get; set; } - [JsonProperty("techPassword", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the TechPassword /// + [JsonProperty("techPassword", NullValueHandling = NullValueHandling.Ignore)] public string TechPassword { get; set; } - [JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the UiBehavior /// + [JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)] public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } [JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)] public bool? SupportsAdvancedSharing { get; set; } + [JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)] public bool? UserCanChangeShareMode { get; set; } - [JsonProperty("roomCombinerKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the RoomCombinerKey /// + [JsonProperty("roomCombinerKey", NullValueHandling = NullValueHandling.Ignore)] public string RoomCombinerKey { get; set; } public RoomConfiguration() @@ -994,17 +1031,19 @@ namespace PepperDash.Essentials.RoomBridges /// public class EnvironmentalDeviceConfiguration { - [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the DeviceKey /// + [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Ignore)] public string DeviceKey { get; private set; } - [JsonConverter(typeof(StringEnumConverter))] - [JsonProperty("deviceType", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the DeviceType /// + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("deviceType", NullValueHandling = NullValueHandling.Ignore)] public eEnvironmentalDeviceTypes DeviceType { get; private set; } public EnvironmentalDeviceConfiguration(string key, eEnvironmentalDeviceTypes type) @@ -1031,57 +1070,18 @@ namespace PepperDash.Essentials.RoomBridges /// public class ApiTouchPanelToken { - [JsonProperty("touchPanels", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the TouchPanels /// + [JsonProperty("touchPanels", NullValueHandling = NullValueHandling.Ignore)] public List TouchPanels { get; set; } = new List(); - [JsonProperty("userAppUrl", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the UserAppUrl /// + [JsonProperty("userAppUrl", NullValueHandling = NullValueHandling.Ignore)] public string UserAppUrl { get; set; } = ""; } - -#if SERIES3 - /// - /// Represents a SourceSelectMessageContent - /// - public class SourceSelectMessageContent - { - /// - /// Gets or sets the SourceListItem - /// - public string SourceListItem { get; set; } - /// - /// Gets or sets the SourceListKey - /// - public string SourceListKey { get; set; } - } - - /// - /// Represents a DirectRoute - /// - public class DirectRoute - { - /// - /// Gets or sets the SourceKey - /// - public string SourceKey { get; set; } - /// - /// Gets or sets the DestinationKey - /// - public string DestinationKey { get; set; } - } - - /// - /// - /// - /// - /// - /// Delegate for PressAndHoldAction - /// - public delegate void PressAndHoldAction(bool b); -#endif } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs index a4476cd8..c1743d40 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -17,6 +17,7 @@ using PepperDash.Essentials.Core.DeviceInfo; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.UI; using Feedback = PepperDash.Essentials.Core.Feedback; +using IPAddress = System.Net.IPAddress; namespace PepperDash.Essentials.Touchpanel { @@ -106,11 +107,14 @@ namespace PepperDash.Essentials.Touchpanel /// public DeviceInfo DeviceInfo => new DeviceInfo(); + /// + /// Gets the list of connected IPs for this IpId + /// public ReadOnlyCollection ConnectedIps => Panel.ConnectedIpList; - private System.Net.IPAddress csIpAddress; + private readonly IPAddress csIpAddress; - private System.Net.IPAddress csSubnetMask; + private readonly IPAddress csSubnetMask; /// @@ -190,12 +194,27 @@ namespace PepperDash.Essentials.Touchpanel RegisterForExtenders(); - var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); - var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId); - var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); + try + { + var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); + var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId); + var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); - this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask); - this.csIpAddress = System.Net.IPAddress.Parse(csIpAddress); + this.csSubnetMask = IPAddress.Parse(csSubnetMask); + this.csIpAddress = IPAddress.Parse(csIpAddress); + } + catch (ArgumentException) + { + Debug.LogInformation("This processor does not have a CS LAN", this); + } + catch (InvalidOperationException) + { + Debug.LogInformation("This processor does not have a CS LAN", this); + } + catch (Exception ex) + { + Debug.LogError($"Unexpected exception when checking CS LAN: {ex}", this); + } } /// @@ -226,7 +245,7 @@ namespace PepperDash.Essentials.Touchpanel { x70Panel.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X70 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + this.LogVerbose("X70 App Control Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); UpdateZoomFeedbacks(); @@ -245,7 +264,7 @@ namespace PepperDash.Essentials.Touchpanel x70Panel.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X70 Zoom Room Ap Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + this.LogVerbose("X70 Zoom Room App Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); if (a.Sig.Number == x70Panel.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number) { @@ -263,7 +282,7 @@ namespace PepperDash.Essentials.Touchpanel DeviceInfo.MacAddress = x70Panel.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; DeviceInfo.IpAddress = x70Panel.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress); var handler = DeviceInfoChanged; @@ -293,7 +312,7 @@ namespace PepperDash.Essentials.Touchpanel { x60withZoomApp.ExtenderApplicationControlReservedSigs.DeviceExtenderSigChange += (e, a) => { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X60 App Control Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + this.LogVerbose("X60 App Control Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); if (a.Sig.Number == x60withZoomApp.ExtenderApplicationControlReservedSigs.HideOpenApplicationFeedback.Number) { @@ -302,7 +321,7 @@ namespace PepperDash.Essentials.Touchpanel }; x60withZoomApp.ExtenderZoomRoomAppReservedSigs.DeviceExtenderSigChange += (e, a) => { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"X60 Zoom Room App Device Extender args: {a.Event}:{a.Sig}:{a.Sig.Type}:{a.Sig.BoolValue}:{a.Sig.UShortValue}:{a.Sig.StringValue}"); + this.LogVerbose("X60 Zoom Room App Device Extender args: {event}:{sig}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue); if (a.Sig.Number == x60withZoomApp.ExtenderZoomRoomAppReservedSigs.ZoomRoomIncomingCallFeedback.Number) { @@ -319,7 +338,7 @@ namespace PepperDash.Essentials.Touchpanel DeviceInfo.MacAddress = x60withZoomApp.ExtenderEthernetReservedSigs.MacAddressFeedback.StringValue; DeviceInfo.IpAddress = x60withZoomApp.ExtenderEthernetReservedSigs.IpAddressFeedback.StringValue; - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress); var handler = DeviceInfoChanged; @@ -381,7 +400,7 @@ namespace PepperDash.Essentials.Touchpanel /// The signal event arguments containing the changed signal information. protected override void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, this, $"System Device Extender args: ${args.Event}:${args.Sig}"); + this.LogVerbose("System Device Extender args: {event}:{sig}", args.Event, args.Sig); } /// @@ -436,7 +455,7 @@ namespace PepperDash.Essentials.Touchpanel var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId); - if(csIpAddress == null || csSubnetMask == null || url == null) + if (csIpAddress == null || csSubnetMask == null || url == null) { this.LogWarning("CS IP Address Subnet Mask or url is null, cannot determine correct IP for URL"); return url; @@ -447,7 +466,7 @@ namespace PepperDash.Essentials.Touchpanel var ip = ConnectedIps.Any(ipInfo => { - if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp)) + if (IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp)) { return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask); } @@ -481,7 +500,7 @@ namespace PepperDash.Essentials.Touchpanel if (mcList.Count == 0) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"No Mobile Control controller found"); + this.LogError("No Mobile Control controller found"); return; } @@ -493,7 +512,7 @@ namespace PepperDash.Essentials.Touchpanel if (bridge == null) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"No Mobile Control bridge for {_config.DefaultRoomKey} found "); + this.LogInformation("No Mobile Control bridge for {roomKey} found", _config.DefaultRoomKey); return; } @@ -502,7 +521,7 @@ namespace PepperDash.Essentials.Touchpanel _bridge.UserCodeChanged += UpdateFeedbacks; _bridge.AppUrlChanged += (s, a) => { - this.LogInformation("AppURL changed"); + this.LogInformation("AppURL changed: {appURL}", _bridge.AppUrl); SetAppUrl(_bridge.AppUrl); UpdateFeedbacks(s, a); }; @@ -538,7 +557,7 @@ namespace PepperDash.Essentials.Touchpanel { foreach (var feedback in ZoomFeedbacks) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"Updating {feedback.Key}"); + this.LogDebug("Updating {feedbackKey}", feedback.Key); feedback.FireUpdate(); } } @@ -574,7 +593,7 @@ namespace PepperDash.Essentials.Touchpanel if (Panel is TswX60WithZoomRoomAppReservedSigs) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, this, $"X60 panel does not support zoom app"); + this.LogInformation("X60 panel does not support zoom app"); return; } } @@ -650,7 +669,16 @@ namespace PepperDash.Essentials.Touchpanel handler(this, new DeviceInfoEventArgs(DeviceInfo)); } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, this, $"MAC: {DeviceInfo.MacAddress} IP: {DeviceInfo.IpAddress}"); + this.LogDebug("MAC: {macAddress} IP: {ipAddress}", DeviceInfo.MacAddress, DeviceInfo.IpAddress); + } + + /// + /// Force a reload of the iframe on the panel connected to this IP ID + /// + public void ReloadIframe() + { + this.LogInformation("Pulsing join 1"); + Panel.PulseBool(1, 100); } } @@ -659,6 +687,8 @@ namespace PepperDash.Essentials.Touchpanel /// public class MobileControlTouchpanelControllerFactory : EssentialsPluginDeviceFactory { + private Dictionary> factories; + /// /// Initializes a new instance of the MobileControlTouchpanelControllerFactory class. /// Sets up supported device type names and minimum framework version requirements. @@ -667,6 +697,31 @@ namespace PepperDash.Essentials.Touchpanel { TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" }; MinimumEssentialsFrameworkVersion = "2.0.0"; + + factories = new Dictionary> + { + {"crestronapp", (id, controlSystem, projectName) => { + var app = new CrestronApp(id, Global.ControlSystem); + app.ParameterProjectName.Value = projectName; + return app; + }}, + {"xpanel", (id, controlSystem, projectName) => new XpanelForHtml5(id, controlSystem)}, + {"tsw550", (id, controlSystem, projectName) => new Tsw550(id, controlSystem)}, + {"tsw552", (id, controlSystem, projectName) => new Tsw552(id, controlSystem)}, + {"tsw560", (id, controlSystem, projectName) => new Tsw560(id, controlSystem)}, + {"tsw750", (id, controlSystem, projectName) => new Tsw750(id, controlSystem)}, + {"tsw752", (id, controlSystem, projectName) => new Tsw752(id, controlSystem)}, + {"tsw760", (id, controlSystem, projectName) => new Tsw760(id, controlSystem)}, + {"tsw1050", (id, controlSystem, projectName) => new Tsw1050(id, controlSystem)}, + {"tsw1052", (id, controlSystem, projectName) => new Tsw1052(id, controlSystem)}, + {"tsw1060", (id, controlSystem, projectName) => new Tsw1060(id, controlSystem)}, + {"tsw570", (id, controlSystem, projectName) => new Tsw570(id, controlSystem)}, + {"tsw770", (id, controlSystem, projectName) => new Tsw770(id, controlSystem)}, + {"ts770", (id, controlSystem, projectName) => new Ts770(id, controlSystem)}, + {"tsw1070", (id, controlSystem, projectName) => new Tsw1070(id, controlSystem)}, + {"ts1070", (id, controlSystem, projectName) => new Ts1070(id, controlSystem)}, + {"dge1000", (id, controlSystem, projectName) => new Dge1000(id, controlSystem)} + }; } /// @@ -686,10 +741,10 @@ namespace PepperDash.Essentials.Touchpanel if (panel == null) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Unable to create Touchpanel for type {0}. Touchpanel Controller WILL NOT function correctly", dc.Type); + Debug.LogError("Unable to create Touchpanel for type {type}. Touchpanel Controller WILL NOT function correctly", dc.Type); } - Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Factory Attempting to create new MobileControlTouchpanelController"); + Debug.LogDebug("Factory Attempting to create new MobileControlTouchpanelController"); var panelController = new MobileControlTouchpanelController(dc.Key, dc.Name, panel, props); @@ -699,56 +754,21 @@ namespace PepperDash.Essentials.Touchpanel private BasicTriListWithSmartObject GetPanelForType(string type, uint id, string projectName) { type = type.ToLower().Replace("mc", ""); + try { - if (type == "crestronapp") + if (!factories.TryGetValue(type, out var buildCrestronHardwareDevice)) { - var app = new CrestronApp(id, Global.ControlSystem); - app.ParameterProjectName.Value = projectName; - return app; - } - else if (type == "xpanel") - return new XpanelForHtml5(id, Global.ControlSystem); - else if (type == "tsw550") - return new Tsw550(id, Global.ControlSystem); - else if (type == "tsw552") - return new Tsw552(id, Global.ControlSystem); - else if (type == "tsw560") - return new Tsw560(id, Global.ControlSystem); - else if (type == "tsw750") - return new Tsw750(id, Global.ControlSystem); - else if (type == "tsw752") - return new Tsw752(id, Global.ControlSystem); - else if (type == "tsw760") - return new Tsw760(id, Global.ControlSystem); - else if (type == "tsw1050") - return new Tsw1050(id, Global.ControlSystem); - else if (type == "tsw1052") - return new Tsw1052(id, Global.ControlSystem); - else if (type == "tsw1060") - return new Tsw1060(id, Global.ControlSystem); - else if (type == "tsw570") - return new Tsw570(id, Global.ControlSystem); - else if (type == "tsw770") - return new Tsw770(id, Global.ControlSystem); - else if (type == "ts770") - return new Ts770(id, Global.ControlSystem); - else if (type == "tsw1070") - return new Tsw1070(id, Global.ControlSystem); - else if (type == "ts1070") - return new Ts1070(id, Global.ControlSystem); - else if (type == "dge1000") - return new Dge1000(id, Global.ControlSystem); - else - - { - Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW controller with type '{0}'", type); + Debug.LogError("Cannot create TSW controller with type {type}", type); return null; } + + return buildCrestronHardwareDevice(id, Global.ControlSystem, projectName); } catch (Exception e) { - Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message); + Debug.LogError("Cannot create TSW base class. Panel will not function: {message}", e.Message); + Debug.LogDebug(e, "Stack Trace: "); return null; } } diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs index c99abe31..8156834b 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelProperties.cs @@ -8,28 +8,32 @@ namespace PepperDash.Essentials.Touchpanel /// public class MobileControlTouchpanelProperties : CrestronTouchpanelPropertiesConfig { - [JsonProperty("useDirectServer")] + /// /// Gets or sets the UseDirectServer /// + [JsonProperty("useDirectServer")] public bool UseDirectServer { get; set; } = false; - [JsonProperty("zoomRoomController")] + /// /// Gets or sets the ZoomRoomController /// + [JsonProperty("zoomRoomController")] public bool ZoomRoomController { get; set; } = false; - [JsonProperty("buttonToolbarTimeoutInS")] + /// /// Gets or sets the ButtonToolbarTimoutInS /// + [JsonProperty("buttonToolbarTimeoutInS")] public ushort ButtonToolbarTimoutInS { get; set; } = 0; - [JsonProperty("theme")] + /// /// Gets or sets the Theme /// + [JsonProperty("theme")] public string Theme { get; set; } = "light"; } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs index 133cf0c8..089665d9 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/ThemeMessenger.cs @@ -42,10 +42,11 @@ namespace PepperDash.Essentials.Touchpanel /// public class ThemeUpdateMessage : DeviceStateMessageBase { - [JsonProperty("theme")] + /// /// Gets or sets the Theme /// + [JsonProperty("theme")] public string Theme { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl/UserCodeChanged.cs b/src/PepperDash.Essentials.MobileControl/UserCodeChanged.cs new file mode 100644 index 00000000..ab899167 --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl/UserCodeChanged.cs @@ -0,0 +1,17 @@ +using System; + +namespace PepperDash.Essentials +{ + /// + /// Represents a UserCodeChanged + /// + public class UserCodeChanged + { + public Action UpdateUserCode { get; private set; } + + public UserCodeChanged(Action updateMethod) + { + UpdateUserCode = updateMethod; + } + } +} diff --git a/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs b/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs index 1dd3ff97..ce31f766 100644 --- a/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs +++ b/src/PepperDash.Essentials.MobileControl/UserCodeChangedContent.cs @@ -7,16 +7,18 @@ namespace PepperDash.Essentials /// public class UserCodeChangedContent { - [JsonProperty("userCode")] + /// /// Gets or sets the UserCode /// + [JsonProperty("userCode")] public string UserCode { get; set; } - [JsonProperty("qrChecksum", NullValueHandling = NullValueHandling.Include)] + /// /// Gets or sets the QrChecksum /// + [JsonProperty("qrChecksum", NullValueHandling = NullValueHandling.Include)] public string QrChecksum { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl/Volumes.cs b/src/PepperDash.Essentials.MobileControl/Volumes.cs index 1de5078e..84accd26 100644 --- a/src/PepperDash.Essentials.MobileControl/Volumes.cs +++ b/src/PepperDash.Essentials.MobileControl/Volumes.cs @@ -1,5 +1,5 @@ -using Newtonsoft.Json; -using System.Collections.Generic; +using System.Collections.Generic; +using Newtonsoft.Json; namespace PepperDash.Essentials { @@ -8,10 +8,11 @@ namespace PepperDash.Essentials /// public class Volumes { - [JsonProperty("master", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Master /// + [JsonProperty("master", NullValueHandling = NullValueHandling.Ignore)] public Volume Master { get; set; } [JsonProperty("auxFaders", NullValueHandling = NullValueHandling.Ignore)] @@ -30,10 +31,11 @@ namespace PepperDash.Essentials /// public class Volume { - [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Key /// + [JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)] public string Key { get; set; } [JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)] @@ -42,10 +44,11 @@ namespace PepperDash.Essentials [JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)] public bool? Muted { get; set; } - [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Label /// + [JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)] public string Label { get; set; } [JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)] @@ -58,10 +61,11 @@ namespace PepperDash.Essentials public bool? PrivacyMuted { get; set; } - [JsonProperty("muteIcon", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the MuteIcon /// + [JsonProperty("muteIcon", NullValueHandling = NullValueHandling.Ignore)] public string MuteIcon { get; set; } public Volume(string key, int level, bool muted, string label, bool hasMute, string muteIcon) diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs index 14fa3568..84d0318a 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/ActionPathsHandler.cs @@ -1,8 +1,8 @@ -using Crestron.SimplSharp.WebScripting; +using System.Collections.Generic; +using System.Linq; +using Crestron.SimplSharp.WebScripting; using Newtonsoft.Json; using PepperDash.Core.Web.RequestHandlers; -using System.Collections.Generic; -using System.Linq; namespace PepperDash.Essentials.WebApiHandlers { @@ -51,16 +51,18 @@ namespace PepperDash.Essentials.WebApiHandlers /// public class ActionPath { - [JsonProperty("messengerKey")] + /// /// Gets or sets the MessengerKey /// + [JsonProperty("messengerKey")] public string MessengerKey { get; set; } - [JsonProperty("path")] + /// /// Gets or sets the Path /// + [JsonProperty("path")] public string Path { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs index 6826092b..e45fcc39 100644 --- a/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs +++ b/src/PepperDash.Essentials.MobileControl/WebApiHandlers/UiClientHandler.cs @@ -148,22 +148,25 @@ namespace PepperDash.Essentials.WebApiHandlers /// public class ClientRequest { - [JsonProperty("roomKey", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the RoomKey /// + [JsonProperty("roomKey", NullValueHandling = NullValueHandling.Ignore)] public string RoomKey { get; set; } - [JsonProperty("grantCode", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the GrantCode /// + [JsonProperty("grantCode", NullValueHandling = NullValueHandling.Ignore)] public string GrantCode { get; set; } - [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Token /// + [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] public string Token { get; set; } } @@ -172,22 +175,25 @@ namespace PepperDash.Essentials.WebApiHandlers /// public class ClientResponse { - [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Error /// + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] public string Error { get; set; } - [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Token /// + [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] public string Token { get; set; } - [JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)] + /// /// Gets or sets the Path /// + [JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)] public string Path { get; set; } } } diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/DeviceInterfaceInfo.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/DeviceInterfaceInfo.cs new file mode 100644 index 00000000..09be4399 --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/DeviceInterfaceInfo.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using PepperDash.Core; + + +/// +/// Represents info about a device including supproted interfaces +/// +public class DeviceInterfaceInfo : IKeyName +{ + /// + /// Gets or sets the Key + /// + [JsonProperty("key")] + public string Key { get; set; } + + /// + /// Gets or sets the Name + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Gets or sets the Interfaces + /// + [JsonProperty("interfaces")] + public List Interfaces { get; set; } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinResponse.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinResponse.cs new file mode 100644 index 00000000..ba214db4 --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinResponse.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + + +namespace PepperDash.Essentials.WebSocketServer +{ + /// + /// Represents a JoinResponse + /// + public class JoinResponse + { + + /// + /// Gets or sets the ClientId + /// + [JsonProperty("clientId")] + public string ClientId { get; set; } + + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + [JsonProperty("systemUUid")] + public string SystemUuid { get; set; } + + + /// + /// Gets or sets the RoomUuid + /// + [JsonProperty("roomUUid")] + public string RoomUuid { get; set; } + + + /// + /// Gets or sets the Config + /// + [JsonProperty("config")] + public object Config { get; set; } + + + /// + /// Gets or sets the CodeExpires + /// + [JsonProperty("codeExpires")] + public DateTime CodeExpires { get; set; } + + + /// + /// Gets or sets the UserCode + /// + [JsonProperty("userCode")] + public string UserCode { get; set; } + + + /// + /// Gets or sets the UserAppUrl + /// + [JsonProperty("userAppUrl")] + public string UserAppUrl { get; set; } + + + /// + /// Gets or sets the EnableDebug + /// + [JsonProperty("enableDebug")] + public bool EnableDebug { get; set; } + + /// + /// Gets or sets the DeviceInterfaceSupport + /// + [JsonProperty("deviceInterfaceSupport")] + public Dictionary DeviceInterfaceSupport { get; set; } + } +} diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinToken.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinToken.cs new file mode 100644 index 00000000..b3ea3c7c --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/JoinToken.cs @@ -0,0 +1,24 @@ +namespace PepperDash.Essentials.WebSocketServer +{ + /// + /// Represents a JoinToken + /// + public class JoinToken + { + /// + /// Gets or sets the Code + /// + public string Code { get; set; } + + public string RoomKey { get; set; } + + public string Uuid { get; set; } + + public string TouchpanelKey { get; set; } = ""; + + /// + /// Gets or sets the Token + /// + public string Token { get; set; } = null; + } +} diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs index ba241a04..d15185b0 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs @@ -4,6 +4,8 @@ using System.ComponentModel; using System.IO; using System.Linq; using System.Net.Http; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; @@ -35,6 +37,10 @@ namespace PepperDash.Essentials.WebSocketServer private readonly string appConfigFileName = "_config.local.json"; private readonly string appConfigCsFileName = "_config.cs.json"; + private const string certificateName = "selfCres"; + + private const string certificatePassword = "cres12345"; + /// /// Where the key is the join token and the value is the room key /// @@ -155,7 +161,7 @@ namespace PepperDash.Essentials.WebSocketServer { try { - Debug.LogMessage(LogEventLevel.Information, "Automatically forwarding port {0} to CS LAN", Port); + this.LogInformation("Automatically forwarding port {port} to CS LAN", Port); var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); var csIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId); @@ -164,16 +170,17 @@ namespace PepperDash.Essentials.WebSocketServer if (result != CrestronEthernetHelper.PortForwardingUserPatRetCodes.NoErr) { - Debug.LogMessage(LogEventLevel.Error, "Error adding port forwarding: {0}", result); + this.LogError("Error adding port forwarding: {error}", result); } } catch (ArgumentException) { - Debug.LogMessage(LogEventLevel.Information, "This processor does not have a CS LAN", this); + this.LogInformation("This processor does not have a CS LAN", this); } catch (Exception ex) { - Debug.LogMessage(ex, "Error automatically forwarding port to CS LAN"); + this.LogError("Error automatically forwarding port to CS LAN: {message}", ex.Message); + this.LogDebug(ex, "Stack Trace"); } } @@ -190,7 +197,7 @@ namespace PepperDash.Essentials.WebSocketServer { if (parent.Config.DirectServer.AutomaticallyForwardPortToCSLAN == false) { - Debug.LogMessage(LogEventLevel.Information, "This processor does not have a CS LAN", this); + this.LogInformation("This processor does not have a CS LAN"); } } @@ -259,13 +266,49 @@ namespace PepperDash.Essentials.WebSocketServer _server.OnPost += Server_OnPost; } + if (_parent.Config.DirectServer.Secure) + { + this.LogInformation("Adding SSL Configuration to server"); + _server.SslConfiguration = new ServerSslConfiguration(new X509Certificate2($"\\user\\{certificateName}.pfx", certificatePassword)) + { + ClientCertificateRequired = false, + CheckCertificateRevocation = false, + EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 + }; + } + + _server.Log.Output = (data, message) => + { + switch (data.Level) + { + case LogLevel.Trace: + this.LogVerbose(data.Message); + break; + case LogLevel.Debug: + this.LogDebug(data.Message); + break; + case LogLevel.Info: + this.LogInformation(data.Message); + break; + case LogLevel.Warn: + this.LogWarning(data.Message); + break; + case LogLevel.Error: + this.LogError(data.Message); + break; + case LogLevel.Fatal: + this.LogFatal(data.Message); + break; + } + }; + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; _server.Start(); if (_server.IsListening) { - Debug.LogMessage(LogEventLevel.Information, "Mobile Control WebSocket Server listening on port {port}", this, _server.Port); + this.LogInformation("Mobile Control WebSocket Server listening on port {port}", _server.Port); } CrestronEnvironment.ProgramStatusEventHandler += OnProgramStop; @@ -278,10 +321,17 @@ namespace PepperDash.Essentials.WebSocketServer } catch (Exception ex) { - Debug.LogMessage(ex, "Exception intializing websocket server", this); + this.LogError("Exception initializing direct server: {message}", ex.Message); + this.LogDebug(ex, "Stack Trace"); } } + public void SetWebsocketLogLevel(LogLevel level) + { + CrestronConsole.ConsoleCommandResponse($"Setting direct server debug level to {level}", level.ToString()); + _server.Log.Level = level; + } + private void AddClientsForTouchpanels() { var touchpanels = DeviceManager.AllDevices @@ -347,22 +397,6 @@ namespace PepperDash.Essentials.WebSocketServer string ip = processorIp; - // Moved to the MobileControlTouchpanelController class in the GetUrlWithCorrectIp method - // triggered by the Panel.IpInformationChange event so that we know we have the necessary info - // to make the determination of which IP to use. - //if (touchpanel.Touchpanel is IMobileControlCrestronTouchpanelController crestronTouchpanel && csIpAddress != null) - //{ - // ip = crestronTouchpanel.ConnectedIps.Any(ipInfo => - // { - // if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp)) - // { - // return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask); - // } - // this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress); - // return false; - // }) ? csIpAddress.ToString() : processorIp; - //} - if (_parent.Config.DirectServer.CSLanUiDeviceKeys != null && _parent.Config.DirectServer.CSLanUiDeviceKeys.Any(k => k.Equals(touchpanel.Touchpanel.Key, StringComparison.InvariantCultureIgnoreCase)) && csIpAddress != null) { ip = csIpAddress.ToString(); @@ -477,7 +511,8 @@ namespace PepperDash.Essentials.WebSocketServer } catch (Exception ex) { - this.LogError(ex, "Error getting application configuration"); + this.LogError("Error getting application configuration: {message}", ex.Message); + this.LogDebug(ex, "Stack Trace"); return null; } @@ -513,15 +548,14 @@ namespace PepperDash.Essentials.WebSocketServer { if (token.Value == null) { - Debug.LogMessage(LogEventLevel.Warning, "Token value is null", this); + this.LogWarning("Token value is null"); continue; } - Debug.LogMessage(LogEventLevel.Information, "Adding token: {0} for room: {1}", this, token.Key, token.Value.RoomKey); + this.LogInformation("Adding token: {key} for room: {roomKey}", token.Key, token.Value.RoomKey); if (UiClients == null) { - Debug.LogMessage(LogEventLevel.Warning, "UiClients is null", this); UiClients = new Dictionary(); } @@ -531,7 +565,7 @@ namespace PepperDash.Essentials.WebSocketServer if (UiClients.Count > 0) { - Debug.LogMessage(LogEventLevel.Information, "Restored {uiClientCount} UiClients from secrets data", this, UiClients.Count); + this.LogInformation("Restored {uiClientCount} UiClients from secrets data", UiClients.Count); foreach (var client in UiClients) { @@ -541,36 +575,28 @@ namespace PepperDash.Essentials.WebSocketServer _server.AddWebSocketService(path, () => { - var c = new UiClient(); - Debug.LogMessage(LogEventLevel.Debug, "Constructing UiClient with id: {key}", this, key); + var c = new UiClient($"uiclient-{key}-{roomKey}"); + this.LogDebug("Constructing UiClient with id: {key}", key); c.Controller = _parent; c.RoomKey = roomKey; UiClients[key].SetClient(c); return c; }); - - - //_server.WebSocketServices.AddService(path, (c) => - //{ - // Debug.Console(2, this, "Constructing UiClient with id: {0}", key); - // c.Controller = _parent; - // c.RoomKey = roomKey; - // UiClients[key].SetClient(c); - //}); } } } else { - Debug.LogMessage(LogEventLevel.Warning, "No secret found"); + this.LogWarning("No secret found"); } - Debug.LogMessage(LogEventLevel.Debug, "{uiClientCount} UiClients restored from secrets data", this, UiClients.Count); + this.LogDebug("{uiClientCount} UiClients restored from secrets data", UiClients.Count); } catch (Exception ex) { - Debug.LogMessage(ex, "Exception retrieving secret", this); + this.LogError("Exception retrieving secret: {message}", ex.Message); + this.LogDebug(ex, "Stack Trace"); } } @@ -583,7 +609,7 @@ namespace PepperDash.Essentials.WebSocketServer { if (_secret == null) { - Debug.LogMessage(LogEventLevel.Error, "Secret is null", this); + this.LogError("Secret is null"); _secret = new ServerTokenSecrets(string.Empty); } @@ -601,7 +627,8 @@ namespace PepperDash.Essentials.WebSocketServer } catch (Exception ex) { - Debug.LogMessage(ex, "Exception updating secret", this); + this.LogError("Exception updating secret: {message}", ex.Message); + this.LogDebug(ex, "Stack Trace"); } } @@ -704,18 +731,18 @@ namespace PepperDash.Essentials.WebSocketServer _server.AddWebSocketService(path, () => { - var c = new UiClient(); - Debug.LogMessage(LogEventLevel.Verbose, "Constructing UiClient with id: {0}", this, key); + var c = new UiClient($"uiclient-{key}-{bridge.RoomKey}"); + this.LogVerbose("Constructing UiClient with id: {key}", key); c.Controller = _parent; c.RoomKey = bridge.RoomKey; UiClients[key].SetClient(c); return c; }); - Debug.LogMessage(LogEventLevel.Information, "Added new WebSocket UiClient service at path: {path}", this, path); - Debug.LogMessage(LogEventLevel.Information, "Token: {@token}", this, token); + this.LogInformation("Added new WebSocket UiClient service at path: {path}", path); + this.LogInformation("Token: {@token}", token); - Debug.LogMessage(LogEventLevel.Verbose, "{serviceCount} websocket services present", this, _server.WebSocketServices.Count); + this.LogVerbose("{serviceCount} websocket services present", _server.WebSocketServices.Count); UpdateSecret(); @@ -729,7 +756,7 @@ namespace PepperDash.Essentials.WebSocketServer { if (s == "?" || string.IsNullOrEmpty(s)) { - CrestronConsole.ConsoleCommandResponse(@"Removes all clients from the server. To execute add 'confirm' to command"); + CrestronConsole.ConsoleCommandResponse(@"Remove all clients from the server. To execute add 'confirm' to command"); return; } @@ -883,7 +910,8 @@ namespace PepperDash.Essentials.WebSocketServer } catch (Exception ex) { - Debug.LogMessage(ex, "Caught an exception in the OnGet handler", this); + this.LogError("Exception in OnGet handler: {message}", ex.Message); + this.LogDebug(ex, "Stack Trace"); } } @@ -972,6 +1000,20 @@ namespace PepperDash.Essentials.WebSocketServer res.StatusCode = 200; res.ContentType = "application/json"; + var devices = DeviceManager.GetDevices(); + Dictionary deviceInterfaces = new Dictionary(); + + foreach (var device in devices) + { + var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List(); + deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo + { + Key = device.Key, + Name = device is IKeyName ? (device as IKeyName).Name : "", + Interfaces = interfaces + }); + } + // Construct the response object JoinResponse jRes = new JoinResponse { @@ -985,7 +1027,8 @@ namespace PepperDash.Essentials.WebSocketServer UserAppUrl = string.Format("http://{0}:{1}/mc/app", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), Port), - EnableDebug = false + EnableDebug = false, + DeviceInterfaceSupport = deviceInterfaces }; // Serialize to JSON and convert to Byte[] @@ -1171,7 +1214,7 @@ namespace PepperDash.Essentials.WebSocketServer } else { - this.LogVerbose("File not found: {filePath}", filePath); + this.LogWarning("File not found: {filePath}", filePath); res.StatusCode = (int)HttpStatusCode.NotFound; res.Close(); return; @@ -1241,145 +1284,4 @@ namespace PepperDash.Essentials.WebSocketServer } } } - - /// - /// Represents a Version - /// - public class Version - { - [JsonProperty("serverVersion")] - public string ServerVersion { get; set; } - - [JsonProperty("serverIsRunningOnProcessorHardware")] - public bool ServerIsRunningOnProcessorHardware { get; private set; } - - public Version() - { - ServerIsRunningOnProcessorHardware = true; - } - } - - /// - /// Represents a UiClientContext - /// - public class UiClientContext - { - /// - /// Gets or sets the Client - /// - public UiClient Client { get; private set; } - /// - /// Gets or sets the Token - /// - public JoinToken Token { get; private set; } - - public UiClientContext(JoinToken token) - { - Token = token; - } - - /// - /// SetClient method - /// - public void SetClient(UiClient client) - { - Client = client; - } - - } - - /// - /// Represents a ServerTokenSecrets - /// - public class ServerTokenSecrets - { - /// - /// Gets or sets the GrantCode - /// - public string GrantCode { get; set; } - - public Dictionary Tokens { get; set; } - - public ServerTokenSecrets(string grantCode) - { - GrantCode = grantCode; - Tokens = new Dictionary(); - } - } - - /// - /// Represents a JoinToken - /// - public class JoinToken - { - /// - /// Gets or sets the Code - /// - public string Code { get; set; } - - public string RoomKey { get; set; } - - public string Uuid { get; set; } - - public string TouchpanelKey { get; set; } = ""; - - /// - /// Gets or sets the Token - /// - public string Token { get; set; } = null; - } - - /// - /// Represents a JoinResponse - /// - public class JoinResponse - { - [JsonProperty("clientId")] - /// - /// Gets or sets the ClientId - /// - public string ClientId { get; set; } - - [JsonProperty("roomKey")] - public string RoomKey { get; set; } - - [JsonProperty("systemUUid")] - public string SystemUuid { get; set; } - - [JsonProperty("roomUUid")] - /// - /// Gets or sets the RoomUuid - /// - public string RoomUuid { get; set; } - - [JsonProperty("config")] - /// - /// Gets or sets the Config - /// - public object Config { get; set; } - - [JsonProperty("codeExpires")] - /// - /// Gets or sets the CodeExpires - /// - public DateTime CodeExpires { get; set; } - - [JsonProperty("userCode")] - /// - /// Gets or sets the UserCode - /// - public string UserCode { get; set; } - - [JsonProperty("userAppUrl")] - /// - /// Gets or sets the UserAppUrl - /// - public string UserAppUrl { get; set; } - - [JsonProperty("enableDebug")] - /// - /// Gets or sets the EnableDebug - /// - public bool EnableDebug { get; set; } - } } diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/ServerTokenSecrets.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/ServerTokenSecrets.cs new file mode 100644 index 00000000..3fa2fb0c --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/ServerTokenSecrets.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + + +namespace PepperDash.Essentials.WebSocketServer +{ + /// + /// Represents a ServerTokenSecrets + /// + public class ServerTokenSecrets + { + /// + /// Gets or sets the GrantCode + /// + public string GrantCode { get; set; } + + public Dictionary Tokens { get; set; } + + public ServerTokenSecrets(string grantCode) + { + GrantCode = grantCode; + Tokens = new Dictionary(); + } + } +} diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs index eb1cf7a1..3cdd183b 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClient.cs @@ -1,31 +1,50 @@ -using Newtonsoft.Json; +using System; +using System.Text.RegularExpressions; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; +using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.RoomBridges; using Serilog.Events; -using System; -using System.Text.RegularExpressions; using WebSocketSharp; using WebSocketSharp.Server; using ErrorEventArgs = WebSocketSharp.ErrorEventArgs; namespace PepperDash.Essentials.WebSocketServer -{ +{ /// /// Represents the behaviour to associate with a UiClient for WebSocket communication /// - public class UiClient : WebSocketBehavior + public class UiClient : WebSocketBehavior, IKeyed { + /// + public string Key { get; private set; } + + /// + /// Gets or sets the mobile control system controller that handles this client's messages + /// public MobileControlSystemController Controller { get; set; } + /// + /// Gets or sets the room key that this client is associated with + /// public string RoomKey { get; set; } + /// + /// The unique identifier for this client instance + /// private string _clientId; + /// + /// The timestamp when this client connection was established + /// private DateTime _connectionTime; + /// + /// Gets the duration that this client has been connected. Returns zero if not currently connected. + /// public TimeSpan ConnectedDuration { get @@ -41,17 +60,22 @@ namespace PepperDash.Essentials.WebSocketServer } } - public UiClient() + /// + /// Initializes a new instance of the UiClient class with the specified key + /// + /// The unique key to identify this client + public UiClient(string key) { - + Key = key; } + /// protected override void OnOpen() { base.OnOpen(); var url = Context.WebSocket.Url; - Debug.LogMessage(LogEventLevel.Verbose, "New WebSocket Connection from: {0}", null, url); + this.LogInformation("New WebSocket Connection from: {url}", url); var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)"); @@ -94,11 +118,21 @@ namespace PepperDash.Essentials.WebSocketServer // TODO: Future: Check token to see if there's already an open session using that token and reject/close the session } + /// + /// Handles the UserCodeChanged event from a room bridge and sends the updated user code to the client + /// + /// The room bridge that raised the event + /// Event arguments private void Bridge_UserCodeChanged(object sender, EventArgs e) { SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, _clientId); } + /// + /// Sends the current user code and QR code URL to the specified client + /// + /// The room bridge containing the user code information + /// The ID of the client to send the information to private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId) { var content = new @@ -117,6 +151,7 @@ namespace PepperDash.Essentials.WebSocketServer Controller.SendMessageObjectToDirectClient(message); } + /// protected override void OnMessage(MessageEventArgs e) { base.OnMessage(e); @@ -128,18 +163,31 @@ namespace PepperDash.Essentials.WebSocketServer } } + /// protected override void OnClose(CloseEventArgs e) { base.OnClose(e); - Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Closing: {0} reason: {1}", null, e.Code, e.Reason); + this.LogInformation("WebSocket UiClient Closing: {code} reason: {reason}", e.Code, e.Reason); + + foreach (var messenger in Controller.Messengers) + { + messenger.Value.UnsubscribeClient(_clientId); + } + + foreach (var messenger in Controller.DefaultMessengers) + { + messenger.Value.UnsubscribeClient(_clientId); + } } + /// protected override void OnError(ErrorEventArgs e) { base.OnError(e); - Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Error: {exception} message: {message}", e.Exception, e.Message); + this.LogError("WebSocket UiClient Error: {message}", e.Message); + this.LogDebug(e.Exception, "Stack Trace"); } } } diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClientContext.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClientContext.cs new file mode 100644 index 00000000..6782306f --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/UiClientContext.cs @@ -0,0 +1,31 @@ +namespace PepperDash.Essentials.WebSocketServer +{ + /// + /// Represents a UiClientContext + /// + public class UiClientContext + { + /// + /// Gets or sets the Client + /// + public UiClient Client { get; private set; } + /// + /// Gets or sets the Token + /// + public JoinToken Token { get; private set; } + + public UiClientContext(JoinToken token) + { + Token = token; + } + + /// + /// SetClient method + /// + public void SetClient(UiClient client) + { + Client = client; + } + + } +} diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/Version.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/Version.cs new file mode 100644 index 00000000..5552e29b --- /dev/null +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/Version.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; + + +namespace PepperDash.Essentials.WebSocketServer +{ + /// + /// Represents a Version + /// + public class Version + { + [JsonProperty("serverVersion")] + public string ServerVersion { get; set; } + + [JsonProperty("serverIsRunningOnProcessorHardware")] + public bool ServerIsRunningOnProcessorHardware { get; private set; } + + public Version() + { + ServerIsRunningOnProcessorHardware = true; + } + } +} diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs index b2fe1e19..28864e83 100644 --- a/src/PepperDash.Essentials/ControlSystem.cs +++ b/src/PepperDash.Essentials/ControlSystem.cs @@ -39,8 +39,6 @@ namespace PepperDash.Essentials DeviceManager.Initialize(this); SecretsManager.Initialize(); SystemMonitor.ProgramInitialization.ProgramInitializationUnderUserControl = true; - - Debug.SetErrorLogMinimumDebugLevel(CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? LogEventLevel.Warning : LogEventLevel.Verbose); } /// @@ -75,8 +73,6 @@ namespace PepperDash.Essentials private void StartSystem(object preventInitialization) { - Debug.SetErrorLogMinimumDebugLevel(LogEventLevel.Verbose); - DeterminePlatform(); if (Debug.DoNotLoadConfigOnNextBoot)