From c0b59c375e99be02fe0f1fbfd109457eedd1c0be Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 15 Nov 2019 22:03:45 -0700 Subject: [PATCH] Removed all references to "Cotija" and replaced with "MobileControl". Progress on multi display routing in room logic and Mobile Control bridging. --- .../IChannelExtensions.cs | 6 +- .../DeviceTypeInterfaces/IColorExtensions.cs | 6 +- .../DeviceTypeInterfaces/IDPadExtensions.cs | 6 +- .../DeviceTypeInterfaces/IDvrExtensions.cs | 6 +- .../INumericExtensions.cs | 6 +- .../DeviceTypeInterfaces/IPowerExtensions.cs | 6 +- .../ISetTopBoxControlsExtensions.cs | 6 +- .../ITransportExtensions.cs | 6 +- PepperDashEssentials/AppServer/Interfaces.cs | 2 +- .../Messengers/AudioCodecBaseMessenger.cs | 2 +- .../AppServer/Messengers/ConfigMessenger.cs | 2 +- .../Messengers/Ddvc01AtcMessenger.cs | 2 +- .../Messengers/Ddvc01VtcMessenger.cs | 2 +- .../AppServer/Messengers/MessengerBase.cs | 6 +- .../Messengers/SystemMonitorMessenger.cs | 2 +- .../Messengers/VideoCodecBaseMessenger.cs | 2 +- ...CotijaConfig.cs => MobileControlConfig.cs} | 4 +- ....cs => MobileControlDdvc01DeviceBridge.cs} | 6 +- ...er.cs => MobileControlSystemController.cs} | 1726 ++++++++--------- ...idgeBase.cs => MobileControlBridgeBase.cs} | 8 +- ...ge.cs => MobileControlDdvc01RoomBridge.cs} | 12 +- ...ControlEssentialsHuddleSpaceRoomBridge.cs} | 60 +- .../RoomBridges/SourceDeviceMapDictionary.cs | 2 +- PepperDashEssentials/AppServer/Volumes.cs | 2 +- PepperDashEssentials/ControlSystem.cs | 125 +- PepperDashEssentials/Factory/DeviceFactory.cs | 8 +- .../PepperDashEssentials.csproj | 12 +- .../Room/Config/EssentialsRoomConfig.cs | 6 + .../Room/Types/EssentialsDualDisplayRoom.cs | 10 +- .../Room/Types/EssentialsNDisplayRoomBase.cs | 8 +- .../Config/Essentials/EssentialsConfig.cs | 2 - .../Room/Interfaces.cs | 10 +- .../Routing/RoutingInterfaces.cs | 1 - .../Routing/RoutingPort.cs | 8 +- essentials-framework/pepperdashcore-builds | 2 +- 35 files changed, 1027 insertions(+), 1053 deletions(-) rename PepperDashEssentials/AppServer/{CotijaConfig.cs => MobileControlConfig.cs} (84%) rename PepperDashEssentials/AppServer/{CotijaDdvc01DeviceBridge.cs => MobileControlDdvc01DeviceBridge.cs} (91%) rename PepperDashEssentials/AppServer/{CotijaSystemController.cs => MobileControlSystemController.cs} (95%) rename PepperDashEssentials/AppServer/RoomBridges/{CotijaBridgeBase.cs => MobileControlBridgeBase.cs} (81%) rename PepperDashEssentials/AppServer/RoomBridges/{CotijaDdvc01RoomBridge.cs => MobileControlDdvc01RoomBridge.cs} (98%) rename PepperDashEssentials/AppServer/RoomBridges/{CotijaEssentialsHuddleSpaceRoomBridge.cs => MobileControlEssentialsHuddleSpaceRoomBridge.cs} (87%) diff --git a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IChannelExtensions.cs b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IChannelExtensions.cs index dd23d85a..287a9ba1 100644 --- a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IChannelExtensions.cs +++ b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IChannelExtensions.cs @@ -6,11 +6,11 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public static class IChannelExtensions { - public static void LinkActions(this IChannel dev, CotijaSystemController controller) + public static void LinkActions(this IChannel dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); @@ -22,7 +22,7 @@ namespace PepperDash.Essentials.Room.Cotija controller.AddAction(prefix + "exit", new PressAndHoldAction(dev.Exit)); } - public static void UnlinkActions(this IChannel dev, CotijaSystemController controller) + public static void UnlinkActions(this IChannel dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); diff --git a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IColorExtensions.cs b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IColorExtensions.cs index 21296550..9912433d 100644 --- a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IColorExtensions.cs +++ b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IColorExtensions.cs @@ -6,11 +6,11 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public static class IColorExtensions { - public static void LinkActions(this IColor dev, CotijaSystemController controller) + public static void LinkActions(this IColor dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); @@ -20,7 +20,7 @@ namespace PepperDash.Essentials.Room.Cotija controller.AddAction(prefix + "blue", new PressAndHoldAction(dev.Blue)); } - public static void UnlinkActions(this IColor dev, CotijaSystemController controller) + public static void UnlinkActions(this IColor dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); diff --git a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IDPadExtensions.cs b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IDPadExtensions.cs index 3652ba68..b094dfe8 100644 --- a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IDPadExtensions.cs +++ b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IDPadExtensions.cs @@ -6,11 +6,11 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public static class IDPadExtensions { - public static void LinkActions(this IDPad dev, CotijaSystemController controller) + public static void LinkActions(this IDPad dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); @@ -23,7 +23,7 @@ namespace PepperDash.Essentials.Room.Cotija controller.AddAction(prefix + "exit", new PressAndHoldAction(dev.Exit)); } - public static void UnlinkActions(this IDPad dev, CotijaSystemController controller) + public static void UnlinkActions(this IDPad dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); diff --git a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IDvrExtensions.cs b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IDvrExtensions.cs index 99aa1103..d4a9570b 100644 --- a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IDvrExtensions.cs +++ b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IDvrExtensions.cs @@ -6,11 +6,11 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public static class IDvrExtensions { - public static void LinkActions(this IDvr dev, CotijaSystemController controller) + public static void LinkActions(this IDvr dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); @@ -18,7 +18,7 @@ namespace PepperDash.Essentials.Room.Cotija controller.AddAction(prefix + "record", new PressAndHoldAction(dev.Record)); } - public static void UnlinkActions(this IDvr dev, CotijaSystemController controller) + public static void UnlinkActions(this IDvr dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); diff --git a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/INumericExtensions.cs b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/INumericExtensions.cs index 376ed57b..2b61d775 100644 --- a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/INumericExtensions.cs +++ b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/INumericExtensions.cs @@ -6,11 +6,11 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public static class INumericExtensions { - public static void LinkActions(this INumericKeypad dev, CotijaSystemController controller) + public static void LinkActions(this INumericKeypad dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); @@ -29,7 +29,7 @@ namespace PepperDash.Essentials.Room.Cotija // Deal with the Accessory functions on the numpad later } - public static void UnlinkActions(this INumericKeypad dev, CotijaSystemController controller) + public static void UnlinkActions(this INumericKeypad dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); diff --git a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IPowerExtensions.cs b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IPowerExtensions.cs index 732d2740..515c2c7f 100644 --- a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IPowerExtensions.cs +++ b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/IPowerExtensions.cs @@ -6,11 +6,11 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public static class IPowerExtensions { - public static void LinkActions(this IPower dev, CotijaSystemController controller) + public static void LinkActions(this IPower dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Room.Cotija controller.AddAction(prefix + "powerToggle", new Action(dev.PowerToggle)); } - public static void UnlinkActions(this IPower dev, CotijaSystemController controller) + public static void UnlinkActions(this IPower dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); diff --git a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/ISetTopBoxControlsExtensions.cs b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/ISetTopBoxControlsExtensions.cs index 99198fa6..2ea60545 100644 --- a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/ISetTopBoxControlsExtensions.cs +++ b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/ISetTopBoxControlsExtensions.cs @@ -6,11 +6,11 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public static class ISetTopBoxControlsExtensions { - public static void LinkActions(this ISetTopBoxControls dev, CotijaSystemController controller) + public static void LinkActions(this ISetTopBoxControls dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); @@ -18,7 +18,7 @@ namespace PepperDash.Essentials.Room.Cotija controller.AddAction(prefix + "replay", new PressAndHoldAction(dev.Replay)); } - public static void UnlinkActions(this ISetTopBoxControls dev, CotijaSystemController controller) + public static void UnlinkActions(this ISetTopBoxControls dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); diff --git a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/ITransportExtensions.cs b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/ITransportExtensions.cs index 9463d95f..f34fb9e3 100644 --- a/PepperDashEssentials/AppServer/DeviceTypeInterfaces/ITransportExtensions.cs +++ b/PepperDashEssentials/AppServer/DeviceTypeInterfaces/ITransportExtensions.cs @@ -6,11 +6,11 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; using PepperDash.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public static class ITransportExtensions { - public static void LinkActions(this ITransport dev, CotijaSystemController controller) + public static void LinkActions(this ITransport dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); @@ -24,7 +24,7 @@ namespace PepperDash.Essentials.Room.Cotija controller.AddAction(prefix + "record", new PressAndHoldAction(dev.Record)); } - public static void UnlinkActions(this ITransport dev, CotijaSystemController controller) + public static void UnlinkActions(this ITransport dev, MobileControlSystemController controller) { var prefix = string.Format(@"/device/{0}/", (dev as IKeyed).Key); diff --git a/PepperDashEssentials/AppServer/Interfaces.cs b/PepperDashEssentials/AppServer/Interfaces.cs index 4372ef8a..8a1c20c8 100644 --- a/PepperDashEssentials/AppServer/Interfaces.cs +++ b/PepperDashEssentials/AppServer/Interfaces.cs @@ -6,7 +6,7 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a room whose configuration is derived from runtime data, diff --git a/PepperDashEssentials/AppServer/Messengers/AudioCodecBaseMessenger.cs b/PepperDashEssentials/AppServer/Messengers/AudioCodecBaseMessenger.cs index b37b80da..3d74b132 100644 --- a/PepperDashEssentials/AppServer/Messengers/AudioCodecBaseMessenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/AudioCodecBaseMessenger.cs @@ -39,7 +39,7 @@ namespace PepperDash.Essentials.AppServer.Messengers } - protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) { appServerController.AddAction(MessagePath + "/fullStatus", new Action(SendAtcFullMessageObject)); appServerController.AddAction(MessagePath + "/dial", new Action(s => Codec.Dial(s))); diff --git a/PepperDashEssentials/AppServer/Messengers/ConfigMessenger.cs b/PepperDashEssentials/AppServer/Messengers/ConfigMessenger.cs index 1e3cfa12..ae05c118 100644 --- a/PepperDashEssentials/AppServer/Messengers/ConfigMessenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/ConfigMessenger.cs @@ -27,7 +27,7 @@ namespace PepperDash.Essentials.AppServer.Messengers PostUpdateStatus(e.UpdateStatus.ToString()); } - protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) { appServerController.AddAction(MessagePath + "/updateConfig", new Action(s => GetConfigFile(s))); } diff --git a/PepperDashEssentials/AppServer/Messengers/Ddvc01AtcMessenger.cs b/PepperDashEssentials/AppServer/Messengers/Ddvc01AtcMessenger.cs index 72e2f8d3..eee94350 100644 --- a/PepperDashEssentials/AppServer/Messengers/Ddvc01AtcMessenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/Ddvc01AtcMessenger.cs @@ -127,7 +127,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// /// - protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) { //EISC.SetStringSigAction(SCurrentDialString, s => PostStatusMessage(new { currentDialString = s })); diff --git a/PepperDashEssentials/AppServer/Messengers/Ddvc01VtcMessenger.cs b/PepperDashEssentials/AppServer/Messengers/Ddvc01VtcMessenger.cs index 7fb53f96..e3de11d0 100644 --- a/PepperDashEssentials/AppServer/Messengers/Ddvc01VtcMessenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/Ddvc01VtcMessenger.cs @@ -253,7 +253,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// /// - protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) { var asc = appServerController; EISC.SetStringSigAction(SHookState, s => diff --git a/PepperDashEssentials/AppServer/Messengers/MessengerBase.cs b/PepperDashEssentials/AppServer/Messengers/MessengerBase.cs index f9833afb..d4967eee 100644 --- a/PepperDashEssentials/AppServer/Messengers/MessengerBase.cs +++ b/PepperDashEssentials/AppServer/Messengers/MessengerBase.cs @@ -24,7 +24,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// /// - public CotijaSystemController AppServerController { get; private set; } + public MobileControlSystemController AppServerController { get; private set; } public string MessagePath { get; private set; } @@ -47,7 +47,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// Registers this messenger with appserver controller /// /// - public void RegisterWithAppServer(CotijaSystemController appServerController) + public void RegisterWithAppServer(MobileControlSystemController appServerController) { if (appServerController == null) throw new ArgumentNullException("appServerController"); @@ -60,7 +60,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// Implemented in extending classes. Wire up API calls and feedback here /// /// - abstract protected void CustomRegisterWithAppServer(CotijaSystemController appServerController); + abstract protected void CustomRegisterWithAppServer(MobileControlSystemController appServerController); /// /// Helper for posting status message diff --git a/PepperDashEssentials/AppServer/Messengers/SystemMonitorMessenger.cs b/PepperDashEssentials/AppServer/Messengers/SystemMonitorMessenger.cs index 12107ff5..080fbd78 100644 --- a/PepperDashEssentials/AppServer/Messengers/SystemMonitorMessenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/SystemMonitorMessenger.cs @@ -86,7 +86,7 @@ namespace PepperDash.Essentials.AppServer.Messengers }); } - protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) { AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatusMessage)); } diff --git a/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs b/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs index 5c1c59b7..29c80085 100644 --- a/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs @@ -160,7 +160,7 @@ namespace PepperDash.Essentials.AppServer.Messengers /// Called from base's RegisterWithAppServer method /// /// - protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) + protected override void CustomRegisterWithAppServer(MobileControlSystemController appServerController) { appServerController.AddAction("/device/videoCodec/isReady", new Action(SendIsReady)); appServerController.AddAction("/device/videoCodec/fullStatus", new Action(SendVtcFullMessageObject)); diff --git a/PepperDashEssentials/AppServer/CotijaConfig.cs b/PepperDashEssentials/AppServer/MobileControlConfig.cs similarity index 84% rename from PepperDashEssentials/AppServer/CotijaConfig.cs rename to PepperDashEssentials/AppServer/MobileControlConfig.cs index 22196956..6b775a0a 100644 --- a/PepperDashEssentials/AppServer/CotijaConfig.cs +++ b/PepperDashEssentials/AppServer/MobileControlConfig.cs @@ -13,7 +13,7 @@ namespace PepperDash.Essentials /// /// /// - public class CotijaConfig + public class MobileControlConfig { [JsonProperty("serverUrl")] public string ServerUrl { get; set; } @@ -25,7 +25,7 @@ namespace PepperDash.Essentials /// /// /// - public class CotijaDdvc01RoomBridgePropertiesConfig + public class MobileControlDdvc01RoomBridgePropertiesConfig { [JsonProperty("eiscId")] public string EiscId { get; set; } diff --git a/PepperDashEssentials/AppServer/CotijaDdvc01DeviceBridge.cs b/PepperDashEssentials/AppServer/MobileControlDdvc01DeviceBridge.cs similarity index 91% rename from PepperDashEssentials/AppServer/CotijaDdvc01DeviceBridge.cs rename to PepperDashEssentials/AppServer/MobileControlDdvc01DeviceBridge.cs index 51c0bb5b..49a75263 100644 --- a/PepperDashEssentials/AppServer/CotijaDdvc01DeviceBridge.cs +++ b/PepperDashEssentials/AppServer/MobileControlDdvc01DeviceBridge.cs @@ -8,19 +8,19 @@ using Crestron.SimplSharpPro.EthernetCommunication; using PepperDash.Core; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { /// /// Represents a generic device connection through to and EISC for DDVC01 /// - public class CotijaDdvc01DeviceBridge : Device, IChannel, INumericKeypad + public class MobileControlDdvc01DeviceBridge : Device, IChannel, INumericKeypad { /// /// EISC used to talk to Simpl /// ThreeSeriesTcpIpEthernetIntersystemCommunications EISC; - public CotijaDdvc01DeviceBridge(string key, string name, ThreeSeriesTcpIpEthernetIntersystemCommunications eisc) + public MobileControlDdvc01DeviceBridge(string key, string name, ThreeSeriesTcpIpEthernetIntersystemCommunications eisc) : base(key, name) { EISC = eisc; diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/MobileControlSystemController.cs similarity index 95% rename from PepperDashEssentials/AppServer/CotijaSystemController.cs rename to PepperDashEssentials/AppServer/MobileControlSystemController.cs index 1e74efe0..08afb464 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/MobileControlSystemController.cs @@ -1,864 +1,864 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Crestron.SimplSharp; -using Crestron.SimplSharp.CrestronIO; -using Crestron.SimplSharp.Reflection; -using Crestron.SimplSharpPro.CrestronThread; -using Crestron.SimplSharp.CrestronWebSocketClient; -using Crestron.SimplSharpPro; -using Crestron.SimplSharp.Net.Http; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Room.Cotija; -using PepperDash.Essentials.AppServer.Messengers; - -namespace PepperDash.Essentials -{ - public class CotijaSystemController : Device - { - WebSocketClient WSClient; - - //bool LinkUp; - - /// - /// Prevents post operations from stomping on each other and getting lost - /// - CEvent PostLockEvent = new CEvent(true, true); - - CEvent RegisterLockEvent = new CEvent(true, true); - - public CotijaConfig Config { get; private set; } - - Dictionary ActionDictionary = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - - Dictionary PushedActions = new Dictionary(); - - public ConfigMessenger ConfigMessenger { get; private set; } - - CTimer ServerHeartbeatCheckTimer; - - long ServerHeartbeatInterval = 20000; - - CTimer ServerReconnectTimer; - - long ServerReconnectInterval = 5000; - - DateTime LastAckMessage; - - public string SystemUuid; - - List RoomBridges = new List(); - - long ButtonHeartbeatInterval = 1000; - - /// - /// Used for tracking HTTP debugging - /// - bool HttpDebugEnabled; - - /// - /// - /// - /// - /// - /// - public CotijaSystemController(string key, string name, CotijaConfig config) : base(key, name) - { - Config = config; - - SystemUuid = ConfigReader.ConfigObject.SystemUuid; - - Debug.Console(0, this, "Mobile UI controller initializing for server:{0}", config.ServerUrl); - - CrestronConsole.AddNewConsoleCommand(AuthorizeSystem, - "mobileauth", "Authorizes system to talk to cotija server", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(s => ShowInfo(), - "mobileinfo", "Shows information for current mobile control session", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(s => { - s = s.Trim(); - if(!string.IsNullOrEmpty(s)) - { - HttpDebugEnabled = (s.Trim() != "0"); - } - CrestronConsole.ConsoleCommandResponse("HTTP Debug {0}", HttpDebugEnabled ? "Enabled" : "Disabled"); - }, - "mobilehttpdebug", "1 enables more verbose HTTP response debugging", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(TestHttpRequest, - "mobilehttprequest", "Tests an HTTP get to URL given", ConsoleAccessLevelEnum.AccessOperator); - - CrestronConsole.AddNewConsoleCommand(PrintActionDictionaryPaths, "mobileshowactionpaths", - "Prints the paths in the Action Dictionary", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(s => ConnectWebsocketClient(), "mobileconnect", - "Forces connect of websocket", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(s => CleanUpWebsocketClient(), "mobiledisco", - "Disconnects websocket", ConsoleAccessLevelEnum.AccessOperator); - - CrestronConsole.AddNewConsoleCommand(s => ParseStreamRx(s), "mobilesimulateaction", "Simulates a message from the server", ConsoleAccessLevelEnum.AccessOperator); - - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); - - // Config Messenger - var cmKey = Key + "-config"; - ConfigMessenger = new ConfigMessenger(cmKey, "/config"); - ConfigMessenger.RegisterWithAppServer(this); - } - - /// - /// If config rooms is empty or null then go - /// - /// - public override bool CustomActivate() - { - if (ConfigReader.ConfigObject.Rooms == null || ConfigReader.ConfigObject.Rooms.Count == 0) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Config contains no rooms. Registering with Server."); - RegisterSystemToServer(); - } - - return base.CustomActivate(); - } - - /// - /// - /// - /// - void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs args) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Ethernet status change, port {0}: {1}", - args.EthernetAdapter, args.EthernetEventType); - - if (args.EthernetEventType == eEthernetEventType.LinkDown && WSClient != null && args.EthernetAdapter == WSClient.EthernetAdapter) - { - CleanUpWebsocketClient(); - } - } - - /// - /// Sends message to server to indicate the system is shutting down - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) - { - if (programEventType == eProgramStatusEventType.Stopping - && WSClient != null - && WSClient.Connected) - { - CleanUpWebsocketClient(); - } - } - - public void PrintActionDictionaryPaths(object o) - { - Debug.Console(0, this, "ActionDictionary Contents:"); - - foreach (var item in ActionDictionary) - { - Debug.Console(0, this, "{0}", item.Key); - } - } - - /// - /// Adds an action to the dictionary - /// - /// The path of the API command - /// The action to be triggered by the commmand - public void AddAction(string key, object action) - { - if (!ActionDictionary.ContainsKey(key)) - { - ActionDictionary.Add(key, action); - } - else - { - Debug.Console(1, this, "Cannot add action with key '{0}' because key already exists in ActionDictionary.", key); - } - } - - /// - /// Removes an action from the dictionary - /// - /// - public void RemoveAction(string key) - { - if (ActionDictionary.ContainsKey(key)) - ActionDictionary.Remove(key); - } - - /// - /// - /// - /// - public void AddBridge(CotijaBridgeBase bridge) - { - RoomBridges.Add(bridge); - var b = bridge as IDelayedConfiguration; - if (b != null) - { - Debug.Console(0, this, "Adding room bridge with delayed configuration"); - b.ConfigurationIsReady += new EventHandler(bridge_ConfigurationIsReady); - } - else - { - Debug.Console(0, this, "Adding room bridge and sending configuration"); - //SystemUuid = ConfigReader.ConfigObject.SystemUuid; - RegisterSystemToServer(); - } - } - - /// - /// - /// - /// - /// - void bridge_ConfigurationIsReady(object sender, EventArgs e) - { - Debug.Console(1, this, "Bridge ready. Registering"); - //SystemUuid = ConfigReader.ConfigObject.SystemUuid; - // send the configuration object to the server - RegisterSystemToServer(); - } - - /// - /// - /// - /// - void ReconnectToServerTimerCallback(object o) - { - RegisterSystemToServer(); - } - - /// - /// Verifies system connection with servers - /// - /// - void AuthorizeSystem(string code) - { - //SystemUuid = ConfigReader.ConfigObject.SystemUuid; - - if (string.IsNullOrEmpty(SystemUuid)) - { - CrestronConsole.ConsoleCommandResponse("System does not have a UUID. Please ensure proper portal-format configuration is loaded and restart."); - return; - } - - if (string.IsNullOrEmpty(code)) - { - CrestronConsole.ConsoleCommandResponse("Please enter a user code to authorize a system"); - return; - } - - var req = new HttpClientRequest(); - string url = string.Format("http://{0}/api/system/grantcode/{1}/{2}", Config.ServerUrl, code, SystemUuid); - Debug.Console(0, this, "Authorizing to: {0}", url); - - if (string.IsNullOrEmpty(Config.ServerUrl)) - { - CrestronConsole.ConsoleCommandResponse("Config URL address is not set. Check portal configuration"); - return; - } - try - { - req.Url.Parse(url); - new HttpClient().DispatchAsync(req, (r, e) => - { - CheckHttpDebug(r, e); - if (e == HTTP_CALLBACK_ERROR.COMPLETED) - { - if (r.Code == 200) - { - Debug.Console(0, "System authorized, sending config."); -#warning This registration may need to wait for config ready. Maybe. - RegisterSystemToServer(); - } - else if (r.Code == 404) - { - if (r.ContentString.Contains("codeNotFound")) - { - Debug.Console(0, "Authorization failed, code not found for system UUID {0}", SystemUuid); - } - else if (r.ContentString.Contains("uuidNotFound")) - { - Debug.Console(0, "Authorization failed, uuid {0} not found. Check Essentials configuration is correct", - SystemUuid); - } - } - } - else - Debug.Console(0, this, "Error {0} in authorizing system", e); - }); - } - catch (Exception e) - { - Debug.Console(0, this, "Error in authorizing: {0}", e); - } - } - - /// - /// Dumps info in response to console command. - /// - void ShowInfo() - { - var url = Config != null ? Config.ServerUrl : "No config"; - string name; - string code; - if (RoomBridges != null && RoomBridges.Count > 0) - { - name = RoomBridges[0].RoomName; - code = RoomBridges[0].UserCode; - } - else - { - name = "No config"; - code = "Not available"; - } - var conn = WSClient == null ? "No client" : (WSClient.Connected ? "Yes" : "No"); - var secSinceLastAck = DateTime.Now - LastAckMessage; - - - CrestronConsole.ConsoleCommandResponse(@"Mobile Control Information: - Server address: {0} - System Name: {1} - System URL: {2} - System UUID: {3} - System User code: {4} - Connected?: {5} - Seconds Since Last Ack: {6}" - , url, name, ConfigReader.ConfigObject.SystemUrl, SystemUuid, - code, conn, secSinceLastAck.Seconds); - } - - /// - /// Registers the room with the server - /// - /// URL of the server, including the port number, if not 80. Format: "serverUrlOrIp:port" - void RegisterSystemToServer() - { - ConnectWebsocketClient(); - } - - /// - /// Connects the Websocket Client - /// - /// - void ConnectWebsocketClient() - { - - Debug.Console(1, this, "Initializing Stream client to server."); - - if (WSClient != null) - { - Debug.Console(1, this, "Cleaning up previous socket"); - CleanUpWebsocketClient(); - } - - WSClient = new WebSocketClient(); - WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); - WSClient.ConnectionCallBack = Websocket_ConnectCallback; - WSClient.ConnectAsync(); - } - - /// - /// - /// - /// - /// - int Websocket_ConnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code) - { - if (code == WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) - { - StopServerReconnectTimer(); - Debug.Console(1, this, "Websocket connected"); - WSClient.DisconnectCallBack = Websocket_DisconnectCallback; - WSClient.SendCallBack = Websocket_SendCallback; - WSClient.ReceiveCallBack = Websocket_ReceiveCallback; - WSClient.ReceiveAsync(); - SendMessageObjectToServer(new - { - type = "hello" - }); - } - else - { - if (code == WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_HTTP_HANDSHAKE_TOKEN_ERROR) - { - // This is the case when app server is running behind a websever and app server is down - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failed. Check that app server is running behind web server"); - } - else if (code == WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SOCKET_CONNECTION_FAILED) - { - // this will be the case when webserver is unreachable - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failed"); - } - else - { - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failure: {0}", code); - } - StartServerReconnectTimer(); - } - - return 0; - } - - /// - /// After a "hello" from the server, sends config and stuff - /// - void SendInitialMessage() - { - Debug.Console(1, this, "Sending initial join message"); - var confObject = ConfigReader.ConfigObject; - confObject.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name; - var version = Assembly.GetExecutingAssembly().GetName().Version; - confObject.Info.RuntimeInfo.AssemblyVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); - - var msg = new - { - type = "join", - content = new - { - config = confObject - } - }; - SendMessageObjectToServer(msg); - } - - /// - /// Sends any object type to server - /// - /// - public void SendMessageObjectToServer(object o) - { - SendMessageToServer(JObject.FromObject(o)); - } - - /// - /// Sends a message to the server from a room - /// - /// room from which the message originates - /// object to be serialized and sent in post body - public void SendMessageToServer(JObject o) - { - if (WSClient != null && WSClient.Connected) - { - string message = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - - if (!message.Contains("/system/heartbeat")) - Debug.Console(1, this, "Message TX: {0}", message); - //else - // Debug.Console(1, this, "TX messages contains /system/heartbeat"); - - var messageBytes = System.Text.Encoding.UTF8.GetBytes(message); - var result = WSClient.Send(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); - if (result != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) - { - Debug.Console(1, this, "Socket send result error: {0}", result); - } - } - else if (WSClient == null) - { - Debug.Console(1, this, "Cannot send. Not connected."); - } - } - - /// - /// Disconnects the SSE Client and stops the heartbeat timer - /// - /// - void CleanUpWebsocketClient() - { - Debug.Console(1, this, "Disconnecting websocket"); - if (WSClient != null) - { - WSClient.SendCallBack = null; - WSClient.ReceiveCallBack = null; - WSClient.ConnectionCallBack = null; - WSClient.DisconnectCallBack = null; - if (WSClient.Connected) - { - WSClient.Disconnect(); - } - WSClient = null; - } - } - - /// - /// - /// - /// - /// - void StartServerReconnectTimer() - { - StopServerReconnectTimer(); - ServerReconnectTimer = new CTimer(ReconnectToServerTimerCallback, ServerReconnectInterval); - Debug.Console(1, this, "Reconnect Timer Started."); - } - - /// - /// Does what it says - /// - void StopServerReconnectTimer() - { - if (ServerReconnectTimer != null) - { - ServerReconnectTimer.Stop(); - ServerReconnectTimer = null; - } - } - - /// - /// Executes when we don't get a heartbeat message in time. Triggers reconnect. - /// - /// For CTimer callback. Not used - void HeartbeatExpiredTimerCallback(object o) - { - Debug.Console(1, this, "Heartbeat Timer Expired."); - if (ServerHeartbeatCheckTimer != null) - { - ServerHeartbeatCheckTimer.Stop(); - ServerHeartbeatCheckTimer = null; - } - CleanUpWebsocketClient(); - StartServerReconnectTimer(); - } - - /// - /// - /// - /// - /// - void ResetOrStartHearbeatTimer() - { - if (ServerHeartbeatCheckTimer == null) - { - ServerHeartbeatCheckTimer = new CTimer(HeartbeatExpiredTimerCallback, null, ServerHeartbeatInterval, ServerHeartbeatInterval); - Debug.Console(1, this, "Heartbeat Timer Started."); - } - else - { - ServerHeartbeatCheckTimer.Reset(ServerHeartbeatInterval, ServerHeartbeatInterval); - } - } - - /// - /// Waits two and goes again - /// - void ReconnectStreamClient() - { - new CTimer(o => ConnectWebsocketClient(), 2000); - } - - /// - /// - /// - /// - /// - int Websocket_DisconnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code, object o) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Websocket disconnected with code: {0}", code); - - if (ServerHeartbeatCheckTimer != null) - ServerHeartbeatCheckTimer.Stop(); - // Start the reconnect timer - StartServerReconnectTimer(); - return 0; - } - - - /// - /// Resets reconnect timer and updates usercode - /// - /// - void HandleHeartBeat(JToken content) - { - SendMessageToServer(JObject.FromObject(new - { - type = "/system/heartbeatAck" - })); - - var code = content["userCode"]; - if(code != null) - { - foreach (var b in RoomBridges) - { - b.SetUserCode(code.Value()); - } - } - ResetOrStartHearbeatTimer(); - } - - /// - /// Outputs debug info when enabled - /// - /// - /// - /// - void CheckHttpDebug(HttpClientResponse r, HTTP_CALLBACK_ERROR e) - { - if (HttpDebugEnabled) - { - try - { - Debug.Console(0, this, "------ Begin HTTP Debug ---------------------------------------"); - if (r != null) - { - Debug.Console(0, this, "HTTP Response URL: {0}", r.ResponseUrl != null ? r.ResponseUrl.ToString() : "NONE"); - Debug.Console(0, this, "HTTP Response code: {0}", r.Code); - Debug.Console(0, this, "HTTP Response content: \r{0}", r.ContentString); - } - else - { - Debug.Console(0, this, "No HTTP response"); - } - Debug.Console(0, this, "HTTP Response 'error' {0}", e); - Debug.Console(0, this, "------ End HTTP Debug -----------------------------------------"); - } - catch (Exception ex) - { - Debug.Console(0, this, "HttpDebugError: {0}", ex); - } - } - } - - /// - /// - /// - /// - /// - /// - /// - int Websocket_ReceiveCallback(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode, - WebSocketClient.WEBSOCKET_RESULT_CODES err) - { - if (opcode == WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME) - { - var rx = System.Text.Encoding.UTF8.GetString(data, 0, (int)length); - if (rx.Length > 0) - ParseStreamRx(rx); - WSClient.ReceiveAsync(); - } - - else if (opcode == WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__CLOSE) - { - Debug.Console(1, this, "Websocket disconnect received from remote"); - CleanUpWebsocketClient(); - } - else - { - Debug.Console(1, this, "websocket rx opcode/err {0}/{1}", opcode, err); - WSClient.ReceiveAsync(); - } - return 0; - } - - /// - /// Callback to catch possible errors in sending via the websocket - /// - /// - /// - int Websocket_SendCallback(Crestron.SimplSharp.CrestronWebSocketClient.WebSocketClient.WEBSOCKET_RESULT_CODES result) - { - if(result != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SendCallback questionable result: {0}", result); - return 1; - } - - /// - /// - /// - /// - /// - void ParseStreamRx(string message) - { - if(string.IsNullOrEmpty(message)) - return; - - if (!message.Contains("/system/heartbeat")) - { - Debug.Console(1, this, "Message RX: {0}", message); - } - else - { - LastAckMessage = DateTime.Now; - } - - try - { - var messageObj = JObject.Parse(message); - - var type = messageObj["type"].Value(); - - if (type == "hello") - { - SendInitialMessage(); - ResetOrStartHearbeatTimer(); - } - else if (type == "/system/heartbeat") - { - HandleHeartBeat(messageObj["content"]); - } - else if (type == "raw") - { - var wrapper = messageObj["content"].ToObject(); - DeviceJsonApi.DoDeviceAction(wrapper); - } - else if (type == "close") - { - Debug.Console(1, this, "Received close message from server."); - // DisconnectWebsocketClient(); - - if (ServerHeartbeatCheckTimer != null) - ServerHeartbeatCheckTimer.Stop(); - } - else - { - // Check path against Action dictionary - if (ActionDictionary.ContainsKey(type)) - { - var action = ActionDictionary[type]; - - if (action is Action) - { - (action as Action)(); - } - else if (action is PressAndHoldAction) - { - var stateString = messageObj["content"]["state"].Value(); - - // Look for a button press event - if (!string.IsNullOrEmpty(stateString)) - { - switch (stateString) - { - case "true": - { - if (!PushedActions.ContainsKey(type)) - { - PushedActions.Add(type, new CTimer(o => - { - (action as PressAndHoldAction)(false); - PushedActions.Remove(type); - }, null, ButtonHeartbeatInterval, ButtonHeartbeatInterval)); - } - // Maybe add an else to reset the timer - break; - } - case "held": - { - if (PushedActions.ContainsKey(type)) - { - PushedActions[type].Reset(ButtonHeartbeatInterval, ButtonHeartbeatInterval); - } - return; - } - case "false": - { - if (PushedActions.ContainsKey(type)) - { - PushedActions[type].Stop(); - PushedActions.Remove(type); - } - break; - } - } - - (action as PressAndHoldAction)(stateString == "true"); - } - } - else if (action is Action) - { - var stateString = messageObj["content"]["state"].Value(); - - if (!string.IsNullOrEmpty(stateString)) - { - (action as Action)(stateString == "true"); - } - } - else if (action is Action) - { - (action as Action)(messageObj["content"]["value"].Value()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"]["value"].Value()); - } - else if (action is Action) - { - (action as Action)(messageObj["content"] - .ToObject()); - } - } - else - { - Debug.Console(1, this, "-- Warning: Incoming message has no registered handler"); - } - } - } - catch (Exception err) - { - //Debug.Console(1, "SseMessageLengthBeforeFailureCount: {0}", SseMessageLengthBeforeFailureCount); - //SseMessageLengthBeforeFailureCount = 0; - Debug.Console(1, this, "Unable to parse message: {0}", err); - } - } - - void TestHttpRequest(string s) - { - { - s = s.Trim(); - if (string.IsNullOrEmpty(s)) - { - PrintTestHttpRequestUsage(); - return; - } - var tokens = s.Split(' '); - if (tokens.Length < 2) - { - CrestronConsole.ConsoleCommandResponse("Too few paramaters\r"); - PrintTestHttpRequestUsage(); - return; - } - - try - { - var url = tokens[1]; - if (tokens[0].ToLower() == "get") - { - var resp = new HttpClient().Get(url); - CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); - } - else if (tokens[0].ToLower() == "post") - { - var resp = new HttpClient().Post(url, new byte[] { }); - CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); - } - - else - { - CrestronConsole.ConsoleCommandResponse("Only get or post supported\r"); - PrintTestHttpRequestUsage(); - } - } - catch (HttpException e) - { - CrestronConsole.ConsoleCommandResponse("Exception in request:\r"); - CrestronConsole.ConsoleCommandResponse("Response URL: {0}\r", e.Response.ResponseUrl); - CrestronConsole.ConsoleCommandResponse("Response Error Code: {0}\r", e.Response.Code); - CrestronConsole.ConsoleCommandResponse("Response body: {0}\r", e.Response.ContentString); - } - - } - } - - void PrintTestHttpRequestUsage() - { - CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r"); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharp.Reflection; +using Crestron.SimplSharpPro.CrestronThread; +using Crestron.SimplSharp.CrestronWebSocketClient; +using Crestron.SimplSharpPro; +using Crestron.SimplSharp.Net.Http; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Room.MobileControl; +using PepperDash.Essentials.AppServer.Messengers; + +namespace PepperDash.Essentials +{ + public class MobileControlSystemController : Device + { + WebSocketClient WSClient; + + //bool LinkUp; + + /// + /// Prevents post operations from stomping on each other and getting lost + /// + CEvent PostLockEvent = new CEvent(true, true); + + CEvent RegisterLockEvent = new CEvent(true, true); + + public MobileControlConfig Config { get; private set; } + + Dictionary ActionDictionary = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + + Dictionary PushedActions = new Dictionary(); + + public ConfigMessenger ConfigMessenger { get; private set; } + + CTimer ServerHeartbeatCheckTimer; + + long ServerHeartbeatInterval = 20000; + + CTimer ServerReconnectTimer; + + long ServerReconnectInterval = 5000; + + DateTime LastAckMessage; + + public string SystemUuid; + + List RoomBridges = new List(); + + long ButtonHeartbeatInterval = 1000; + + /// + /// Used for tracking HTTP debugging + /// + bool HttpDebugEnabled; + + /// + /// + /// + /// + /// + /// + public MobileControlSystemController(string key, string name, MobileControlConfig config) : base(key, name) + { + Config = config; + + SystemUuid = ConfigReader.ConfigObject.SystemUuid; + + Debug.Console(0, this, "Mobile UI controller initializing for server:{0}", config.ServerUrl); + + CrestronConsole.AddNewConsoleCommand(AuthorizeSystem, + "mobileauth", "Authorizes system to talk to Mobile Control server", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => ShowInfo(), + "mobileinfo", "Shows information for current mobile control session", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => { + s = s.Trim(); + if(!string.IsNullOrEmpty(s)) + { + HttpDebugEnabled = (s.Trim() != "0"); + } + CrestronConsole.ConsoleCommandResponse("HTTP Debug {0}", HttpDebugEnabled ? "Enabled" : "Disabled"); + }, + "mobilehttpdebug", "1 enables more verbose HTTP response debugging", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(TestHttpRequest, + "mobilehttprequest", "Tests an HTTP get to URL given", ConsoleAccessLevelEnum.AccessOperator); + + CrestronConsole.AddNewConsoleCommand(PrintActionDictionaryPaths, "mobileshowactionpaths", + "Prints the paths in the Action Dictionary", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => ConnectWebsocketClient(), "mobileconnect", + "Forces connect of websocket", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => CleanUpWebsocketClient(), "mobiledisco", + "Disconnects websocket", ConsoleAccessLevelEnum.AccessOperator); + + CrestronConsole.AddNewConsoleCommand(s => ParseStreamRx(s), "mobilesimulateaction", "Simulates a message from the server", ConsoleAccessLevelEnum.AccessOperator); + + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); + + // Config Messenger + var cmKey = Key + "-config"; + ConfigMessenger = new ConfigMessenger(cmKey, "/config"); + ConfigMessenger.RegisterWithAppServer(this); + } + + /// + /// If config rooms is empty or null then go + /// + /// + public override bool CustomActivate() + { + if (ConfigReader.ConfigObject.Rooms == null || ConfigReader.ConfigObject.Rooms.Count == 0) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Config contains no rooms. Registering with Server."); + RegisterSystemToServer(); + } + + return base.CustomActivate(); + } + + /// + /// + /// + /// + void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs args) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Ethernet status change, port {0}: {1}", + args.EthernetAdapter, args.EthernetEventType); + + if (args.EthernetEventType == eEthernetEventType.LinkDown && WSClient != null && args.EthernetAdapter == WSClient.EthernetAdapter) + { + CleanUpWebsocketClient(); + } + } + + /// + /// Sends message to server to indicate the system is shutting down + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping + && WSClient != null + && WSClient.Connected) + { + CleanUpWebsocketClient(); + } + } + + public void PrintActionDictionaryPaths(object o) + { + Debug.Console(0, this, "ActionDictionary Contents:"); + + foreach (var item in ActionDictionary) + { + Debug.Console(0, this, "{0}", item.Key); + } + } + + /// + /// Adds an action to the dictionary + /// + /// The path of the API command + /// The action to be triggered by the commmand + public void AddAction(string key, object action) + { + if (!ActionDictionary.ContainsKey(key)) + { + ActionDictionary.Add(key, action); + } + else + { + Debug.Console(1, this, "Cannot add action with key '{0}' because key already exists in ActionDictionary.", key); + } + } + + /// + /// Removes an action from the dictionary + /// + /// + public void RemoveAction(string key) + { + if (ActionDictionary.ContainsKey(key)) + ActionDictionary.Remove(key); + } + + /// + /// + /// + /// + public void AddBridge(MobileControlBridgeBase bridge) + { + RoomBridges.Add(bridge); + var b = bridge as IDelayedConfiguration; + if (b != null) + { + Debug.Console(0, this, "Adding room bridge with delayed configuration"); + b.ConfigurationIsReady += new EventHandler(bridge_ConfigurationIsReady); + } + else + { + Debug.Console(0, this, "Adding room bridge and sending configuration"); + //SystemUuid = ConfigReader.ConfigObject.SystemUuid; + RegisterSystemToServer(); + } + } + + /// + /// + /// + /// + /// + void bridge_ConfigurationIsReady(object sender, EventArgs e) + { + Debug.Console(1, this, "Bridge ready. Registering"); + //SystemUuid = ConfigReader.ConfigObject.SystemUuid; + // send the configuration object to the server + RegisterSystemToServer(); + } + + /// + /// + /// + /// + void ReconnectToServerTimerCallback(object o) + { + RegisterSystemToServer(); + } + + /// + /// Verifies system connection with servers + /// + /// + void AuthorizeSystem(string code) + { + //SystemUuid = ConfigReader.ConfigObject.SystemUuid; + + if (string.IsNullOrEmpty(SystemUuid)) + { + CrestronConsole.ConsoleCommandResponse("System does not have a UUID. Please ensure proper portal-format configuration is loaded and restart."); + return; + } + + if (string.IsNullOrEmpty(code)) + { + CrestronConsole.ConsoleCommandResponse("Please enter a user code to authorize a system"); + return; + } + + var req = new HttpClientRequest(); + string url = string.Format("http://{0}/api/system/grantcode/{1}/{2}", Config.ServerUrl, code, SystemUuid); + Debug.Console(0, this, "Authorizing to: {0}", url); + + if (string.IsNullOrEmpty(Config.ServerUrl)) + { + CrestronConsole.ConsoleCommandResponse("Config URL address is not set. Check portal configuration"); + return; + } + try + { + req.Url.Parse(url); + new HttpClient().DispatchAsync(req, (r, e) => + { + CheckHttpDebug(r, e); + if (e == HTTP_CALLBACK_ERROR.COMPLETED) + { + if (r.Code == 200) + { + Debug.Console(0, "System authorized, sending config."); +#warning This registration may need to wait for config ready. Maybe. + RegisterSystemToServer(); + } + else if (r.Code == 404) + { + if (r.ContentString.Contains("codeNotFound")) + { + Debug.Console(0, "Authorization failed, code not found for system UUID {0}", SystemUuid); + } + else if (r.ContentString.Contains("uuidNotFound")) + { + Debug.Console(0, "Authorization failed, uuid {0} not found. Check Essentials configuration is correct", + SystemUuid); + } + } + } + else + Debug.Console(0, this, "Error {0} in authorizing system", e); + }); + } + catch (Exception e) + { + Debug.Console(0, this, "Error in authorizing: {0}", e); + } + } + + /// + /// Dumps info in response to console command. + /// + void ShowInfo() + { + var url = Config != null ? Config.ServerUrl : "No config"; + string name; + string code; + if (RoomBridges != null && RoomBridges.Count > 0) + { + name = RoomBridges[0].RoomName; + code = RoomBridges[0].UserCode; + } + else + { + name = "No config"; + code = "Not available"; + } + var conn = WSClient == null ? "No client" : (WSClient.Connected ? "Yes" : "No"); + var secSinceLastAck = DateTime.Now - LastAckMessage; + + + CrestronConsole.ConsoleCommandResponse(@"Mobile Control Information: + Server address: {0} + System Name: {1} + System URL: {2} + System UUID: {3} + System User code: {4} + Connected?: {5} + Seconds Since Last Ack: {6}" + , url, name, ConfigReader.ConfigObject.SystemUrl, SystemUuid, + code, conn, secSinceLastAck.Seconds); + } + + /// + /// Registers the room with the server + /// + /// URL of the server, including the port number, if not 80. Format: "serverUrlOrIp:port" + void RegisterSystemToServer() + { + ConnectWebsocketClient(); + } + + /// + /// Connects the Websocket Client + /// + /// + void ConnectWebsocketClient() + { + + Debug.Console(1, this, "Initializing Stream client to server."); + + if (WSClient != null) + { + Debug.Console(1, this, "Cleaning up previous socket"); + CleanUpWebsocketClient(); + } + + WSClient = new WebSocketClient(); + WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); + WSClient.ConnectionCallBack = Websocket_ConnectCallback; + WSClient.ConnectAsync(); + } + + /// + /// + /// + /// + /// + int Websocket_ConnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code) + { + if (code == WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) + { + StopServerReconnectTimer(); + Debug.Console(1, this, "Websocket connected"); + WSClient.DisconnectCallBack = Websocket_DisconnectCallback; + WSClient.SendCallBack = Websocket_SendCallback; + WSClient.ReceiveCallBack = Websocket_ReceiveCallback; + WSClient.ReceiveAsync(); + SendMessageObjectToServer(new + { + type = "hello" + }); + } + else + { + if (code == WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_HTTP_HANDSHAKE_TOKEN_ERROR) + { + // This is the case when app server is running behind a websever and app server is down + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failed. Check that app server is running behind web server"); + } + else if (code == WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SOCKET_CONNECTION_FAILED) + { + // this will be the case when webserver is unreachable + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failed"); + } + else + { + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failure: {0}", code); + } + StartServerReconnectTimer(); + } + + return 0; + } + + /// + /// After a "hello" from the server, sends config and stuff + /// + void SendInitialMessage() + { + Debug.Console(1, this, "Sending initial join message"); + var confObject = ConfigReader.ConfigObject; + confObject.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name; + var version = Assembly.GetExecutingAssembly().GetName().Version; + confObject.Info.RuntimeInfo.AssemblyVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); + + var msg = new + { + type = "join", + content = new + { + config = confObject + } + }; + SendMessageObjectToServer(msg); + } + + /// + /// Sends any object type to server + /// + /// + public void SendMessageObjectToServer(object o) + { + SendMessageToServer(JObject.FromObject(o)); + } + + /// + /// Sends a message to the server from a room + /// + /// room from which the message originates + /// object to be serialized and sent in post body + public void SendMessageToServer(JObject o) + { + if (WSClient != null && WSClient.Connected) + { + string message = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + + if (!message.Contains("/system/heartbeat")) + Debug.Console(1, this, "Message TX: {0}", message); + //else + // Debug.Console(1, this, "TX messages contains /system/heartbeat"); + + var messageBytes = System.Text.Encoding.UTF8.GetBytes(message); + var result = WSClient.Send(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); + if (result != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) + { + Debug.Console(1, this, "Socket send result error: {0}", result); + } + } + else if (WSClient == null) + { + Debug.Console(1, this, "Cannot send. Not connected."); + } + } + + /// + /// Disconnects the SSE Client and stops the heartbeat timer + /// + /// + void CleanUpWebsocketClient() + { + Debug.Console(1, this, "Disconnecting websocket"); + if (WSClient != null) + { + WSClient.SendCallBack = null; + WSClient.ReceiveCallBack = null; + WSClient.ConnectionCallBack = null; + WSClient.DisconnectCallBack = null; + if (WSClient.Connected) + { + WSClient.Disconnect(); + } + WSClient = null; + } + } + + /// + /// + /// + /// + /// + void StartServerReconnectTimer() + { + StopServerReconnectTimer(); + ServerReconnectTimer = new CTimer(ReconnectToServerTimerCallback, ServerReconnectInterval); + Debug.Console(1, this, "Reconnect Timer Started."); + } + + /// + /// Does what it says + /// + void StopServerReconnectTimer() + { + if (ServerReconnectTimer != null) + { + ServerReconnectTimer.Stop(); + ServerReconnectTimer = null; + } + } + + /// + /// Executes when we don't get a heartbeat message in time. Triggers reconnect. + /// + /// For CTimer callback. Not used + void HeartbeatExpiredTimerCallback(object o) + { + Debug.Console(1, this, "Heartbeat Timer Expired."); + if (ServerHeartbeatCheckTimer != null) + { + ServerHeartbeatCheckTimer.Stop(); + ServerHeartbeatCheckTimer = null; + } + CleanUpWebsocketClient(); + StartServerReconnectTimer(); + } + + /// + /// + /// + /// + /// + void ResetOrStartHearbeatTimer() + { + if (ServerHeartbeatCheckTimer == null) + { + ServerHeartbeatCheckTimer = new CTimer(HeartbeatExpiredTimerCallback, null, ServerHeartbeatInterval, ServerHeartbeatInterval); + Debug.Console(1, this, "Heartbeat Timer Started."); + } + else + { + ServerHeartbeatCheckTimer.Reset(ServerHeartbeatInterval, ServerHeartbeatInterval); + } + } + + /// + /// Waits two and goes again + /// + void ReconnectStreamClient() + { + new CTimer(o => ConnectWebsocketClient(), 2000); + } + + /// + /// + /// + /// + /// + int Websocket_DisconnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code, object o) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Websocket disconnected with code: {0}", code); + + if (ServerHeartbeatCheckTimer != null) + ServerHeartbeatCheckTimer.Stop(); + // Start the reconnect timer + StartServerReconnectTimer(); + return 0; + } + + + /// + /// Resets reconnect timer and updates usercode + /// + /// + void HandleHeartBeat(JToken content) + { + SendMessageToServer(JObject.FromObject(new + { + type = "/system/heartbeatAck" + })); + + var code = content["userCode"]; + if(code != null) + { + foreach (var b in RoomBridges) + { + b.SetUserCode(code.Value()); + } + } + ResetOrStartHearbeatTimer(); + } + + /// + /// Outputs debug info when enabled + /// + /// + /// + /// + void CheckHttpDebug(HttpClientResponse r, HTTP_CALLBACK_ERROR e) + { + if (HttpDebugEnabled) + { + try + { + Debug.Console(0, this, "------ Begin HTTP Debug ---------------------------------------"); + if (r != null) + { + Debug.Console(0, this, "HTTP Response URL: {0}", r.ResponseUrl != null ? r.ResponseUrl.ToString() : "NONE"); + Debug.Console(0, this, "HTTP Response code: {0}", r.Code); + Debug.Console(0, this, "HTTP Response content: \r{0}", r.ContentString); + } + else + { + Debug.Console(0, this, "No HTTP response"); + } + Debug.Console(0, this, "HTTP Response 'error' {0}", e); + Debug.Console(0, this, "------ End HTTP Debug -----------------------------------------"); + } + catch (Exception ex) + { + Debug.Console(0, this, "HttpDebugError: {0}", ex); + } + } + } + + /// + /// + /// + /// + /// + /// + /// + int Websocket_ReceiveCallback(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode, + WebSocketClient.WEBSOCKET_RESULT_CODES err) + { + if (opcode == WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME) + { + var rx = System.Text.Encoding.UTF8.GetString(data, 0, (int)length); + if (rx.Length > 0) + ParseStreamRx(rx); + WSClient.ReceiveAsync(); + } + + else if (opcode == WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__CLOSE) + { + Debug.Console(1, this, "Websocket disconnect received from remote"); + CleanUpWebsocketClient(); + } + else + { + Debug.Console(1, this, "websocket rx opcode/err {0}/{1}", opcode, err); + WSClient.ReceiveAsync(); + } + return 0; + } + + /// + /// Callback to catch possible errors in sending via the websocket + /// + /// + /// + int Websocket_SendCallback(Crestron.SimplSharp.CrestronWebSocketClient.WebSocketClient.WEBSOCKET_RESULT_CODES result) + { + if(result != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SendCallback questionable result: {0}", result); + return 1; + } + + /// + /// + /// + /// + /// + void ParseStreamRx(string message) + { + if(string.IsNullOrEmpty(message)) + return; + + if (!message.Contains("/system/heartbeat")) + { + Debug.Console(1, this, "Message RX: {0}", message); + } + else + { + LastAckMessage = DateTime.Now; + } + + try + { + var messageObj = JObject.Parse(message); + + var type = messageObj["type"].Value(); + + if (type == "hello") + { + SendInitialMessage(); + ResetOrStartHearbeatTimer(); + } + else if (type == "/system/heartbeat") + { + HandleHeartBeat(messageObj["content"]); + } + else if (type == "raw") + { + var wrapper = messageObj["content"].ToObject(); + DeviceJsonApi.DoDeviceAction(wrapper); + } + else if (type == "close") + { + Debug.Console(1, this, "Received close message from server."); + // DisconnectWebsocketClient(); + + if (ServerHeartbeatCheckTimer != null) + ServerHeartbeatCheckTimer.Stop(); + } + else + { + // Check path against Action dictionary + if (ActionDictionary.ContainsKey(type)) + { + var action = ActionDictionary[type]; + + if (action is Action) + { + (action as Action)(); + } + else if (action is PressAndHoldAction) + { + var stateString = messageObj["content"]["state"].Value(); + + // Look for a button press event + if (!string.IsNullOrEmpty(stateString)) + { + switch (stateString) + { + case "true": + { + if (!PushedActions.ContainsKey(type)) + { + PushedActions.Add(type, new CTimer(o => + { + (action as PressAndHoldAction)(false); + PushedActions.Remove(type); + }, null, ButtonHeartbeatInterval, ButtonHeartbeatInterval)); + } + // Maybe add an else to reset the timer + break; + } + case "held": + { + if (PushedActions.ContainsKey(type)) + { + PushedActions[type].Reset(ButtonHeartbeatInterval, ButtonHeartbeatInterval); + } + return; + } + case "false": + { + if (PushedActions.ContainsKey(type)) + { + PushedActions[type].Stop(); + PushedActions.Remove(type); + } + break; + } + } + + (action as PressAndHoldAction)(stateString == "true"); + } + } + else if (action is Action) + { + var stateString = messageObj["content"]["state"].Value(); + + if (!string.IsNullOrEmpty(stateString)) + { + (action as Action)(stateString == "true"); + } + } + else if (action is Action) + { + (action as Action)(messageObj["content"]["value"].Value()); + } + else if (action is Action) + { + (action as Action)(messageObj["content"]["value"].Value()); + } + else if (action is Action) + { + (action as Action)(messageObj["content"] + .ToObject()); + } + } + else + { + Debug.Console(1, this, "-- Warning: Incoming message has no registered handler"); + } + } + } + catch (Exception err) + { + //Debug.Console(1, "SseMessageLengthBeforeFailureCount: {0}", SseMessageLengthBeforeFailureCount); + //SseMessageLengthBeforeFailureCount = 0; + Debug.Console(1, this, "Unable to parse message: {0}", err); + } + } + + void TestHttpRequest(string s) + { + { + s = s.Trim(); + if (string.IsNullOrEmpty(s)) + { + PrintTestHttpRequestUsage(); + return; + } + var tokens = s.Split(' '); + if (tokens.Length < 2) + { + CrestronConsole.ConsoleCommandResponse("Too few paramaters\r"); + PrintTestHttpRequestUsage(); + return; + } + + try + { + var url = tokens[1]; + if (tokens[0].ToLower() == "get") + { + var resp = new HttpClient().Get(url); + CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); + } + else if (tokens[0].ToLower() == "post") + { + var resp = new HttpClient().Post(url, new byte[] { }); + CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp); + } + + else + { + CrestronConsole.ConsoleCommandResponse("Only get or post supported\r"); + PrintTestHttpRequestUsage(); + } + } + catch (HttpException e) + { + CrestronConsole.ConsoleCommandResponse("Exception in request:\r"); + CrestronConsole.ConsoleCommandResponse("Response URL: {0}\r", e.Response.ResponseUrl); + CrestronConsole.ConsoleCommandResponse("Response Error Code: {0}\r", e.Response.Code); + CrestronConsole.ConsoleCommandResponse("Response body: {0}\r", e.Response.ContentString); + } + + } + } + + void PrintTestHttpRequestUsage() + { + CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r"); + } + } } \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaBridgeBase.cs b/PepperDashEssentials/AppServer/RoomBridges/MobileControlBridgeBase.cs similarity index 81% rename from PepperDashEssentials/AppServer/RoomBridges/CotijaBridgeBase.cs rename to PepperDashEssentials/AppServer/RoomBridges/MobileControlBridgeBase.cs index a578a0ae..d7258070 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaBridgeBase.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/MobileControlBridgeBase.cs @@ -12,15 +12,15 @@ namespace PepperDash.Essentials /// /// /// - public abstract class CotijaBridgeBase: Device + public abstract class MobileControlBridgeBase: Device { - public CotijaSystemController Parent { get; private set; } + public MobileControlSystemController Parent { get; private set; } public string UserCode { get; private set; } public abstract string RoomName { get; } - public CotijaBridgeBase(string key, string name) + public MobileControlBridgeBase(string key, string name) : base(key, name) { } @@ -30,7 +30,7 @@ namespace PepperDash.Essentials /// as adding actions to parent /// /// - public virtual void AddParent(CotijaSystemController parent) + public virtual void AddParent(MobileControlSystemController parent) { Parent = parent; } diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/MobileControlDdvc01RoomBridge.cs similarity index 98% rename from PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs rename to PepperDashEssentials/AppServer/RoomBridges/MobileControlDdvc01RoomBridge.cs index 0ff3c80c..eefd8fbc 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/MobileControlDdvc01RoomBridge.cs @@ -16,9 +16,9 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { - public class CotijaDdvc01RoomBridge : CotijaBridgeBase, IDelayedConfiguration + public class MobileControlDdvc01RoomBridge : MobileControlBridgeBase, IDelayedConfiguration { public class BoolJoin { @@ -236,7 +236,7 @@ namespace PepperDash.Essentials.Room.Cotija } } - CotijaDdvc01DeviceBridge SourceBridge; + MobileControlDdvc01DeviceBridge SourceBridge; Ddvc01AtcMessenger AtcMessenger; Ddvc01VtcMessenger VtcMessenger; @@ -248,7 +248,7 @@ namespace PepperDash.Essentials.Room.Cotija /// /// /// - public CotijaDdvc01RoomBridge(string key, string name, uint ipId) + public MobileControlDdvc01RoomBridge(string key, string name, uint ipId) : base(key, name) { try @@ -258,7 +258,7 @@ namespace PepperDash.Essentials.Room.Cotija if (reg != Crestron.SimplSharpPro.eDeviceRegistrationUnRegistrationResponse.Success) Debug.Console(0, this, "Cannot connect EISC at IPID {0}: \r{1}", ipId, reg); - SourceBridge = new CotijaDdvc01DeviceBridge(key + "-sourceBridge", "DDVC01 source bridge", EISC); + SourceBridge = new MobileControlDdvc01DeviceBridge(key + "-sourceBridge", "DDVC01 source bridge", EISC); DeviceManager.AddDevice(SourceBridge); } catch (Exception) @@ -590,7 +590,7 @@ namespace PepperDash.Essentials.Room.Cotija // rmProps.VolumeSliderNames.Add(EISC.StringInput[i].StringValue); //} - // There should be cotija devices in here, I think... + // There should be Mobile Control devices in here, I think... if(co.Devices == null) co.Devices = new List(); diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/MobileControlEssentialsHuddleSpaceRoomBridge.cs similarity index 87% rename from PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs rename to PepperDashEssentials/AppServer/RoomBridges/MobileControlEssentialsHuddleSpaceRoomBridge.cs index a55dbdee..fd36389a 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/MobileControlEssentialsHuddleSpaceRoomBridge.cs @@ -9,14 +9,14 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Room.Cotija; +using PepperDash.Essentials.Room.MobileControl; using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.AudioCodec; namespace PepperDash.Essentials { - public class CotijaEssentialsHuddleSpaceRoomBridge : CotijaBridgeBase + public class MobileConrolEssentialsHuddleSpaceRoomBridge : MobileControlBridgeBase { public EssentialsRoomBase Room { get; private set; } @@ -42,7 +42,7 @@ namespace PepperDash.Essentials /// /// /// - public CotijaEssentialsHuddleSpaceRoomBridge(EssentialsRoomBase room): + public MobileConrolEssentialsHuddleSpaceRoomBridge(EssentialsRoomBase room): base("mobileControlBridge-essentialsHuddle", "Essentials Mobile Control Bridge-Huddle") { Room = room; @@ -52,7 +52,7 @@ namespace PepperDash.Essentials /// Override of base: calls base to add parent and then registers actions and events. /// /// - public override void AddParent(CotijaSystemController parent) + public override void AddParent(MobileControlSystemController parent) { base.AddParent(parent); @@ -169,19 +169,6 @@ namespace PepperDash.Essentials }); } - ///// - ///// Handler for codec changes - ///// - //void codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e) - //{ - // PostStatusMessage(new - // { - // calls = GetCallsMessageObject(), - // //vtc = GetVtcCallsMessageObject() - // }); - - //} - /// /// Helper for posting status message /// @@ -435,45 +422,6 @@ namespace PepperDash.Essentials volumes = volumes }); } - - ///// - ///// Helper to return a anonymous object with the call data for JSON message - ///// - ///// - //object GetCallsMessageObject() - //{ - // var callRm = Room as IHasVideoCodec; - // if (callRm == null) - // return null; - // return new - // { - // activeCalls = callRm.VideoCodec.ActiveCalls, - // callType = callRm.CallTypeFeedback.IntValue, - // inCall = callRm.InCallFeedback.BoolValue, - // isSharing = callRm.IsSharingFeedback.BoolValue, - // privacyModeIsOn = callRm.PrivacyModeIsOnFeedback.BoolValue - // }; - //} - - ///// - ///// Helper method to build call status for vtc - ///// - ///// - //object GetVtcCallsMessageObject() - //{ - // var callRm = Room as IHasVideoCodec; - // object vtc = null; - // if (callRm != null) - // { - // var codec = callRm.VideoCodec; - // vtc = new - // { - // isInCall = codec.IsInCall, - // calls = codec.ActiveCalls - // }; - // } - // return vtc; - //} } /// diff --git a/PepperDashEssentials/AppServer/RoomBridges/SourceDeviceMapDictionary.cs b/PepperDashEssentials/AppServer/RoomBridges/SourceDeviceMapDictionary.cs index 976c4121..b025de44 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/SourceDeviceMapDictionary.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/SourceDeviceMapDictionary.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { /// diff --git a/PepperDashEssentials/AppServer/Volumes.cs b/PepperDashEssentials/AppServer/Volumes.cs index 5806f117..5b5096b0 100644 --- a/PepperDashEssentials/AppServer/Volumes.cs +++ b/PepperDashEssentials/AppServer/Volumes.cs @@ -6,7 +6,7 @@ using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Essentials.Room.Cotija +namespace PepperDash.Essentials.Room.MobileControl { public class Volumes { diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 151509f2..c080c1b2 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -15,7 +15,7 @@ using PepperDash.Essentials.Devices.Common; using PepperDash.Essentials.DM; using PepperDash.Essentials.Fusion; using PepperDash.Essentials.Room.Config; -using PepperDash.Essentials.Room.Cotija; +using PepperDash.Essentials.Room.MobileControl; namespace PepperDash.Essentials { @@ -40,8 +40,11 @@ namespace PepperDash.Essentials { DeterminePlatform(); - //CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file", - // ConsoleAccessLevelEnum.AccessOperator); + //if (Debug.DoNotLoadOnNextBoot) + //{ + // CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file", + // ConsoleAccessLevelEnum.AccessOperator); + //} // CrestronConsole.AddNewConsoleCommand(S => { ConfigWriter.WriteConfigFile(null); }, "writeconfig", "writes the current config to a file", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(s => @@ -71,7 +74,8 @@ namespace PepperDash.Essentials "Template URL: {1}", ConfigReader.ConfigObject.SystemUrl, ConfigReader.ConfigObject.TemplateUrl); }, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator); - GoWithLoad(); + //if(!Debug.DoNotLoadOnNextBoot) + GoWithLoad(); } /// @@ -81,57 +85,64 @@ namespace PepperDash.Essentials /// public void DeterminePlatform() { - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Determining Platform...."); - - string filePathPrefix; - - var dirSeparator = Global.DirectorySeparator; - - var version = Crestron.SimplSharp.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - - var versionString = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); - - string directoryPrefix; - - directoryPrefix = Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory(); - - if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows OS + try { - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on 3-series Appliance", versionString); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Determining Platform...."); - // Check if User/ProgramX exists - if (Directory.Exists(directoryPrefix + dirSeparator + "User" - + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber))) + string filePathPrefix; + + var dirSeparator = Global.DirectorySeparator; + + var version = Crestron.SimplSharp.Reflection.Assembly.GetExecutingAssembly().GetName().Version; + + var versionString = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); + + string directoryPrefix; + + directoryPrefix = Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory(); + + if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows OS { - Debug.Console(0, @"User/program{0} directory found", InitialParametersClass.ApplicationNumber); - filePathPrefix = directoryPrefix + dirSeparator + "User" - + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on 3-series Appliance", versionString); + + // Check if User/ProgramX exists + if (Directory.Exists(directoryPrefix + dirSeparator + "User" + + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber))) + { + Debug.Console(0, @"User/program{0} directory found", InitialParametersClass.ApplicationNumber); + filePathPrefix = directoryPrefix + dirSeparator + "User" + + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; + } + // Check if Nvram/Programx exists + else if (Directory.Exists(directoryPrefix + dirSeparator + "Nvram" + + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber))) + { + Debug.Console(0, @"Nvram/program{0} directory found", InitialParametersClass.ApplicationNumber); + filePathPrefix = directoryPrefix + dirSeparator + "Nvram" + + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; + } + // If neither exists, set path to User/ProgramX + else + { + Debug.Console(0, @"No previous directory found. Using User/program{0}", InitialParametersClass.ApplicationNumber); + filePathPrefix = directoryPrefix + dirSeparator + "User" + + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; + } } - // Check if Nvram/Programx exists - else if (Directory.Exists(directoryPrefix + dirSeparator + "Nvram" - + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber))) + else // Handles Linux OS (Virtual Control) { - Debug.Console(0, @"Nvram/program{0} directory found", InitialParametersClass.ApplicationNumber); - filePathPrefix = directoryPrefix + dirSeparator + "Nvram" - + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; - } - // If neither exists, set path to User/ProgramX - else - { - Debug.Console(0, @"No previous directory found. Using User/program{0}", InitialParametersClass.ApplicationNumber); - filePathPrefix = directoryPrefix + dirSeparator + "User" - + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on Virtual Control Server", versionString); + + // Set path to User/ + filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator; } + + Global.SetFilePathPrefix(filePathPrefix); } - else // Handles Linux OS (Virtual Control) + catch (Exception e) { - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on Virtual Control Server", versionString); - - // Set path to User/ - filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator; + Debug.Console(0, "Unable to Determine Platform due to Exception: {0}", e.Message); } - - Global.SetFilePathPrefix(filePathPrefix); } /// @@ -141,6 +152,8 @@ namespace PepperDash.Essentials { try { + //Debug.SetDoNotLoadOnNextBoot(false); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials load from configuration"); var filesReady = SetupFilesystem(); @@ -335,7 +348,7 @@ namespace PepperDash.Essentials { var sysMon = DeviceManager.GetDeviceForKey("systemMonitor") as PepperDash.Essentials.Core.Monitoring.SystemMonitorController; - var appServer = DeviceManager.GetDeviceForKey("appServer") as CotijaSystemController; + var appServer = DeviceManager.GetDeviceForKey("appServer") as MobileControlSystemController; if (sysMon != null && appServer != null) @@ -489,13 +502,13 @@ namespace PepperDash.Essentials DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase((EssentialsHuddleSpaceRoom)room, 0xf1)); - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Cotija Bridge..."); - // Cotija bridge - var bridge = new CotijaEssentialsHuddleSpaceRoomBridge(room as EssentialsHuddleSpaceRoom); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge..."); + // Mobile Control bridge + var bridge = new MobileConrolEssentialsHuddleSpaceRoomBridge(room as EssentialsHuddleSpaceRoom); AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present DeviceManager.AddDevice(bridge); - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Cotija Bridge Added..."); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Mobile Control Bridge Added..."); } else if (room is EssentialsHuddleVtc1Room) { @@ -504,9 +517,9 @@ namespace PepperDash.Essentials Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion"); DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((EssentialsHuddleVtc1Room)room, 0xf1)); - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Cotija Bridge..."); - // Cotija bridge - var bridge = new CotijaEssentialsHuddleSpaceRoomBridge(room); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge..."); + // Mobile Control bridge + var bridge = new MobileConrolEssentialsHuddleSpaceRoomBridge(room); AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present DeviceManager.AddDevice(bridge); } @@ -529,11 +542,11 @@ namespace PepperDash.Essentials /// Helps add the post activation steps that link bridges to main controller /// /// - void AddBridgePostActivationHelper(CotijaBridgeBase bridge) + void AddBridgePostActivationHelper(MobileControlBridgeBase bridge) { bridge.AddPostActivationAction(() => { - var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as CotijaSystemController; + var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as MobileControlSystemController; if (parent == null) { Debug.Console(0, bridge, "ERROR: Cannot connect app server room bridge. System controller not present"); diff --git a/PepperDashEssentials/Factory/DeviceFactory.cs b/PepperDashEssentials/Factory/DeviceFactory.cs index ddee8361..24c4bfe1 100644 --- a/PepperDashEssentials/Factory/DeviceFactory.cs +++ b/PepperDashEssentials/Factory/DeviceFactory.cs @@ -61,18 +61,18 @@ namespace PepperDash.Essentials else if (typeName == "appserver") { - var props = JsonConvert.DeserializeObject(properties.ToString()); - return new CotijaSystemController(key, name, props); + var props = JsonConvert.DeserializeObject(properties.ToString()); + return new MobileControlSystemController(key, name, props); } else if (typeName == "mobilecontrolbridge-ddvc01") { var comm = CommFactory.GetControlPropertiesConfig(dc); - var bridge = new PepperDash.Essentials.Room.Cotija.CotijaDdvc01RoomBridge(key, name, comm.IpIdInt); + var bridge = new PepperDash.Essentials.Room.MobileControl.MobileControlDdvc01RoomBridge(key, name, comm.IpIdInt); bridge.AddPreActivationAction(() => { - var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as CotijaSystemController; + var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as MobileControlSystemController; if (parent == null) { Debug.Console(0, bridge, "ERROR: Cannot connect bridge. System controller not present"); diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 348a84a5..a238a4e8 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -184,12 +184,12 @@ - - + + - - - + + + @@ -238,7 +238,7 @@ - + diff --git a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs index 7077d9c2..b34e923b 100644 --- a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs @@ -38,6 +38,12 @@ namespace PepperDash.Essentials.Room.Config { return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing. } + else if (typeName == "dualdisplay") + { + var rm = new EssentialsDualDisplayRoom(roomConfig); + + return rm; + } return null; } diff --git a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs index 79a5f7df..44c88724 100644 --- a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs @@ -15,7 +15,7 @@ using PepperDash.Essentials.Devices.Common.Codec; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Devices.Common.AudioCodec; -namespace PepperDash.Essentials.Room.Types +namespace PepperDash.Essentials { public class EssentialsDualDisplayRoom : EssentialsNDisplayRoomBase, IHasCurrentVolumeControls, IRunRouteAction, IPrivacy, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasInCallFeedback @@ -174,9 +174,11 @@ namespace PepperDash.Essentials.Room.Types var leftDisp = PropertiesConfig.Displays[eSourceListItemDestinationTypes.leftDisplay]; if (leftDisp != null) { - if (!string.IsNullOrEmpty(leftDisp.Key)) + { LeftDisplay = DeviceManager.GetDeviceForKey(leftDisp.Key) as IRoutingSinkWithSwitching; + Displays.Add(eSourceListItemDestinationTypes.leftDisplay, LeftDisplay); + } else Debug.Console(0, this, "Unable to get LeftDisplay for Room"); } @@ -184,9 +186,11 @@ namespace PepperDash.Essentials.Room.Types var rightDisp = PropertiesConfig.Displays[eSourceListItemDestinationTypes.rightDisplay]; if (rightDisp != null) { - if (!string.IsNullOrEmpty(rightDisp.Key)) + { LeftDisplay = DeviceManager.GetDeviceForKey(rightDisp.Key) as IRoutingSinkWithSwitching; + Displays.Add(eSourceListItemDestinationTypes.rightDisplay, RightDisplay); + } else Debug.Console(0, this, "Unable to get LeftDisplay for Room"); } diff --git a/PepperDashEssentials/Room/Types/EssentialsNDisplayRoomBase.cs b/PepperDashEssentials/Room/Types/EssentialsNDisplayRoomBase.cs index 677c4048..85f52c9f 100644 --- a/PepperDashEssentials/Room/Types/EssentialsNDisplayRoomBase.cs +++ b/PepperDashEssentials/Room/Types/EssentialsNDisplayRoomBase.cs @@ -12,21 +12,21 @@ using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Room.Config; -namespace PepperDash.Essentials.Room.Types +namespace PepperDash.Essentials { /// /// Base class for rooms with more than a single display /// - public abstract class EssentialsNDisplayRoomBase : EssentialsRoomBase + public abstract class EssentialsNDisplayRoomBase : EssentialsRoomBase, IHasMultipleDisplays { //public event SourceInfoChangeHandler CurrentSingleSourceChange; + public Dictionary Displays { get; protected set;} public EssentialsNDisplayRoomBase(DeviceConfig config) : base (config) { - - var propertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); + Displays = new Dictionary(); } } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Essentials/EssentialsConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Essentials/EssentialsConfig.cs index 69f162d0..cc3375e2 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Essentials/EssentialsConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Config/Essentials/EssentialsConfig.cs @@ -21,8 +21,6 @@ namespace PepperDash.Essentials.Core.Config public string TemplateUrl { get; set; } - //public CotijaConfig Cotija { get; private set; } - [JsonProperty("systemUuid")] public string SystemUuid { diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs index 745f161d..36f390c3 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs @@ -22,6 +22,14 @@ namespace PepperDash.Essentials.Core IRoutingSinkWithSwitching DefaultDisplay { get; } } + /// + /// For rooms with multiple displays + /// + public interface IHasMultipleDisplays + { + Dictionary Displays { get; } + } + /// /// For rooms with routing /// @@ -30,8 +38,6 @@ namespace PepperDash.Essentials.Core void RunRouteAction(string routeKey); void RunRouteAction(string routeKey, Action successCallback); - - } /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingInterfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingInterfaces.cs index 118bdc0a..0c642d5c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingInterfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingInterfaces.cs @@ -31,7 +31,6 @@ namespace PepperDash.Essentials.Core event SourceInfoChangeHandler CurrentSourceChange; } - /// /// Defines a class that has a collection of RoutingInputPorts /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingPort.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingPort.cs index a6a16e08..fe7a0015 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingPort.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingPort.cs @@ -32,10 +32,10 @@ namespace PepperDash.Essentials.Core public enum eRoutingSignalType { Audio = 1, - Video = 2, - //AudioVideo = 4, - UsbOutput = 4, - UsbInput = 8 + Video = 2, + AudioVideo = 4, + UsbOutput = 8, + UsbInput = 16 } public enum eRoutingPortConnectionType diff --git a/essentials-framework/pepperdashcore-builds b/essentials-framework/pepperdashcore-builds index 07f4c597..45949f09 160000 --- a/essentials-framework/pepperdashcore-builds +++ b/essentials-framework/pepperdashcore-builds @@ -1 +1 @@ -Subproject commit 07f4c5975f72eeccc650cda24872d74364f6be35 +Subproject commit 45949f09bdcf6548be7fdf5c860ea4e3a5cf152d