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.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.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..7650b430 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/CameraBaseMessenger.cs @@ -55,7 +55,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,7 +175,7 @@ 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(); @@ -188,7 +190,7 @@ namespace PepperDash.Essentials.AppServer.Messengers cameraMode = GetCameraMode(), hasPresets = Camera is IHasCameraPresets, presets = presetList - }) + }), id ); } 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 3a04c77d..fba7c643 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/DeviceVolumeMessenger.cs @@ -62,7 +62,7 @@ namespace PepperDash.Essentials.AppServer.Messengers #region Overrides of MessengerBase - + /// protected override void RegisterActions() { AddAction("/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => 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..7099e52c 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs +++ b/src/PepperDash.Essentials.MobileControl.Messengers/Messengers/IHasCamerasMessenger.cs @@ -1,11 +1,11 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using PepperDash.Essentials.Devices.Common.Cameras; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Essentials.Devices.Common.Cameras; namespace PepperDash.Essentials.AppServer.Messengers { @@ -26,7 +26,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 +49,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/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..36d73a3e 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,7 +11,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// Represents a ISelectableItemsMessenger /// public class ISelectableItemsMessenger : MessengerBase - { + { private readonly ISelectableItems itemDevice; private readonly string _propName; @@ -34,9 +34,10 @@ namespace PepperDash.Essentials.AppServer.Messengers base.RegisterActions(); AddAction("/fullStatus", (id, context) => - { - SendFullStatus(); - }); + SendFullStatus(id) + ); + + AddAction("/itemsStatus", (id, content) => SendFullStatus(id)); itemDevice.ItemsUpdated += (sender, args) => { @@ -65,7 +66,7 @@ namespace PepperDash.Essentials.AppServer.Messengers } } - private void SendFullStatus() + private void SendFullStatus(string id = null) { try { @@ -77,7 +78,7 @@ namespace PepperDash.Essentials.AppServer.Messengers CurrentItem = itemDevice.CurrentItem }; - PostStatusMessage(stateObject); + PostStatusMessage(stateObject, id); } catch (Exception e) { @@ -91,13 +92,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 83254e76..0579c1f6 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; @@ -1199,8 +1212,7 @@ namespace PepperDash.Essentials if (_initialized) { - this.LogDebug("Registering messenger {messengerKey} AFTER initialization", messenger.Key); - messenger.RegisterWithAppServer(this); + RegisterMessengerWithServer(messenger); } } @@ -1241,6 +1253,12 @@ namespace PepperDash.Essentials messenger.MessagePath ); + if (messenger is IMobileControlMessengerWithSubscriptions subMessenger) + { + subMessenger.RegisterWithAppServer(this, Config.EnableMessengerSubscriptions); + return; + } + messenger.RegisterWithAppServer(this); } @@ -1335,11 +1353,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 +1420,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 +1452,8 @@ namespace PepperDash.Essentials _wsClient2.Log.Level = _wsLogLevel; } + _directServer?.SetWebsocketLogLevel(_wsLogLevel); + CrestronConsole.ConsoleCommandResponse($"Websocket log level set to {debugLevel}"); } catch @@ -1484,7 +1523,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 +2233,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 +2472,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 540063c5..c1743d40 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -16,8 +16,8 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceInfo; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.UI; -using Serilog.Events; using Feedback = PepperDash.Essentials.Core.Feedback; +using IPAddress = System.Net.IPAddress; namespace PepperDash.Essentials.Touchpanel { @@ -107,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; /// @@ -197,8 +200,8 @@ namespace PepperDash.Essentials.Touchpanel 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) { @@ -242,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(); @@ -261,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) { @@ -279,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; @@ -309,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) { @@ -318,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) { @@ -335,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; @@ -397,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); } /// @@ -452,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; @@ -463,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); } @@ -497,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; } @@ -509,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; } @@ -554,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(); } } @@ -590,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; } } @@ -666,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); } } @@ -675,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. @@ -683,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)} + }; } /// @@ -702,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); @@ -715,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; + } + } +}