From b295f931a39a950fe35a6630663560258d2aa890 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Tue, 4 Sep 2018 14:31:29 -0600 Subject: [PATCH 01/19] ? --- .../AppServer/CotijaSystemController.cs | 41 ++++++++++++++++++- .../RoomBridges/CotijaDdvc01RoomBridge.cs | 2 + .../CotijaEssentialsHuddleSpaceRoomBridge.cs | 2 +- .../Properties/AssemblyInfo.cs | 2 +- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index 338d325b..0564a048 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -474,6 +474,8 @@ namespace PepperDash.Essentials WSClient = new WebSocketClient(); } WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); + WSClient.ConnectionCallBack = ConnectCallback; + WSClient.DisconnectCallBack = DisconnectCallback; WSClient.Connect(); Debug.Console(0, this, "Websocket connected"); WSClient.ReceiveCallBack = WebsocketReceiveCallback; @@ -481,6 +483,43 @@ namespace PepperDash.Essentials WSClient.ReceiveAsync(); } + /// + /// Waits two and goes again + /// + void ReconnectStreamClient() + { + WSClient = null; + new CTimer(o => ConnectStreamClient(), 2000); + } + + /// + /// + /// + /// + /// + int ConnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code) + { + if (code != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) + { + Debug.Console(1, this, "Web socket connection failed: {0}", code); + ReconnectStreamClient(); + } + return 0; + } + + /// + /// + /// + /// + /// + int DisconnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code, object o) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Websocket disconnected with code: {0}", code); + ReconnectStreamClient(); + return 0; + } + + /// /// Resets reconnect timer and updates usercode /// @@ -619,7 +658,7 @@ namespace PepperDash.Essentials } case "held": { - if (!PushedActions.ContainsKey(type)) + if (PushedActions.ContainsKey(type)) { PushedActions[type].Reset(ButtonHeartbeatInterval, ButtonHeartbeatInterval); } diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index c47d11b3..699b5d84 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -422,6 +422,7 @@ namespace PepperDash.Essentials.Room.Cotija break; var icon = EISC.StringOutput[651 + i].StringValue; var key = EISC.StringOutput[671 + i].StringValue; + var type = EISC.StringOutput[701 + i].StringValue; Debug.Console(0, this, "Adding source {0} '{1}'", key, name); @@ -430,6 +431,7 @@ namespace PepperDash.Essentials.Room.Cotija Name = name, Order = (int)i + 1, SourceKey = key, + Type = eSourceListItemType.Route }; newSl.Add(key, newSLI); diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs index 24f2340a..815aa3e8 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs @@ -74,7 +74,7 @@ namespace PepperDash.Essentials { Parent.AddAction(string.Format(@"/room/{0}/volumes/master/level", Room.Key), new Action(u => (volumeRoom.CurrentVolumeControls as IBasicVolumeWithFeedback).SetVolume(u))); - Parent.AddAction(string.Format(@"/room/{0}/volumes/master/mute", Room.Key), new Action(() => + Parent.AddAction(string.Format(@"/room/{0}/volumes/master/muteToggle", Room.Key), new Action(() => volumeRoom.CurrentVolumeControls.MuteToggle())); volumeRoom.CurrentVolumeDeviceChange += new EventHandler(Room_CurrentVolumeDeviceChange); diff --git a/PepperDashEssentials/Properties/AssemblyInfo.cs b/PepperDashEssentials/Properties/AssemblyInfo.cs index b603f138..36c70ef4 100644 --- a/PepperDashEssentials/Properties/AssemblyInfo.cs +++ b/PepperDashEssentials/Properties/AssemblyInfo.cs @@ -4,5 +4,5 @@ [assembly: AssemblyCompany("PepperDash Technology Corp")] [assembly: AssemblyProduct("PepperDashEssentials")] [assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2018")] -[assembly: AssemblyVersion("1.2.5.*")] +[assembly: AssemblyVersion("1.2.6.*")] From 5ed8ff6dace5ddcd4434d91243b6e732659d495f Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Tue, 4 Sep 2018 15:39:58 -0600 Subject: [PATCH 02/19] Fixed scope issue joining sources to EISC --- .../AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index 699b5d84..25c122df 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -260,7 +260,8 @@ namespace PepperDash.Essentials.Room.Cotija foreach (var item in sourceJoinMap) { - Parent.AddAction(string.Format("{0}{1}", prefix, item.Key), new PressAndHoldAction(b => EISC.SetBool(item.Value, b))); + var join = item.Value; + Parent.AddAction(string.Format("{0}{1}", prefix, item.Key), new PressAndHoldAction(b => EISC.SetBool(join, b))); } } From 42086f650d2c4ca86f18e2a1e6a8892ce7097b43 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Fri, 7 Sep 2018 18:09:59 -0600 Subject: [PATCH 03/19] Weil-related changes; app server, many websocket and http client related changes to imrpove connection resilience; Added newer pd.core 1.0.9 --- .../AppServer/CotijaSystemController.cs | 156 +++++++++++++----- ...lsHuddleSpaceFusionSystemControllerBase.cs | 9 +- .../EssentialsHuddleVtc1FusionController.cs | 4 +- 3 files changed, 127 insertions(+), 42 deletions(-) diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index 0564a048..bf3c3598 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -23,6 +23,8 @@ namespace PepperDash.Essentials { WebSocketClient WSClient; + bool LinkUp; + /// /// Prevents post operations from stomping on each other and getting lost /// @@ -86,8 +88,25 @@ namespace PepperDash.Essentials CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); + } + /// + /// + /// + /// + void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Ethernet status change, port {0}: {1}", + ethernetEventArgs.EthernetAdapter, ethernetEventArgs.EthernetEventType); + + if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkDown) + { + LinkUp = false; + } + } + /// /// Sends message to server to indicate the system is shutting down /// @@ -280,8 +299,6 @@ namespace PepperDash.Essentials /// URL of the server, including the port number, if not 80. Format: "serverUrlOrIp:port" void RegisterSystemToServer() { - - var ready = RegisterLockEvent.Wait(20000); if (!ready) { @@ -318,14 +335,20 @@ namespace PepperDash.Essentials request.RequestType = RequestType.Post; request.Header.SetHeaderValue("Content-Type", "application/json"); request.ContentString = postBody; - - var err = regClient.DispatchAsync(request, RegistrationConnectionCallback); + try + { + regClient.DispatchAsync(request, RegistrationConnectionCallback); + } + catch (Exception e) + { + Debug.Console(1, this, "Cannot register with app server: {0}", e); + } } } catch (Exception e) { - Debug.Console(0, this, "ERROR: Initilizing Room: {0}", e); + Debug.Console(0, this, "ERROR: Initilizing app server controller: {0}", e); RegisterLockEvent.Set(); StartReconnectTimer(); } @@ -345,8 +368,8 @@ namespace PepperDash.Essentials string message = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); Debug.Console(1, this, "Message TX: {0}", message); var messageBytes = System.Text.Encoding.UTF8.GetBytes(message); - WSClient.Send(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); - //WSClient.SendAsync(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); + //WSClient.Send(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); + WSClient.SendAsync(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); } } @@ -355,20 +378,18 @@ namespace PepperDash.Essentials /// Disconnects the SSE Client and stops the heartbeat timer /// /// - void DisconnectStreamClient(string command) + void DisconnectWebsocketClient() { - //if(SseClient != null) - // SseClient.Disconnect(); - - if (WSClient != null && WSClient.Connected) + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting websocket"); + if (WSClient != null) // && WSClient.Connected) + { WSClient.Disconnect(); - - if (ServerHeartbeatCheckTimer != null) - { - ServerHeartbeatCheckTimer.Stop(); - - ServerHeartbeatCheckTimer = null; - } + WSClient.SendCallBack = null; + WSClient.ReceiveCallBack = null; + WSClient.ConnectionCallBack = null; + WSClient.Dispose(); + WSClient = null; + } } /// @@ -396,10 +417,19 @@ namespace PepperDash.Essentials else { if (resp != null) - Debug.Console(1, this, "Response from server: {0}\n{1}", resp.Code, err); + { + if (resp.Code == 502) + { + Debug.Console(1, this, "Cannot reach App Server behind web server. Check that service/app is running on server"); + } + else + { + Debug.Console(1, this, "Error response from server: {0}\n{1}", resp.Code, err); + } + } else { - Debug.Console(1, this, "Null response received from server."); + Debug.Console(1, this, "No response. Server is likely unreachable"); } StartReconnectTimer(); } @@ -424,6 +454,7 @@ namespace PepperDash.Essentials ServerHeartbeatCheckTimer.Stop(); ServerHeartbeatCheckTimer = null; } + DisconnectWebsocketClient(); StartReconnectTimer(); } @@ -461,25 +492,55 @@ namespace PepperDash.Essentials } - /// - /// Connects the SSE Client +#warning notes here + + /* + * Need to understand why this is being sent from a server that should not have been closing, + * and also why essentials is not recovering + * + [17:36:09.044]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 +[17:36:13.086]App 10:[appServer] RegistrationConnectionCallback: COMPLETED +[17:36:13.088]App 10:[appServer] Response from server: 502COMPLETED +[17:36:18.113]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 +[17:36:22.159]App 10:[appServer] RegistrationConnectionCallback: COMPLETED +[17:36:22.160]App 10:[appServer] Response from server: 502COMPLETED +[17:36:27.005]App 10:[ciscoSparkCodec-1] Retrieving Booking Info from Codec. Current Time: 9/6/2018 5:36:27 PM +[17:36:27.187]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 +[17:36:31.233]App 10:[appServer] RegistrationConnectionCallback: COMPLETED +[17:36:31.234]App 10:[appServer] Response from server: 502COMPLETED +[17:36:36.338]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 +[17:36:42.151]App 10:[appServer] RegistrationConnectionCallback: COMPLETED +[17:36:42.153]App 10:[appServer] Initializing Stream client to server. +[17:36:42.887]App 10:[appServer] Websocket connected +[17:36:42.916]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 +[17:36:42.978]App 10:[appServer] RegistrationConnectionCallback: COMPLETED +[17:36:42.979]App 10:[appServer] Initializing Stream client to server. +[17:36:42.980]App 10:[appServer] Websocket connected +[17:36:42.990]App 10:[appServer] Message RX: '{"type":"close"}' + */ + + + /// + /// Connects the Websocket Client /// /// void ConnectStreamClient() { Debug.Console(0, this, "Initializing Stream client to server."); - if (WSClient == null) + if (WSClient != null) { - WSClient = new WebSocketClient(); + DisconnectWebsocketClient(); } + + WSClient = new WebSocketClient(); WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); WSClient.ConnectionCallBack = ConnectCallback; WSClient.DisconnectCallBack = DisconnectCallback; WSClient.Connect(); - Debug.Console(0, this, "Websocket connected"); + Debug.Console(1, this, "Websocket connected"); + WSClient.SendCallBack = WebsocketSendCallback; WSClient.ReceiveCallBack = WebsocketReceiveCallback; - //WSClient.SendCallBack = WebsocketSendCallback; WSClient.ReceiveAsync(); } @@ -488,7 +549,6 @@ namespace PepperDash.Essentials /// void ReconnectStreamClient() { - WSClient = null; new CTimer(o => ConnectStreamClient(), 2000); } @@ -499,6 +559,7 @@ namespace PepperDash.Essentials /// int ConnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code) { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Websocket status change: {0}", code); if (code != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) { Debug.Console(1, this, "Web socket connection failed: {0}", code); @@ -552,12 +613,26 @@ namespace PepperDash.Essentials { if (HttpDebugEnabled) { - Debug.Console(0, this, "------ Begin HTTP Debug ---------------------------------------"); - Debug.Console(0, this, "HTTP Response URL: {0}", r.ResponseUrl.ToString()); - Debug.Console(0, this, "HTTP Response 'error' {0}", e); - Debug.Console(0, this, "HTTP Response code: {0}", r.Code); - Debug.Console(0, this, "HTTP Response content: \r{0}", r.ContentString); - Debug.Console(0, this, "------ End HTTP Debug -----------------------------------------"); + 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); + } } } @@ -575,7 +650,7 @@ namespace PepperDash.Essentials if(rx.Length > 0) ParseStreamRx(rx); WSClient.ReceiveAsync(); - return 1; + return 0; } /// @@ -585,9 +660,11 @@ namespace PepperDash.Essentials /// int WebsocketSendCallback(Crestron.SimplSharp.CrestronWebSocketClient.WebSocketClient.WEBSOCKET_RESULT_CODES result) { - Debug.Console(1, this, "SendCallback result: {0}", result); + if(result != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SendCallback questionable result: {0}", result); + - return 1; + return 0; } /// @@ -617,9 +694,10 @@ namespace PepperDash.Essentials } else if (type == "close") { - WSClient.Disconnect(); + DisconnectWebsocketClient(); - ServerHeartbeatCheckTimer.Stop(); + if(ServerHeartbeatCheckTimer != null) + ServerHeartbeatCheckTimer.Stop(); // Start the reconnect timer StartReconnectTimer(); } diff --git a/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index a463fa50..f446a596 100644 --- a/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -17,6 +17,7 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials; using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Devices.Common; using PepperDash.Essentials.Devices.Common.Occupancy; @@ -334,6 +335,8 @@ namespace PepperDash.Essentials.Fusion FusionRoom.ErrorMessage.InputSig.StringValue = "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; + SetUpEthernetValues(); + GetProcessorEthernetValues(); GetSystemInfo(); @@ -363,7 +366,7 @@ namespace PepperDash.Essentials.Fusion systemReboot.OutputSig.SetSigFalseAction(() => CrestronConsole.SendControlSystemCommand("reboot", ref response)); } - protected void GetProcessorEthernetValues() + protected void SetUpEthernetValues() { Ip1 = FusionRoom.CreateOffsetStringSig(50, "Info - Processor - IP 1", eSigIoMask.InputSigOnly); Ip2 = FusionRoom.CreateOffsetStringSig(51, "Info - Processor - IP 2", eSigIoMask.InputSigOnly); @@ -376,8 +379,10 @@ namespace PepperDash.Essentials.Fusion Mac2 = FusionRoom.CreateOffsetStringSig(58, "Info - Processor - MAC 2", eSigIoMask.InputSigOnly); NetMask1 = FusionRoom.CreateOffsetStringSig(59, "Info - Processor - Net Mask 1", eSigIoMask.InputSigOnly); NetMask2 = FusionRoom.CreateOffsetStringSig(60, "Info - Processor - Net Mask 2", eSigIoMask.InputSigOnly); + } - // Interface =0 + protected void GetProcessorEthernetValues() + { Ip1.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); Gateway.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); Hostname.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); diff --git a/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleVtc1FusionController.cs b/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleVtc1FusionController.cs index 214e3537..dd374586 100644 --- a/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleVtc1FusionController.cs +++ b/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleVtc1FusionController.cs @@ -189,7 +189,9 @@ namespace PepperDash.Essentials.Fusion FusionRoom.ErrorMessage.InputSig.StringValue = "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; - GetProcessorEthernetValues(); + SetUpEthernetValues(); + + GetProcessorEthernetValues(); GetSystemInfo(); From 5f8170fb6640577d451e9fcc506bffd8bca0782b Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Fri, 7 Sep 2018 18:15:39 -0600 Subject: [PATCH 04/19] Commit of framework --- essentials-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework b/essentials-framework index f28c5903..fb02dac4 160000 --- a/essentials-framework +++ b/essentials-framework @@ -1 +1 @@ -Subproject commit f28c59035c5de92dc2c957ad2bd56ada4538d0f3 +Subproject commit fb02dac4bbf50cc5e17a41539be6b5b5ea8752f1 From f17b62844df96bd14340d3d27ffba326f04b475b Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Mon, 10 Sep 2018 07:48:14 -0600 Subject: [PATCH 05/19] Attempting to prevent deadlock/multiple connection attempts on reconnect --- .../AppServer/CotijaSystemController.cs | 82 +++++++------------ 1 file changed, 28 insertions(+), 54 deletions(-) diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index bf3c3598..5497c27c 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -302,8 +302,8 @@ namespace PepperDash.Essentials var ready = RegisterLockEvent.Wait(20000); if (!ready) { - Debug.Console(1, this, "RegisterSystemToServer failed to enter after 20 seconds. Ignoring"); - return; + Debug.Console(1, this, "RegisterSystemToServer event failed to clear after 20 seconds. Ignoring"); + //return; } RegisterLockEvent.Reset(); @@ -335,14 +335,8 @@ namespace PepperDash.Essentials request.RequestType = RequestType.Post; request.Header.SetHeaderValue("Content-Type", "application/json"); request.ContentString = postBody; - try - { - regClient.DispatchAsync(request, RegistrationConnectionCallback); - } - catch (Exception e) - { - Debug.Console(1, this, "Cannot register with app server: {0}", e); - } + + regClient.DispatchAsync(request, RegistrationConnectionCallback); } } @@ -400,7 +394,7 @@ namespace PepperDash.Essentials void RegistrationConnectionCallback(HttpClientResponse resp, HTTP_CALLBACK_ERROR err) { CheckHttpDebug(resp, err); - Debug.Console(1, this, "RegistrationConnectionCallback: {0}", err); + //Debug.Console(2, this, "RegistrationConnectionCallback: {0}", err); try { if (resp != null && resp.Code == 200) @@ -438,8 +432,8 @@ namespace PepperDash.Essentials { Debug.Console(1, this, "Error Initializing Stream Client: {0}", e); StartReconnectTimer(); + RegisterLockEvent.Set(); } - RegisterLockEvent.Set(); } /// @@ -448,7 +442,7 @@ namespace PepperDash.Essentials /// For CTimer callback. Not used void HeartbeatExpiredTimerCallback(object o) { - Debug.Console(1, this, "Heartbeat Timer Expired."); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Heartbeat Timer Expired."); if (ServerHeartbeatCheckTimer != null) { ServerHeartbeatCheckTimer.Stop(); @@ -491,57 +485,30 @@ namespace PepperDash.Essentials ServerHeartbeatCheckTimer.Reset(ServerHeartbeatInterval, ServerHeartbeatInterval); } - -#warning notes here - - /* - * Need to understand why this is being sent from a server that should not have been closing, - * and also why essentials is not recovering - * - [17:36:09.044]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 -[17:36:13.086]App 10:[appServer] RegistrationConnectionCallback: COMPLETED -[17:36:13.088]App 10:[appServer] Response from server: 502COMPLETED -[17:36:18.113]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 -[17:36:22.159]App 10:[appServer] RegistrationConnectionCallback: COMPLETED -[17:36:22.160]App 10:[appServer] Response from server: 502COMPLETED -[17:36:27.005]App 10:[ciscoSparkCodec-1] Retrieving Booking Info from Codec. Current Time: 9/6/2018 5:36:27 PM -[17:36:27.187]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 -[17:36:31.233]App 10:[appServer] RegistrationConnectionCallback: COMPLETED -[17:36:31.234]App 10:[appServer] Response from server: 502COMPLETED -[17:36:36.338]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 -[17:36:42.151]App 10:[appServer] RegistrationConnectionCallback: COMPLETED -[17:36:42.153]App 10:[appServer] Initializing Stream client to server. -[17:36:42.887]App 10:[appServer] Websocket connected -[17:36:42.916]App 10:[appServer] Joining server at http://bosd-node01.pepperdash.net/mobilecontrolapi/api/system/join/02cf80a1-ce35-482c-8fa6-286457ff2826 -[17:36:42.978]App 10:[appServer] RegistrationConnectionCallback: COMPLETED -[17:36:42.979]App 10:[appServer] Initializing Stream client to server. -[17:36:42.980]App 10:[appServer] Websocket connected -[17:36:42.990]App 10:[appServer] Message RX: '{"type":"close"}' - */ - - /// /// Connects the Websocket Client /// /// void ConnectStreamClient() { - Debug.Console(0, this, "Initializing Stream client to server."); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Initializing Stream client to server."); if (WSClient != null) { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Cleaning up previous socket"); DisconnectWebsocketClient(); } WSClient = new WebSocketClient(); WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); - WSClient.ConnectionCallBack = ConnectCallback; - WSClient.DisconnectCallBack = DisconnectCallback; + WSClient.ConnectionCallBack = Websocket_ConnectCallback; + WSClient.DisconnectCallBack = Websocket_DisconnectCallback; WSClient.Connect(); Debug.Console(1, this, "Websocket connected"); WSClient.SendCallBack = WebsocketSendCallback; WSClient.ReceiveCallBack = WebsocketReceiveCallback; WSClient.ReceiveAsync(); + RegisterLockEvent.Set(); } /// @@ -557,13 +524,13 @@ namespace PepperDash.Essentials /// /// /// - int ConnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code) + int Websocket_ConnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code) { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Websocket status change: {0}", code); if (code != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) { - Debug.Console(1, this, "Web socket connection failed: {0}", code); - ReconnectStreamClient(); + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failed: {0}", code); + //ReconnectStreamClient(); } return 0; } @@ -573,10 +540,16 @@ namespace PepperDash.Essentials /// /// /// - int DisconnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code, object o) + int Websocket_DisconnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code, object o) { Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Websocket disconnected with code: {0}", code); - ReconnectStreamClient(); + + if (ServerHeartbeatCheckTimer != null) + ServerHeartbeatCheckTimer.Stop(); + // Start the reconnect timer + StartReconnectTimer(); + + //ReconnectStreamClient(); return 0; } @@ -694,12 +667,13 @@ namespace PepperDash.Essentials } else if (type == "close") { - DisconnectWebsocketClient(); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Received close message from server."); + // DisconnectWebsocketClient(); - if(ServerHeartbeatCheckTimer != null) + if (ServerHeartbeatCheckTimer != null) ServerHeartbeatCheckTimer.Stop(); - // Start the reconnect timer - StartReconnectTimer(); + //// Start the reconnect timer + //StartReconnectTimer(); } else { From a0a83a1af7783fd5c8f62ff324c00b01193e4fa5 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Mon, 10 Sep 2018 13:00:03 -0600 Subject: [PATCH 06/19] Removed HTTP join procedure; rehashed reconnects --- .../AppServer/CotijaSystemController.cs | 378 ++++++++++-------- 1 file changed, 206 insertions(+), 172 deletions(-) diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index 5497c27c..abaa9a0d 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -23,7 +23,7 @@ namespace PepperDash.Essentials { WebSocketClient WSClient; - bool LinkUp; + //bool LinkUp; /// /// Prevents post operations from stomping on each other and getting lost @@ -84,8 +84,12 @@ namespace PepperDash.Essentials CrestronConsole.AddNewConsoleCommand(TestHttpRequest, "mobilehttprequest", "Tests an HTTP get to URL given", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(PrintActionDictionaryPaths, "showactionpaths", "Prints the paths in teh Action Dictionary", ConsoleAccessLevelEnum.AccessOperator); - + CrestronConsole.AddNewConsoleCommand(PrintActionDictionaryPaths, "mobileshowactionpaths", + "Prints the paths in teh Action Dictionary", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => ConnectStreamClient(), "mobileconnect", + "Forces connect of websocket", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => DisconnectWebsocketClient(), "mobiledisco", + "Disconnects websocket", ConsoleAccessLevelEnum.AccessOperator); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); @@ -101,10 +105,10 @@ namespace PepperDash.Essentials Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Ethernet status change, port {0}: {1}", ethernetEventArgs.EthernetAdapter, ethernetEventArgs.EthernetEventType); - if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkDown) - { - LinkUp = false; - } + //if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkDown) + //{ + // LinkUp = false; + //} } /// @@ -115,11 +119,7 @@ namespace PepperDash.Essentials { if (programEventType == eProgramStatusEventType.Stopping && WSClient.Connected) { - SendMessageToServer(JObject.FromObject( new - { - type = "/system/close" - })); - + DisconnectWebsocketClient(); } } @@ -299,56 +299,181 @@ namespace PepperDash.Essentials /// URL of the server, including the port number, if not 80. Format: "serverUrlOrIp:port" void RegisterSystemToServer() { - var ready = RegisterLockEvent.Wait(20000); - if (!ready) - { - Debug.Console(1, this, "RegisterSystemToServer event failed to clear after 20 seconds. Ignoring"); - //return; - } - RegisterLockEvent.Reset(); + ConnectStreamClient(); + return; - try - { - 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 ready = RegisterLockEvent.Wait(20000); + //if (!ready) + //{ + // Debug.Console(1, this, "RegisterSystemToServer event failed to clear after 20 seconds. Ignoring"); + // //return; + //} + //RegisterLockEvent.Reset(); - string postBody = JsonConvert.SerializeObject(confObject); - SystemUuid = confObject.SystemUuid; + //try + //{ + // 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); - if (string.IsNullOrEmpty(postBody)) - { - Debug.Console(1, this, "ERROR: Config body is empty. Cannot register with server."); - } - else - { - var regClient = new HttpClient(); - regClient.Verbose = true; - regClient.KeepAlive = true; + // string postBody = JsonConvert.SerializeObject(confObject); + // SystemUuid = confObject.SystemUuid; - string url = string.Format("http://{0}/api/system/join/{1}", Config.ServerUrl, SystemUuid); - Debug.Console(1, this, "Joining server at {0}", url); + // if (string.IsNullOrEmpty(postBody)) + // { + // Debug.Console(1, this, "ERROR: Config body is empty. Cannot register with server."); + // } + // else + // { + // var regClient = new HttpClient(); + // regClient.Verbose = true; + // regClient.KeepAlive = true; - HttpClientRequest request = new HttpClientRequest(); - request.Url.Parse(url); - request.RequestType = RequestType.Post; - request.Header.SetHeaderValue("Content-Type", "application/json"); - request.ContentString = postBody; + // string url = string.Format("http://{0}/api/system/join/{1}", Config.ServerUrl, SystemUuid); + // Debug.Console(1, this, "Joining server at {0}", url); - regClient.DispatchAsync(request, RegistrationConnectionCallback); - } + // HttpClientRequest request = new HttpClientRequest(); + // request.Url.Parse(url); + // request.RequestType = RequestType.Post; + // request.Header.SetHeaderValue("Content-Type", "application/json"); + // request.ContentString = postBody; - } - catch (Exception e) - { - Debug.Console(0, this, "ERROR: Initilizing app server controller: {0}", e); - RegisterLockEvent.Set(); - StartReconnectTimer(); - } + // regClient.DispatchAsync(request, RegistrationConnectionCallback); + // } + + //} + //catch (Exception e) + //{ + // Debug.Console(0, this, "ERROR: Initilizing app server controller: {0}", e); + // RegisterLockEvent.Set(); + // StartReconnectTimer(); + //} } + ///// + ///// The callback that fires when we get a response from our registration attempt + ///// + ///// + ///// + //void RegistrationConnectionCallback(HttpClientResponse resp, HTTP_CALLBACK_ERROR err) + //{ + // CheckHttpDebug(resp, err); + // try + // { + // if (resp != null && resp.Code == 200) + // { + // StopReconnectTimer(); + + // // Success here! + // ConnectStreamClient(); + // } + // else + // { + // if (resp != null) + // { + // if (resp.Code == 502) + // { + // Debug.Console(1, this, "Cannot reach App Server behind web server. Check that service/app is running on server"); + // } + // else + // { + // Debug.Console(1, this, "Error response from server: {0}\n{1}", resp.Code, err); + // } + // } + // else + // { + // Debug.Console(1, this, "No response. Server is likely unreachable"); + // } + // StartReconnectTimer(); + // } + // } + // catch (Exception e) + // { + // Debug.Console(1, this, "Error Initializing Stream Client: {0}", e); + // StartReconnectTimer(); + // RegisterLockEvent.Set(); + // } + //} + + /// + /// Connects the Websocket Client + /// + /// + void ConnectStreamClient() + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Initializing Stream client to server."); + + if (WSClient != null) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Cleaning up previous socket"); + DisconnectWebsocketClient(); + } + + SystemUuid = ConfigReader.ConfigObject.SystemUuid; + + WSClient = new WebSocketClient(); + WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); + WSClient.ConnectionCallBack = Websocket_ConnectCallback; + WSClient.DisconnectCallBack = Websocket_DisconnectCallback; + 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.SendCallBack = Websocket_SendCallback; + WSClient.ReceiveCallBack = Websocket_ReceiveCallback; + WSClient.ReceiveAsync(); + } + else + { + Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failed: {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 /// @@ -356,16 +481,13 @@ namespace PepperDash.Essentials /// 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 }); Debug.Console(1, this, "Message TX: {0}", message); var messageBytes = System.Text.Encoding.UTF8.GetBytes(message); - //WSClient.Send(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); WSClient.SendAsync(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); } - } /// @@ -375,66 +497,39 @@ namespace PepperDash.Essentials void DisconnectWebsocketClient() { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting websocket"); - if (WSClient != null) // && WSClient.Connected) + if (WSClient != null) { WSClient.Disconnect(); WSClient.SendCallBack = null; WSClient.ReceiveCallBack = null; WSClient.ConnectionCallBack = null; - WSClient.Dispose(); WSClient = null; } } - - /// - /// The callback that fires when we get a response from our registration attempt - /// - /// - /// - void RegistrationConnectionCallback(HttpClientResponse resp, HTTP_CALLBACK_ERROR err) - { - CheckHttpDebug(resp, err); - //Debug.Console(2, this, "RegistrationConnectionCallback: {0}", err); - try - { - if (resp != null && resp.Code == 200) - { - if(ServerReconnectTimer != null) - { - ServerReconnectTimer.Stop(); - ServerReconnectTimer = null; - } - // Success here! - ConnectStreamClient(); - } - else - { - if (resp != null) - { - if (resp.Code == 502) - { - Debug.Console(1, this, "Cannot reach App Server behind web server. Check that service/app is running on server"); - } - else - { - Debug.Console(1, this, "Error response from server: {0}\n{1}", resp.Code, err); - } - } - else - { - Debug.Console(1, this, "No response. Server is likely unreachable"); - } - StartReconnectTimer(); - } - } - catch (Exception e) - { - Debug.Console(1, this, "Error Initializing Stream Client: {0}", e); - StartReconnectTimer(); - RegisterLockEvent.Set(); - } - } + /// + /// + /// + /// + /// + 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. @@ -449,23 +544,7 @@ namespace PepperDash.Essentials ServerHeartbeatCheckTimer = null; } DisconnectWebsocketClient(); - StartReconnectTimer(); - } - - /// - /// - /// - /// - /// - void StartReconnectTimer() - { - // Start the reconnect timer - if (ServerReconnectTimer == null) - { - ServerReconnectTimer = new CTimer(ReconnectToServerTimerCallback, null, ServerReconnectInterval, ServerReconnectInterval); - Debug.Console(1, this, "Reconnect Timer Started."); - } - ServerReconnectTimer.Reset(ServerReconnectInterval, ServerReconnectInterval); + StartServerReconnectTimer(); } /// @@ -485,32 +564,6 @@ namespace PepperDash.Essentials ServerHeartbeatCheckTimer.Reset(ServerHeartbeatInterval, ServerHeartbeatInterval); } - /// - /// Connects the Websocket Client - /// - /// - void ConnectStreamClient() - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Initializing Stream client to server."); - - if (WSClient != null) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Cleaning up previous socket"); - DisconnectWebsocketClient(); - } - - WSClient = new WebSocketClient(); - WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); - WSClient.ConnectionCallBack = Websocket_ConnectCallback; - WSClient.DisconnectCallBack = Websocket_DisconnectCallback; - WSClient.Connect(); - Debug.Console(1, this, "Websocket connected"); - WSClient.SendCallBack = WebsocketSendCallback; - WSClient.ReceiveCallBack = WebsocketReceiveCallback; - WSClient.ReceiveAsync(); - RegisterLockEvent.Set(); - } - /// /// Waits two and goes again /// @@ -519,22 +572,6 @@ namespace PepperDash.Essentials new CTimer(o => ConnectStreamClient(), 2000); } - /// - /// - /// - /// - /// - int Websocket_ConnectCallback(WebSocketClient.WEBSOCKET_RESULT_CODES code) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Websocket status change: {0}", code); - if (code != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failed: {0}", code); - //ReconnectStreamClient(); - } - return 0; - } - /// /// /// @@ -547,9 +584,7 @@ namespace PepperDash.Essentials if (ServerHeartbeatCheckTimer != null) ServerHeartbeatCheckTimer.Stop(); // Start the reconnect timer - StartReconnectTimer(); - - //ReconnectStreamClient(); + StartServerReconnectTimer(); return 0; } @@ -616,7 +651,7 @@ namespace PepperDash.Essentials /// /// /// - int WebsocketReceiveCallback(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode, + int Websocket_ReceiveCallback(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode, WebSocketClient.WEBSOCKET_RESULT_CODES err) { var rx = System.Text.Encoding.UTF8.GetString(data, 0, (int)length); @@ -631,7 +666,7 @@ namespace PepperDash.Essentials /// /// /// - int WebsocketSendCallback(Crestron.SimplSharp.CrestronWebSocketClient.WebSocketClient.WEBSOCKET_RESULT_CODES result) + 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); @@ -659,6 +694,7 @@ namespace PepperDash.Essentials if (type == "hello") { + SendInitialMessage(); ResetOrStartHearbeatTimer(); } else if (type == "/system/heartbeat") @@ -672,8 +708,6 @@ namespace PepperDash.Essentials if (ServerHeartbeatCheckTimer != null) ServerHeartbeatCheckTimer.Stop(); - //// Start the reconnect timer - //StartReconnectTimer(); } else { From 1c9061cc280dfeb84cfed19d02542ea912315ba0 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Mon, 10 Sep 2018 13:49:56 -0600 Subject: [PATCH 07/19] Strengthened reconnect behavior with both app server and IIS outages --- .../AppServer/CotijaSystemController.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index abaa9a0d..c7856753 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -416,7 +416,6 @@ namespace PepperDash.Essentials WSClient = new WebSocketClient(); WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); WSClient.ConnectionCallBack = Websocket_ConnectCallback; - WSClient.DisconnectCallBack = Websocket_DisconnectCallback; WSClient.ConnectAsync(); } @@ -431,15 +430,30 @@ namespace PepperDash.Essentials { StopServerReconnectTimer(); Debug.Console(1, this, "Websocket connected"); + WSClient.DisconnectCallBack = Websocket_DisconnectCallback; WSClient.SendCallBack = Websocket_SendCallback; WSClient.ReceiveCallBack = Websocket_ReceiveCallback; WSClient.ReceiveAsync(); } else { - Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Web socket connection failed: {0}", code); + 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; } @@ -670,8 +684,6 @@ namespace PepperDash.Essentials { if(result != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SendCallback questionable result: {0}", result); - - return 0; } From 1df658b7eb99c6d2b3884379cd9692b8e5745277 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Mon, 10 Sep 2018 20:23:57 -0600 Subject: [PATCH 08/19] Added close handlers to catch legit shutdowns from servers --- .../AppServer/CotijaSystemController.cs | 73 ++++++++++++------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index c7856753..79a4ba46 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -86,9 +86,9 @@ namespace PepperDash.Essentials CrestronConsole.AddNewConsoleCommand(PrintActionDictionaryPaths, "mobileshowactionpaths", "Prints the paths in teh Action Dictionary", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(s => ConnectStreamClient(), "mobileconnect", + CrestronConsole.AddNewConsoleCommand(s => ConnectWebsocketClient(), "mobileconnect", "Forces connect of websocket", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(s => DisconnectWebsocketClient(), "mobiledisco", + CrestronConsole.AddNewConsoleCommand(s => CleanUpWebsocketClient(), "mobiledisco", "Disconnects websocket", ConsoleAccessLevelEnum.AccessOperator); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); @@ -100,15 +100,15 @@ namespace PepperDash.Essentials /// /// /// - void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) + void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs args) { Debug.Console(1, this, Debug.ErrorLogLevel.Warning, "Ethernet status change, port {0}: {1}", - ethernetEventArgs.EthernetAdapter, ethernetEventArgs.EthernetEventType); + args.EthernetAdapter, args.EthernetEventType); - //if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkDown) - //{ - // LinkUp = false; - //} + if (args.EthernetEventType == eEthernetEventType.LinkDown && WSClient != null && args.EthernetAdapter == WSClient.EthernetAdapter) + { + CleanUpWebsocketClient(); + } } /// @@ -119,7 +119,7 @@ namespace PepperDash.Essentials { if (programEventType == eProgramStatusEventType.Stopping && WSClient.Connected) { - DisconnectWebsocketClient(); + CleanUpWebsocketClient(); } } @@ -299,7 +299,7 @@ namespace PepperDash.Essentials /// URL of the server, including the port number, if not 80. Format: "serverUrlOrIp:port" void RegisterSystemToServer() { - ConnectStreamClient(); + ConnectWebsocketClient(); return; //var ready = RegisterLockEvent.Wait(20000); @@ -401,14 +401,14 @@ namespace PepperDash.Essentials /// Connects the Websocket Client /// /// - void ConnectStreamClient() + void ConnectWebsocketClient() { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Initializing Stream client to server."); if (WSClient != null) { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Cleaning up previous socket"); - DisconnectWebsocketClient(); + CleanUpWebsocketClient(); } SystemUuid = ConfigReader.ConfigObject.SystemUuid; @@ -508,15 +508,19 @@ namespace PepperDash.Essentials /// Disconnects the SSE Client and stops the heartbeat timer /// /// - void DisconnectWebsocketClient() + void CleanUpWebsocketClient() { Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting websocket"); if (WSClient != null) { - WSClient.Disconnect(); WSClient.SendCallBack = null; WSClient.ReceiveCallBack = null; WSClient.ConnectionCallBack = null; + WSClient.DisconnectCallBack = null; + if (WSClient.Connected) + { + WSClient.Disconnect(); + } WSClient = null; } } @@ -557,7 +561,7 @@ namespace PepperDash.Essentials ServerHeartbeatCheckTimer.Stop(); ServerHeartbeatCheckTimer = null; } - DisconnectWebsocketClient(); + CleanUpWebsocketClient(); StartServerReconnectTimer(); } @@ -568,14 +572,15 @@ namespace PepperDash.Essentials /// void ResetOrStartHearbeatTimer() { - if (ServerHeartbeatCheckTimer == null) - { + if (ServerHeartbeatCheckTimer == null) + { ServerHeartbeatCheckTimer = new CTimer(HeartbeatExpiredTimerCallback, null, ServerHeartbeatInterval, ServerHeartbeatInterval); - - Debug.Console(1, this, "Heartbeat Timer Started."); - } - - ServerHeartbeatCheckTimer.Reset(ServerHeartbeatInterval, ServerHeartbeatInterval); + Debug.Console(1, this, "Heartbeat Timer Started."); + } + else + { + ServerHeartbeatCheckTimer.Reset(ServerHeartbeatInterval, ServerHeartbeatInterval); + } } /// @@ -583,7 +588,7 @@ namespace PepperDash.Essentials /// void ReconnectStreamClient() { - new CTimer(o => ConnectStreamClient(), 2000); + new CTimer(o => ConnectWebsocketClient(), 2000); } /// @@ -668,10 +673,24 @@ namespace PepperDash.Essentials int Websocket_ReceiveCallback(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode, WebSocketClient.WEBSOCKET_RESULT_CODES err) { - var rx = System.Text.Encoding.UTF8.GetString(data, 0, (int)length); - if(rx.Length > 0) - ParseStreamRx(rx); - WSClient.ReceiveAsync(); + 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; } From a2a3f4caede4f123ddbda5c3f238f489e434c518 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Tue, 11 Sep 2018 08:13:14 -0600 Subject: [PATCH 09/19] Clean up extra verbose logging after solidifying reconnection --- .../AppServer/CotijaSystemController.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index 79a4ba46..f72857d1 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -403,11 +403,11 @@ namespace PepperDash.Essentials /// void ConnectWebsocketClient() { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Initializing Stream client to server."); + Debug.Console(1, this, "Initializing Stream client to server."); if (WSClient != null) { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Cleaning up previous socket"); + Debug.Console(1, this, "Cleaning up previous socket"); CleanUpWebsocketClient(); } @@ -510,7 +510,7 @@ namespace PepperDash.Essentials /// void CleanUpWebsocketClient() { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Disconnecting websocket"); + Debug.Console(1, this, "Disconnecting websocket"); if (WSClient != null) { WSClient.SendCallBack = null; @@ -555,7 +555,7 @@ namespace PepperDash.Essentials /// For CTimer callback. Not used void HeartbeatExpiredTimerCallback(object o) { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Heartbeat Timer Expired."); + Debug.Console(1, this, "Heartbeat Timer Expired."); if (ServerHeartbeatCheckTimer != null) { ServerHeartbeatCheckTimer.Stop(); @@ -734,7 +734,7 @@ namespace PepperDash.Essentials } else if (type == "close") { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Received close message from server."); + Debug.Console(1, this, "Received close message from server."); // DisconnectWebsocketClient(); if (ServerHeartbeatCheckTimer != null) From 873fd81b5c7fc1b7bec329849cb36fde5dfdb6b1 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Tue, 11 Sep 2018 10:04:41 -0600 Subject: [PATCH 10/19] Added debug command to log marker in log --- PepperDashEssentials/ControlSystem.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index d25711ed..72954503 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -35,6 +35,11 @@ namespace PepperDash.Essentials //CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file", // ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "CONSOLE MESSAGE: {0}", s); + }, "appdebugmessage", "Writes message to log", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => { foreach (var tl in TieLineCollection.Default) From ee6293fa7511347ab3b9c83517872241bd565e7e Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Wed, 12 Sep 2018 13:53:35 -0600 Subject: [PATCH 11/19] Added MessengerBase class to app server stuff --- .../AppServer/Messengers/MessengerBase.cs | 72 +++++++++++++++++++ .../Messengers/VideoCodecBaseMessenger.cs | 33 ++------- .../PepperDashEssentials.csproj | 1 + 3 files changed, 77 insertions(+), 29 deletions(-) create mode 100644 PepperDashEssentials/AppServer/Messengers/MessengerBase.cs diff --git a/PepperDashEssentials/AppServer/Messengers/MessengerBase.cs b/PepperDashEssentials/AppServer/Messengers/MessengerBase.cs new file mode 100644 index 00000000..125bf83a --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/MessengerBase.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.VideoCodec; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + /// + /// Provides a messaging bridge for a VideoCodecBase + /// + public abstract class MessengerBase + { + /// + /// + /// + public CotijaSystemController AppServerController { get; private set; } + + public string MessagePath { get; private set; } + + /// + /// + /// + /// + public MessengerBase(string messagePath) + { + if (string.IsNullOrEmpty(messagePath)) + throw new ArgumentException("messagePath must not be empty or null"); + + MessagePath = messagePath; + } + + + /// + /// Registers this messenger with appserver controller + /// + /// + public void RegisterWithAppServer(CotijaSystemController appServerController) + { + if (appServerController == null) + throw new ArgumentNullException("appServerController"); + + AppServerController = appServerController; + CustomRegisterWithAppServer(AppServerController); + } + + /// + /// Implemented in extending classes. Wire up API calls and feedback here + /// + /// + abstract protected void CustomRegisterWithAppServer(CotijaSystemController appServerController); + + /// + /// Helper for posting status message + /// + /// The contents of the content object + protected void PostStatusMessage(object contentObject) + { + AppServerController.SendMessageToServer(JObject.FromObject(new + { + type = MessagePath, + content = contentObject + })); + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs b/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs index 67180b35..37437b5d 100644 --- a/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/VideoCodecBaseMessenger.cs @@ -15,29 +15,22 @@ namespace PepperDash.Essentials.AppServer.Messengers /// /// Provides a messaging bridge for a VideoCodecBase /// - public class VideoCodecBaseMessenger + public class VideoCodecBaseMessenger : MessengerBase { /// /// /// public VideoCodecBase Codec { get; private set; } - public CotijaSystemController AppServerController { get; private set; } - - public string MessagePath { get; private set; } - /// /// /// /// - public VideoCodecBaseMessenger(VideoCodecBase codec, string messagePath) + public VideoCodecBaseMessenger(VideoCodecBase codec, string messagePath) : base(messagePath) { if (codec == null) throw new ArgumentNullException("codec"); - if (string.IsNullOrEmpty(messagePath)) - throw new ArgumentException("messagePath must not be empty or null"); - MessagePath = messagePath; Codec = codec; codec.CallStatusChange += new EventHandler(codec_CallStatusChange); codec.IsReadyChange += new EventHandler(codec_IsReadyChange); @@ -77,16 +70,11 @@ namespace PepperDash.Essentials.AppServer.Messengers } /// - /// Registers this codec's messaging with an app server controller + /// Called from base's RegisterWithAppServer method /// /// - public void RegisterWithAppServer(CotijaSystemController appServerController) + protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) { - if (appServerController == null) - throw new ArgumentNullException("appServerController"); - - AppServerController = appServerController; - appServerController.AddAction("/device/videoCodec/isReady", new Action(SendIsReady)); appServerController.AddAction("/device/videoCodec/fullStatus", new Action(SendVtcFullMessageObject)); appServerController.AddAction("/device/videoCodec/dial", new Action(s => Codec.Dial(s))); @@ -242,18 +230,5 @@ namespace PepperDash.Essentials.AppServer.Messengers hasDirectory = Codec is IHasDirectory }); } - - /// - /// Helper for posting status message - /// - /// The contents of the content object - void PostStatusMessage(object contentObject) - { - AppServerController.SendMessageToServer(JObject.FromObject(new - { - type = MessagePath, - content = contentObject - })); - } } } \ No newline at end of file diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 14e916f9..1bcd3259 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -104,6 +104,7 @@ + From 99da6debdca61f3bf49529df7bafea5f549553ac Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Wed, 19 Sep 2018 11:46:52 -0600 Subject: [PATCH 12/19] Switched Websocket to synchronous Send method. Seems to prevent data loss --- .../AppServer/CotijaSystemController.cs | 109 ++------------- .../Messengers/AtcDdvc01Messenger.cs | 127 ++++++++++++++++++ .../RoomBridges/CotijaDdvc01RoomBridge.cs | 12 +- .../CotijaEssentialsHuddleSpaceRoomBridge.cs | 5 +- .../PepperDashEssentials.csproj | 1 + .../EssentialsHuddlePanelAvFunctionsDriver.cs | 2 +- devjson commands.json | 3 + essentials-framework | 2 +- 8 files changed, 156 insertions(+), 105 deletions(-) create mode 100644 PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index f72857d1..a6b06e55 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -239,6 +239,7 @@ namespace PepperDash.Essentials 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) @@ -301,102 +302,8 @@ namespace PepperDash.Essentials { ConnectWebsocketClient(); return; - - //var ready = RegisterLockEvent.Wait(20000); - //if (!ready) - //{ - // Debug.Console(1, this, "RegisterSystemToServer event failed to clear after 20 seconds. Ignoring"); - // //return; - //} - //RegisterLockEvent.Reset(); - - //try - //{ - // 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); - - // string postBody = JsonConvert.SerializeObject(confObject); - // SystemUuid = confObject.SystemUuid; - - // if (string.IsNullOrEmpty(postBody)) - // { - // Debug.Console(1, this, "ERROR: Config body is empty. Cannot register with server."); - // } - // else - // { - // var regClient = new HttpClient(); - // regClient.Verbose = true; - // regClient.KeepAlive = true; - - // string url = string.Format("http://{0}/api/system/join/{1}", Config.ServerUrl, SystemUuid); - // Debug.Console(1, this, "Joining server at {0}", url); - - // HttpClientRequest request = new HttpClientRequest(); - // request.Url.Parse(url); - // request.RequestType = RequestType.Post; - // request.Header.SetHeaderValue("Content-Type", "application/json"); - // request.ContentString = postBody; - - // regClient.DispatchAsync(request, RegistrationConnectionCallback); - // } - - //} - //catch (Exception e) - //{ - // Debug.Console(0, this, "ERROR: Initilizing app server controller: {0}", e); - // RegisterLockEvent.Set(); - // StartReconnectTimer(); - //} - } - ///// - ///// The callback that fires when we get a response from our registration attempt - ///// - ///// - ///// - //void RegistrationConnectionCallback(HttpClientResponse resp, HTTP_CALLBACK_ERROR err) - //{ - // CheckHttpDebug(resp, err); - // try - // { - // if (resp != null && resp.Code == 200) - // { - // StopReconnectTimer(); - - // // Success here! - // ConnectStreamClient(); - // } - // else - // { - // if (resp != null) - // { - // if (resp.Code == 502) - // { - // Debug.Console(1, this, "Cannot reach App Server behind web server. Check that service/app is running on server"); - // } - // else - // { - // Debug.Console(1, this, "Error response from server: {0}\n{1}", resp.Code, err); - // } - // } - // else - // { - // Debug.Console(1, this, "No response. Server is likely unreachable"); - // } - // StartReconnectTimer(); - // } - // } - // catch (Exception e) - // { - // Debug.Console(1, this, "Error Initializing Stream Client: {0}", e); - // StartReconnectTimer(); - // RegisterLockEvent.Set(); - // } - //} - /// /// Connects the Websocket Client /// @@ -500,8 +407,16 @@ namespace PepperDash.Essentials string message = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); Debug.Console(1, this, "Message TX: {0}", message); var messageBytes = System.Text.Encoding.UTF8.GetBytes(message); - WSClient.SendAsync(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME); + 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.Connected) + { + Debug.Console(1, this, "Cannot send. Not connected {0}"); + } } /// @@ -703,7 +618,7 @@ namespace PepperDash.Essentials { if(result != WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS) Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "SendCallback questionable result: {0}", result); - return 0; + return 1; } /// @@ -716,7 +631,7 @@ namespace PepperDash.Essentials if(string.IsNullOrEmpty(message)) return; - Debug.Console(1, this, "Message RX: '{0}'", message); + Debug.Console(1, this, "Message RX: {0}", message); try { var messageObj = JObject.Parse(message); diff --git a/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs b/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs new file mode 100644 index 00000000..c36702aa --- /dev/null +++ b/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.EthernetCommunication; + +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.AppServer.Messengers +{ + public class Ddvc01AtcMessenger : MessengerBase + { + BasicTriList EISC; + + const uint BKeypad1 = 201; + const uint BKeypad2 = 202; + const uint BKeypad3 = 203; + const uint BKeypad4 = 204; + const uint BKeypad5 = 205; + const uint BKeypad6 = 206; + const uint BKeypad7 = 207; + const uint BKeypad8 = 208; + const uint BKeypad9 = 209; + const uint BKeypad0 = 210; + const uint BKeypadStar = 211; + const uint BKeypadPound = 212; + const uint BDialHangup = 221; + const uint BIncomingAnswer = 251; + const uint BIncomingReject = 252; + const uint BSpeedDial1 = 241; + const uint BSpeedDial2 = 242; + const uint BSpeedDial3 = 243; + const uint BSpeedDial4 = 244; + + const uint BIsOnHook = 222; + const uint BIsOffHook = 224; + const uint BDialHangupIsVisible = 251; + const uint BCallIsIncoming = 254; + const uint BSpeedDialIsVisible1 = 261; + const uint BSpeedDialIsVisible2 = 262; + const uint BSpeedDialIsVisible3 = 263; + const uint BSpeedDialIsVisible4 = 264; + + + const uint SCurrentDialString = 201; + const uint SSpeedDialName1 = 241; + const uint SSpeedDialName2 = 242; + const uint SSpeedDialName3 = 243; + const uint SSpeedDialName4 = 244; + + /// + /// + /// + /// + /// + public Ddvc01AtcMessenger(BasicTriList eisc, string messagePath) + : base(messagePath) + { + EISC = eisc; + + } + + /// + /// + /// + void SendFullStatus() + { + this.PostStatusMessage(new + { + atc = new + { + callIsIncoming = EISC.GetBool(BCallIsIncoming), + isOnHook = EISC.GetBool(BIsOnHook), + isOffHook = EISC.GetBool(BIsOffHook), + dialHangupIsVisible = EISC.GetBool(BDialHangupIsVisible), + currentDialString = EISC.GetString(SCurrentDialString), + } + }); + } + + /// + /// + /// + /// + protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) + { + Action send = this.PostStatusMessage; + EISC.SetBoolSigAction(BIsOffHook, b => send(new { isOffHook = b })); + EISC.SetBoolSigAction(BIsOnHook, b => send(new { isOnHook = b })); + EISC.SetBoolSigAction(BDialHangupIsVisible, b => send(new { dialHangupIsVisible = b })); + EISC.SetBoolSigAction(BCallIsIncoming, b => send(new { callIsIncoming = b })); + EISC.SetStringSigAction(SCurrentDialString, s => send(new { currentDialString = s })); + + // Add press and holds using helper + Action addPHAction = (s, u) => + AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => EISC.SetBool(u, b))); + addPHAction("/dial1", BKeypad1); + addPHAction("/dial2", BKeypad2); + addPHAction("/dial3", BKeypad3); + addPHAction("/dial4", BKeypad4); + addPHAction("/dial5", BKeypad5); + addPHAction("/dial6", BKeypad6); + addPHAction("/dial7", BKeypad7); + addPHAction("/dial8", BKeypad8); + addPHAction("/dial9", BKeypad9); + addPHAction("/dial0", BKeypad0); + addPHAction("/dialStar", BKeypadStar); + addPHAction("/dialPound", BKeypadPound); + + // Add straight calls + Action addAction = (s, u) => + AppServerController.AddAction(MessagePath + s, new Action(() => EISC.PulseBool(u, 100))); + addAction("/dialHangup", BDialHangup); + addAction("/incomingAnswer", BIncomingAnswer); + addAction("/incomingReject", BIncomingReject); + addAction("/speedDial1", BSpeedDial1); + addAction("/speedDial2", BSpeedDial2); + addAction("/speedDial3", BSpeedDial3); + addAction("/speedDial4", BSpeedDial4); + + AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatus)); + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index 25c122df..ddff3e14 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -10,6 +10,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; +using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Room.Config; @@ -145,6 +146,8 @@ namespace PepperDash.Essentials.Room.Cotija CotijaDdvc01DeviceBridge SourceBridge; + Ddvc01AtcMessenger AtcMessenger; + /// /// @@ -182,6 +185,9 @@ namespace PepperDash.Essentials.Room.Cotija SetupFunctions(); SetupFeedbacks(); + AtcMessenger = new Ddvc01AtcMessenger(EISC, "/atc"); + AtcMessenger.RegisterWithAppServer(Parent); + EISC.SigChange += EISC_SigChange; EISC.OnlineStatusChange += (o, a) => { @@ -216,8 +222,6 @@ namespace PepperDash.Essentials.Room.Cotija } }, "mobilebridgedump", "Dumps DDVC01 bridge EISC data b,u,s", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(s => LoadConfigValues(), "loadddvc", "", ConsoleAccessLevelEnum.AccessOperator); - return base.CustomActivate(); } @@ -227,7 +231,6 @@ namespace PepperDash.Essentials.Room.Cotija /// void SetupFunctions() { - Parent.AddAction(@"/room/room1/status", new Action(SendFullStatus)); Parent.AddAction(@"/room/room1/source", new Action(c => @@ -465,6 +468,9 @@ namespace PepperDash.Essentials.Room.Cotija ConfigIsLoaded = true; } + /// + /// + /// void SendFullStatus() { if (ConfigIsLoaded) diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs index 815aa3e8..35acefc6 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs @@ -82,7 +82,7 @@ namespace PepperDash.Essentials var currentVolumeDevice = volumeRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; if (currentVolumeDevice != null) { - currentVolumeDevice.MuteFeedback.OutputChange += VolumeLevelFeedback_OutputChange; + currentVolumeDevice.MuteFeedback.OutputChange += MuteFeedback_OutputChange; currentVolumeDevice.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; } } @@ -470,8 +470,7 @@ namespace PepperDash.Essentials }; } return vtc; - } - + } } /// diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 1bcd3259..1bb81720 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -104,6 +104,7 @@ + diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs index abdfeea6..e18801ea 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs @@ -741,7 +741,7 @@ namespace PepperDash.Essentials _CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished; _CurrentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled; - _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; + _CurrentRoom.OnFeedback.OutputChange -= CurrentRoom_OnFeedback_OutputChange; _CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange; _CurrentRoom.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange; } diff --git a/devjson commands.json b/devjson commands.json index 67ee4df4..55bc8bda 100644 --- a/devjson commands.json +++ b/devjson commands.json @@ -29,3 +29,6 @@ devjson:1 {"deviceKey":"microphonePrivacyController-1", "methodName":"TogglePriv devjson:1 {"deviceKey":"room1.InCallFeedback","methodName":"SetTestValue", "params": [ true ]} devjson:1 {"deviceKey":"room1.InCallFeedback","methodName":"ClearTestValue", "params": []} + +devjson:10 {"deviceKey":"mobileControlBridge-essentialsHuddle","methodName":"TestOne"} +devjson:10 {"deviceKey":"mobileControlBridge-essentialsHuddle","methodName":"TestMulti"} diff --git a/essentials-framework b/essentials-framework index fb02dac4..7d08a09d 160000 --- a/essentials-framework +++ b/essentials-framework @@ -1 +1 @@ -Subproject commit fb02dac4bbf50cc5e17a41539be6b5b5ea8752f1 +Subproject commit 7d08a09d5f7a03164907a5bbf15e80f49bf7658c From 101d1b56250f5c19e8c330d86442e65e9fa46919 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Mon, 24 Sep 2018 15:01:02 -0600 Subject: [PATCH 13/19] Added handler for phone call activity, DDVC bridge --- .../AppServer/CotijaSystemController.cs | 15 +++++++++++---- .../RoomBridges/CotijaDdvc01RoomBridge.cs | 10 ++++++++++ .../EssentialsHuddleVtc1PropertiesConfig.cs | 2 ++ devjson commands.json | 5 ++++- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/PepperDashEssentials/AppServer/CotijaSystemController.cs b/PepperDashEssentials/AppServer/CotijaSystemController.cs index a6b06e55..33f66eff 100644 --- a/PepperDashEssentials/AppServer/CotijaSystemController.cs +++ b/PepperDashEssentials/AppServer/CotijaSystemController.cs @@ -85,7 +85,7 @@ namespace PepperDash.Essentials "mobilehttprequest", "Tests an HTTP get to URL given", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(PrintActionDictionaryPaths, "mobileshowactionpaths", - "Prints the paths in teh Action Dictionary", ConsoleAccessLevelEnum.AccessOperator); + "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", @@ -176,6 +176,7 @@ namespace PepperDash.Essentials else { Debug.Console(0, this, "Adding room bridge and sending configuration"); + SystemUuid = ConfigReader.ConfigObject.SystemUuid; RegisterSystemToServer(); } } @@ -188,6 +189,7 @@ namespace PepperDash.Essentials 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(); } @@ -207,6 +209,8 @@ namespace PepperDash.Essentials /// 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."); @@ -301,7 +305,6 @@ namespace PepperDash.Essentials void RegisterSystemToServer() { ConnectWebsocketClient(); - return; } /// @@ -310,6 +313,8 @@ namespace PepperDash.Essentials /// void ConnectWebsocketClient() { + + Debug.Console(1, this, "Initializing Stream client to server."); if (WSClient != null) @@ -318,8 +323,6 @@ namespace PepperDash.Essentials CleanUpWebsocketClient(); } - SystemUuid = ConfigReader.ConfigObject.SystemUuid; - WSClient = new WebSocketClient(); WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid); WSClient.ConnectionCallBack = Websocket_ConnectCallback; @@ -341,6 +344,10 @@ namespace PepperDash.Essentials WSClient.SendCallBack = Websocket_SendCallback; WSClient.ReceiveCallBack = Websocket_ReceiveCallback; WSClient.ReceiveAsync(); + SendMessageObjectToServer(new + { + type = "hello" + }); } else { diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index ddff3e14..c3d47916 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -241,6 +241,11 @@ namespace PepperDash.Essentials.Room.Cotija Parent.AddAction(@"/room/room1/defaultsource", new Action(() => EISC.PulseBool(BoolJoin.ActivitySharePress))); + Parent.AddAction(@"/room/room1/activityVideo", new Action(() => + EISC.PulseBool(BoolJoin.ActivityVideoCallPress))); + Parent.AddAction(@"/room/room1/activityPhone", new Action(() => + EISC.PulseBool(BoolJoin.ActivityPhoneCallPress))); + Parent.AddAction(@"/room/room1/volumes/master/level", new Action(u => EISC.SetUshort(UshortJoin.MasterVolumeLevel, u))); @@ -392,6 +397,11 @@ namespace PepperDash.Essentials.Room.Cotija var name = EISC.StringOutput[i + 1].StringValue; rmProps.SpeedDials.Add(new DDVC01SpeedDial { Number = num, Name = name}); } + + // This MAY need a check + rmProps.AudioCodecKey = "audioCodec"; + rmProps.VideoCodecKey = null; // "videoCodec"; + // volume control names var volCount = EISC.UShortOutput[701].UShortValue; diff --git a/PepperDashEssentials/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs b/PepperDashEssentials/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs index 83303582..16e49933 100644 --- a/PepperDashEssentials/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs @@ -20,5 +20,7 @@ namespace PepperDash.Essentials.Room.Config public string DefaultSourceItem { get; set; } [JsonProperty("videoCodecKey")] public string VideoCodecKey { get; set; } + [JsonProperty("audioCodecKey")] + public string AudioCodecKey { get; set; } } } \ No newline at end of file diff --git a/devjson commands.json b/devjson commands.json index 55bc8bda..d8f5f401 100644 --- a/devjson commands.json +++ b/devjson commands.json @@ -12,7 +12,7 @@ devjson:1 {"deviceKey":"timer","methodName":"Cancel" } devjson:1 {"deviceKey":"timer","methodName":"Reset" } -devjson:1 {"deviceKey":"room1","methodName":"Shutdown" } +devjson:10 {"deviceKey":"room1","methodName":"Shutdown" } devjson:1 {"deviceKey":"mockVc-1", "methodName":"TestIncomingVideoCall", "params": ["123-456-7890"]} @@ -30,5 +30,8 @@ devjson:1 {"deviceKey":"room1.InCallFeedback","methodName":"SetTestValue", "para devjson:1 {"deviceKey":"room1.InCallFeedback","methodName":"ClearTestValue", "params": []} + + devjson:10 {"deviceKey":"mobileControlBridge-essentialsHuddle","methodName":"TestOne"} devjson:10 {"deviceKey":"mobileControlBridge-essentialsHuddle","methodName":"TestMulti"} + devjson:10 {"deviceKey":"room1","methodName":"RunDefaultPresentRoute"} From 78668e8abbe29cd40c758d451684d1fd0db423a7 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Tue, 25 Sep 2018 14:36:38 -0600 Subject: [PATCH 14/19] Added config construction for audio conf in DDVC MOB bridge --- .../Messengers/AtcDdvc01Messenger.cs | 19 ++++--- .../RoomBridges/CotijaDdvc01RoomBridge.cs | 54 +++++++++++++++++-- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs b/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs index c36702aa..139ada9a 100644 --- a/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs @@ -39,17 +39,10 @@ namespace PepperDash.Essentials.AppServer.Messengers const uint BIsOffHook = 224; const uint BDialHangupIsVisible = 251; const uint BCallIsIncoming = 254; - const uint BSpeedDialIsVisible1 = 261; - const uint BSpeedDialIsVisible2 = 262; - const uint BSpeedDialIsVisible3 = 263; - const uint BSpeedDialIsVisible4 = 264; - const uint SCurrentDialString = 201; - const uint SSpeedDialName1 = 241; - const uint SSpeedDialName2 = 242; - const uint SSpeedDialName3 = 243; - const uint SSpeedDialName4 = 244; + const uint SHookState = 221; + /// /// @@ -68,8 +61,9 @@ namespace PepperDash.Essentials.AppServer.Messengers /// void SendFullStatus() { + this.PostStatusMessage(new - { + { atc = new { callIsIncoming = EISC.GetBool(BCallIsIncoming), @@ -93,6 +87,7 @@ namespace PepperDash.Essentials.AppServer.Messengers EISC.SetBoolSigAction(BDialHangupIsVisible, b => send(new { dialHangupIsVisible = b })); EISC.SetBoolSigAction(BCallIsIncoming, b => send(new { callIsIncoming = b })); EISC.SetStringSigAction(SCurrentDialString, s => send(new { currentDialString = s })); + EISC.SetStringSigAction(SHookState, s => send(new { callStatus = s })); // Add press and holds using helper Action addPHAction = (s, u) => @@ -122,6 +117,10 @@ namespace PepperDash.Essentials.AppServer.Messengers addAction("/speedDial4", BSpeedDial4); AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatus)); + + // Dial on string +#warning Does this need to set the string and then dial? + AppServerController.AddAction(MessagePath + "/dial", new Action(s => EISC.SetString(SCurrentDialString, s))); } } } \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index c3d47916..773c1158 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -61,14 +61,15 @@ namespace PepperDash.Essentials.Room.Cotija /// 63 /// public const uint ShutdownStart = 63; - - - /// /// 72 /// public const uint SourceHasChanged = 72; /// + /// 261 - The start of the range of speed dial visibles + /// + public const uint SpeedDialVisibleStartJoin = 261; + /// /// 501 /// public const uint ConfigIsReady = 501; @@ -93,6 +94,16 @@ namespace PepperDash.Essentials.Room.Cotija /// 71 /// public const uint SelectedSourceKey = 71; + + /// + /// 241 + /// + public const uint SpeedDialNameStartJoin = 241; + + /// + /// 251 + /// + public const uint SpeedDialNumberStartJoin = 251; /// /// 501 @@ -185,7 +196,7 @@ namespace PepperDash.Essentials.Room.Cotija SetupFunctions(); SetupFeedbacks(); - AtcMessenger = new Ddvc01AtcMessenger(EISC, "/atc"); + AtcMessenger = new Ddvc01AtcMessenger(EISC, "/device/audioCodec"); AtcMessenger.RegisterWithAppServer(Parent); EISC.SigChange += EISC_SigChange; @@ -467,6 +478,41 @@ namespace PepperDash.Essentials.Room.Cotija co.SourceLists.Add("default", newSl); + // build "audioCodec" config if we need + if (string.IsNullOrEmpty(rmProps.AudioCodecKey)) + { + var acFavs = new List(); + for (uint i = 0; i < 4; i++) + { + if (!EISC.GetBool(BoolJoin.SpeedDialVisibleStartJoin + i)) + { + break; + } + acFavs.Add(new PepperDash.Essentials.Devices.Common.Codec.CodecActiveCallItem() + { + Name = EISC.GetString(StringJoin.SpeedDialNameStartJoin + i), + Number = EISC.GetString(StringJoin.SpeedDialNumberStartJoin + i), + Type = PepperDash.Essentials.Devices.Common.Codec.eCodecCallType.Audio + }); + } + + var acProps = new + { + favorites = acFavs + }; + + var acStr = "audioCodec"; + var acConf = new DeviceConfig() + { + Group = acStr, + Key = acStr, + Name = acStr, + Type = acStr, + Properties = JToken.FromObject(acProps) + }; + co.Devices.Add(acConf); + } + Debug.Console(0, this, "******* CONFIG FROM DDVC: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented)); var handler = ConfigurationIsReady; From 5014343fa3cfcf5703fac826d15151ffbde8f945 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Thu, 27 Sep 2018 10:50:23 -0600 Subject: [PATCH 15/19] DDVC01 - MOB ATC messaging changes --- .../Messengers/AtcDdvc01Messenger.cs | 85 ++++++++++--------- .../RoomBridges/CotijaDdvc01RoomBridge.cs | 4 +- essentials-framework | 2 +- 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs b/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs index 139ada9a..8eb47aa4 100644 --- a/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs @@ -15,18 +15,6 @@ namespace PepperDash.Essentials.AppServer.Messengers { BasicTriList EISC; - const uint BKeypad1 = 201; - const uint BKeypad2 = 202; - const uint BKeypad3 = 203; - const uint BKeypad4 = 204; - const uint BKeypad5 = 205; - const uint BKeypad6 = 206; - const uint BKeypad7 = 207; - const uint BKeypad8 = 208; - const uint BKeypad9 = 209; - const uint BKeypad0 = 210; - const uint BKeypadStar = 211; - const uint BKeypadPound = 212; const uint BDialHangup = 221; const uint BIncomingAnswer = 251; const uint BIncomingReject = 252; @@ -35,14 +23,38 @@ namespace PepperDash.Essentials.AppServer.Messengers const uint BSpeedDial3 = 243; const uint BSpeedDial4 = 244; - const uint BIsOnHook = 222; - const uint BIsOffHook = 224; - const uint BDialHangupIsVisible = 251; - const uint BCallIsIncoming = 254; - + /// + /// 201 + /// const uint SCurrentDialString = 201; + /// + /// 211 + /// + const uint SCurrentCallString = 211; + /// + /// 221 + /// const uint SHookState = 221; + /// + /// + /// + Dictionary DTMFMap = new Dictionary + { + { "1", 201 }, + { "2", 202 }, + { "3", 203 }, + { "4", 204 }, + { "5", 205 }, + { "6", 206 }, + { "7", 207 }, + { "8", 208 }, + { "9", 209 }, + { "0", 210 }, + { "*", 211 }, + { "#", 212 }, + }; + /// /// @@ -53,7 +65,6 @@ namespace PepperDash.Essentials.AppServer.Messengers : base(messagePath) { EISC = eisc; - } /// @@ -66,10 +77,8 @@ namespace PepperDash.Essentials.AppServer.Messengers { atc = new { - callIsIncoming = EISC.GetBool(BCallIsIncoming), - isOnHook = EISC.GetBool(BIsOnHook), - isOffHook = EISC.GetBool(BIsOffHook), - dialHangupIsVisible = EISC.GetBool(BDialHangupIsVisible), + callStatus = EISC.GetString(SHookState), + currentCallString = EISC.GetString(SCurrentCallString), currentDialString = EISC.GetString(SCurrentDialString), } }); @@ -82,33 +91,18 @@ namespace PepperDash.Essentials.AppServer.Messengers protected override void CustomRegisterWithAppServer(CotijaSystemController appServerController) { Action send = this.PostStatusMessage; - EISC.SetBoolSigAction(BIsOffHook, b => send(new { isOffHook = b })); - EISC.SetBoolSigAction(BIsOnHook, b => send(new { isOnHook = b })); - EISC.SetBoolSigAction(BDialHangupIsVisible, b => send(new { dialHangupIsVisible = b })); - EISC.SetBoolSigAction(BCallIsIncoming, b => send(new { callIsIncoming = b })); EISC.SetStringSigAction(SCurrentDialString, s => send(new { currentDialString = s })); + EISC.SetStringSigAction(SCurrentCallString, s => send(new { currentCallString = s })); EISC.SetStringSigAction(SHookState, s => send(new { callStatus = s })); // Add press and holds using helper Action addPHAction = (s, u) => AppServerController.AddAction(MessagePath + s, new PressAndHoldAction(b => EISC.SetBool(u, b))); - addPHAction("/dial1", BKeypad1); - addPHAction("/dial2", BKeypad2); - addPHAction("/dial3", BKeypad3); - addPHAction("/dial4", BKeypad4); - addPHAction("/dial5", BKeypad5); - addPHAction("/dial6", BKeypad6); - addPHAction("/dial7", BKeypad7); - addPHAction("/dial8", BKeypad8); - addPHAction("/dial9", BKeypad9); - addPHAction("/dial0", BKeypad0); - addPHAction("/dialStar", BKeypadStar); - addPHAction("/dialPound", BKeypadPound); - // Add straight calls + // Add straight pulse calls Action addAction = (s, u) => AppServerController.AddAction(MessagePath + s, new Action(() => EISC.PulseBool(u, 100))); - addAction("/dialHangup", BDialHangup); + addAction("/endCall", BDialHangup); addAction("/incomingAnswer", BIncomingAnswer); addAction("/incomingReject", BIncomingReject); addAction("/speedDial1", BSpeedDial1); @@ -116,11 +110,18 @@ namespace PepperDash.Essentials.AppServer.Messengers addAction("/speedDial3", BSpeedDial3); addAction("/speedDial4", BSpeedDial4); + // Get status AppServerController.AddAction(MessagePath + "/fullStatus", new Action(SendFullStatus)); - // Dial on string -#warning Does this need to set the string and then dial? AppServerController.AddAction(MessagePath + "/dial", new Action(s => EISC.SetString(SCurrentDialString, s))); + // Pulse DTMF + AppServerController.AddAction(MessagePath + "/dtmf", new Action(s => + { + if (DTMFMap.ContainsKey(s)) + { + EISC.PulseBool(DTMFMap[s], 100); + } + })); } } } \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index 773c1158..141dece9 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -479,7 +479,7 @@ namespace PepperDash.Essentials.Room.Cotija co.SourceLists.Add("default", newSl); // build "audioCodec" config if we need - if (string.IsNullOrEmpty(rmProps.AudioCodecKey)) + if (!string.IsNullOrEmpty(rmProps.AudioCodecKey)) { var acFavs = new List(); for (uint i = 0; i < 4; i++) @@ -511,7 +511,7 @@ namespace PepperDash.Essentials.Room.Cotija Properties = JToken.FromObject(acProps) }; co.Devices.Add(acConf); - } + } Debug.Console(0, this, "******* CONFIG FROM DDVC: \r{0}", JsonConvert.SerializeObject(ConfigReader.ConfigObject, Formatting.Indented)); diff --git a/essentials-framework b/essentials-framework index 7d08a09d..98f2cfc6 160000 --- a/essentials-framework +++ b/essentials-framework @@ -1 +1 @@ -Subproject commit 7d08a09d5f7a03164907a5bbf15e80f49bf7658c +Subproject commit 98f2cfc64a4f294cc8ed2b27134c34bb8405bde6 From 184144dc3c87adc30a31fc5e8dcbc7d6151efbb0 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Thu, 27 Sep 2018 17:50:04 -0600 Subject: [PATCH 16/19] Touchups to ddvc mob codec messages --- .../Messengers/AtcDdvc01Messenger.cs | 58 ++++++++++--- .../RoomBridges/CotijaDdvc01RoomBridge.cs | 81 ------------------- 2 files changed, 49 insertions(+), 90 deletions(-) diff --git a/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs b/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs index 8eb47aa4..882ad317 100644 --- a/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs +++ b/PepperDashEssentials/AppServer/Messengers/AtcDdvc01Messenger.cs @@ -8,6 +8,7 @@ using Crestron.SimplSharpPro.EthernetCommunication; using PepperDash.Core; using PepperDash.Essentials.Core; +using PepperDash.Essentials.Devices.Common.Codec; namespace PepperDash.Essentials.AppServer.Messengers { @@ -55,6 +56,8 @@ namespace PepperDash.Essentials.AppServer.Messengers { "#", 212 }, }; + CodecActiveCallItem CurrentCallItem; + /// /// @@ -65,6 +68,10 @@ namespace PepperDash.Essentials.AppServer.Messengers : base(messagePath) { EISC = eisc; + + CurrentCallItem = new CodecActiveCallItem(); + CurrentCallItem.Type = eCodecCallType.Audio; + CurrentCallItem.Id = "-audio-"; } /// @@ -72,15 +79,12 @@ namespace PepperDash.Essentials.AppServer.Messengers /// void SendFullStatus() { - this.PostStatusMessage(new { - atc = new - { - callStatus = EISC.GetString(SHookState), - currentCallString = EISC.GetString(SCurrentCallString), - currentDialString = EISC.GetString(SCurrentDialString), - } + calls = GetCurrentCallList(), + callStatus = EISC.GetString(SHookState), + currentCallString = EISC.GetString(SCurrentCallString), + currentDialString = EISC.GetString(SCurrentDialString), }); } @@ -92,8 +96,28 @@ namespace PepperDash.Essentials.AppServer.Messengers { Action send = this.PostStatusMessage; EISC.SetStringSigAction(SCurrentDialString, s => send(new { currentDialString = s })); - EISC.SetStringSigAction(SCurrentCallString, s => send(new { currentCallString = s })); - EISC.SetStringSigAction(SHookState, s => send(new { callStatus = s })); + + EISC.SetStringSigAction(SHookState, s => + { + CurrentCallItem.Status = (eCodecCallStatus)Enum.Parse(typeof(eCodecCallStatus), s, true); + GetCurrentCallList(); + send(new + { + calls = GetCurrentCallList(), + callStatus = s + }); + }); + + EISC.SetStringSigAction(SCurrentCallString, s => + { + CurrentCallItem.Name = s; + CurrentCallItem.Number = s; + send(new + { + calls = GetCurrentCallList(), + currentCallString = s + }); + }); // Add press and holds using helper Action addPHAction = (s, u) => @@ -123,5 +147,21 @@ namespace PepperDash.Essentials.AppServer.Messengers } })); } + + /// + /// Turns the + /// + /// + List GetCurrentCallList() + { + if (CurrentCallItem.Status == eCodecCallStatus.Disconnected) + { + return new List(); + } + else + { + return new List() { CurrentCallItem }; + } + } } } \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index 141dece9..d99534b4 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -650,86 +650,5 @@ namespace PepperDash.Essentials.Room.Cotija EISC.StringInput[StringJoin.UserCodeToSystem].StringValue = UserCode; EISC.StringInput[StringJoin.ServerUrl].StringValue = Parent.Config.ClientAppUrl; } - - /// - /// - /// - /// - /// - void SourceChange(string oldKey, string newKey) - { - /* Example message - * { -   "type":"/room/status", -   "content": { -     "selectedSourceKey": "off", -   } - } - */ - //if (type == ChangeType.WillChange) - //{ - // // Disconnect from previous source - - // if (info != null) - // { - // var previousDev = info.SourceDevice; - - // // device type interfaces - // if (previousDev is ISetTopBoxControls) - // (previousDev as ISetTopBoxControls).UnlinkActions(Parent); - // // common interfaces - // if (previousDev is IChannel) - // (previousDev as IChannel).UnlinkActions(Parent); - // if (previousDev is IColor) - // (previousDev as IColor).UnlinkActions(Parent); - // if (previousDev is IDPad) - // (previousDev as IDPad).UnlinkActions(Parent); - // if (previousDev is IDvr) - // (previousDev as IDvr).UnlinkActions(Parent); - // if (previousDev is INumericKeypad) - // (previousDev as INumericKeypad).UnlinkActions(Parent); - // if (previousDev is IPower) - // (previousDev as IPower).UnlinkActions(Parent); - // if (previousDev is ITransport) - // (previousDev as ITransport).UnlinkActions(Parent); - // } - - - // var huddleRoom = room as EssentialsHuddleSpaceRoom; - // JObject roomStatus = new JObject(); - // roomStatus.Add("selectedSourceKey", huddleRoom.CurrentSourceInfoKey); - - // JObject message = new JObject(); - - // message.Add("type", "/room/status/"); - // message.Add("content", roomStatus); - - // Parent.PostToServer(message); - //} - //else - //{ - // if (info != null) - // { - // var dev = info.SourceDevice; - - // if (dev is ISetTopBoxControls) - // (dev as ISetTopBoxControls).LinkActions(Parent); - // if (dev is IChannel) - // (dev as IChannel).LinkActions(Parent); - // if (dev is IColor) - // (dev as IColor).LinkActions(Parent); - // if (dev is IDPad) - // (dev as IDPad).LinkActions(Parent); - // if (dev is IDvr) - // (dev as IDvr).LinkActions(Parent); - // if (dev is INumericKeypad) - // (dev as INumericKeypad).LinkActions(Parent); - // if (dev is IPower) - // (dev as IPower).LinkActions(Parent); - // if (dev is ITransport) - // (dev as ITransport).LinkActions(Parent); - // } - //} - } } } \ No newline at end of file From 28d694d0b4fd8373fba9c414d700c9219b39c7b9 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Tue, 2 Oct 2018 13:02:46 -0600 Subject: [PATCH 17/19] Reset of connected simpl program will no longer add duplicate audioCodec and videoCodec devices to output config --- .../AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs | 11 +++++++---- PepperDashEssentials/Properties/AssemblyInfo.cs | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index d99534b4..c68d0463 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -365,10 +365,10 @@ namespace PepperDash.Essentials.Room.Cotija var version = Assembly.GetExecutingAssembly().GetName().Version; co.Info.RuntimeInfo.AssemblyVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build); - //Room - if (co.Rooms == null) - co.Rooms = new List(); + //if (co.Rooms == null) + // always start fresh in case simpl changed + co.Rooms = new List(); var rm = new EssentialsRoomConfig(); if (co.Rooms.Count == 0) { @@ -428,7 +428,10 @@ namespace PepperDash.Essentials.Room.Cotija co.Devices = new List(); // clear out previous DDVC devices - co.Devices.RemoveAll(d => d.Key.StartsWith("source-", StringComparison.OrdinalIgnoreCase)); + co.Devices.RemoveAll(d => + d.Key.StartsWith("source-", StringComparison.OrdinalIgnoreCase) + || d.Key.Equals("audioCodec", StringComparison.OrdinalIgnoreCase) + || d.Key.Equals("videoCodec", StringComparison.OrdinalIgnoreCase)); rmProps.SourceListKey = "default"; rm.Properties = JToken.FromObject(rmProps); diff --git a/PepperDashEssentials/Properties/AssemblyInfo.cs b/PepperDashEssentials/Properties/AssemblyInfo.cs index 36c70ef4..c1a2d70a 100644 --- a/PepperDashEssentials/Properties/AssemblyInfo.cs +++ b/PepperDashEssentials/Properties/AssemblyInfo.cs @@ -4,5 +4,5 @@ [assembly: AssemblyCompany("PepperDash Technology Corp")] [assembly: AssemblyProduct("PepperDashEssentials")] [assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2018")] -[assembly: AssemblyVersion("1.2.6.*")] +[assembly: AssemblyVersion("1.2.9.*")] From 3cbf784417fb18d43a25327cdf079b5b50b32995 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Wed, 3 Oct 2018 18:17:12 -0600 Subject: [PATCH 18/19] Added messaging for code prompt login methods --- .../AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs | 13 ++++++++++++- PepperDashEssentials/Properties/AssemblyInfo.cs | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index c68d0463..dccdc92f 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -27,6 +27,14 @@ namespace PepperDash.Essentials.Room.Cotija /// public const uint RoomIsOn = 301; + /// + /// 41 + /// + public const uint PromptForCode = 41; + /// + /// 42 + /// + public const uint ClientJoined = 42; /// /// 51 /// @@ -242,6 +250,10 @@ namespace PepperDash.Essentials.Room.Cotija /// void SetupFunctions() { +#warning need join numbers for these + Parent.AddAction(@"/room/room1/promptForCode", new Action(() => EISC.PulseBool(12345))); + Parent.AddAction(@"/room/room1/clientJoined", new Action(() => EISC.PulseBool(12346))); + Parent.AddAction(@"/room/room1/status", new Action(SendFullStatus)); Parent.AddAction(@"/room/room1/source", new Action(c => @@ -257,7 +269,6 @@ namespace PepperDash.Essentials.Room.Cotija Parent.AddAction(@"/room/room1/activityPhone", new Action(() => EISC.PulseBool(BoolJoin.ActivityPhoneCallPress))); - Parent.AddAction(@"/room/room1/volumes/master/level", new Action(u => EISC.SetUshort(UshortJoin.MasterVolumeLevel, u))); Parent.AddAction(@"/room/room1/volumes/master/muteToggle", new Action(() => diff --git a/PepperDashEssentials/Properties/AssemblyInfo.cs b/PepperDashEssentials/Properties/AssemblyInfo.cs index c1a2d70a..7f0e0611 100644 --- a/PepperDashEssentials/Properties/AssemblyInfo.cs +++ b/PepperDashEssentials/Properties/AssemblyInfo.cs @@ -4,5 +4,5 @@ [assembly: AssemblyCompany("PepperDash Technology Corp")] [assembly: AssemblyProduct("PepperDashEssentials")] [assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2018")] -[assembly: AssemblyVersion("1.2.9.*")] +[assembly: AssemblyVersion("1.2.10.*")] From 397b0b4d9c2167c9af48a8dffaeb51c57ff294c1 Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Mon, 8 Oct 2018 15:17:02 -0600 Subject: [PATCH 19/19] DDVC01 bridge, repaired device controls --- .../RoomBridges/CotijaDdvc01RoomBridge.cs | 40 ++++++++++++------- .../Properties/AssemblyInfo.cs | 2 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs index dccdc92f..f02d6098 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaDdvc01RoomBridge.cs @@ -251,8 +251,8 @@ namespace PepperDash.Essentials.Room.Cotija void SetupFunctions() { #warning need join numbers for these - Parent.AddAction(@"/room/room1/promptForCode", new Action(() => EISC.PulseBool(12345))); - Parent.AddAction(@"/room/room1/clientJoined", new Action(() => EISC.PulseBool(12346))); + Parent.AddAction(@"/room/room1/promptForCode", new Action(() => EISC.PulseBool(BoolJoin.PromptForCode))); + Parent.AddAction(@"/room/room1/clientJoined", new Action(() => EISC.PulseBool(BoolJoin.ClientJoined))); Parent.AddAction(@"/room/room1/status", new Action(SendFullStatus)); @@ -280,21 +280,26 @@ namespace PepperDash.Essentials.Room.Cotija EISC.PulseBool(BoolJoin.ShutdownEnd))); Parent.AddAction(@"/room/room1/shutdownCancel", new Action(() => EISC.PulseBool(BoolJoin.ShutdownCancel))); - - - // Source Device (Current Source)' - - SourceDeviceMapDictionary sourceJoinMap = new SourceDeviceMapDictionary(); - - var prefix = @"/device/currentSource/"; - - foreach (var item in sourceJoinMap) - { - var join = item.Value; - Parent.AddAction(string.Format("{0}{1}", prefix, item.Key), new PressAndHoldAction(b => EISC.SetBool(join, b))); - } } + /// + /// + /// + /// + void SetupSourceFunctions(string devKey) + { + SourceDeviceMapDictionary sourceJoinMap = new SourceDeviceMapDictionary(); + + var prefix = string.Format("/device/{0}/", devKey); + + foreach (var item in sourceJoinMap) + { + var join = item.Value; + Parent.AddAction(string.Format("{0}{1}", prefix, item.Key), new PressAndHoldAction(b => EISC.SetBool(join, b))); + } + } + + /// /// Links feedbacks to whatever is gonna happen! /// @@ -488,6 +493,11 @@ namespace PepperDash.Essentials.Room.Cotija Type = type }; co.Devices.Add(devConf); + + if (group.ToLower().StartsWith("settopbox")) // Add others here as needed + { + SetupSourceFunctions(key); + } } co.SourceLists.Add("default", newSl); diff --git a/PepperDashEssentials/Properties/AssemblyInfo.cs b/PepperDashEssentials/Properties/AssemblyInfo.cs index 7f0e0611..4cd22c15 100644 --- a/PepperDashEssentials/Properties/AssemblyInfo.cs +++ b/PepperDashEssentials/Properties/AssemblyInfo.cs @@ -4,5 +4,5 @@ [assembly: AssemblyCompany("PepperDash Technology Corp")] [assembly: AssemblyProduct("PepperDashEssentials")] [assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2018")] -[assembly: AssemblyVersion("1.2.10.*")] +[assembly: AssemblyVersion("1.2.11.*")]