diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 235fee48..ab9f2732 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,6 +1,6 @@ - 2.42.1-local + 2.36.6-local $(Version) PepperDash Technology PepperDash Technology diff --git a/src/PepperDash.Core/Comm/GenericSshClient.cs b/src/PepperDash.Core/Comm/GenericSshClient.cs index 546a2a67..df44ab51 100644 --- a/src/PepperDash.Core/Comm/GenericSshClient.cs +++ b/src/PepperDash.Core/Comm/GenericSshClient.cs @@ -151,8 +151,6 @@ namespace PepperDash.Core // Thread-safety lock for state changes private readonly object _stateLock = new object(); - private volatile bool _isProgramStopping; - private bool disconnectLogged = false; /// @@ -209,9 +207,11 @@ namespace PepperDash.Core { if (programEventType == eProgramStatusEventType.Stopping) { - _isProgramStopping = true; - this.LogDebug("Program stopping. Closing connection"); - Disconnect(); + if (client != null) + { + this.LogDebug("Program stopping. Closing connection"); + Disconnect(); + } } } @@ -228,12 +228,6 @@ namespace PepperDash.Core return; } - if (_isProgramStopping) - { - this.LogDebug("Skipping connect because program is stopping"); - return; - } - ConnectEnabled = true; try @@ -293,7 +287,13 @@ namespace PepperDash.Core } catch (SshConnectionException e) { - var ie = e.InnerException; // The details are inside, when present - remote can close the connection with no inner exception at all + var ie = e.InnerException; // The details are inside!! + + if (ie is SocketException) + { + this.LogError("CONNECTION failure: Cannot reach host"); + this.LogVerbose(ie, "Exception details: "); + } if (ie is System.Net.Sockets.SocketException socketException) { @@ -301,20 +301,20 @@ namespace PepperDash.Core Hostname, Port); this.LogVerbose(socketException, "SocketException details: "); } - else if (ie is SshAuthenticationException) + if (ie is SshAuthenticationException) { this.LogError("Authentication failure for username {userName}", Username); this.LogVerbose(ie, "AuthenticationException details: "); } else { - this.LogError("Error on connect: {error}", ie?.Message ?? e.Message); - this.LogVerbose(ie ?? e, "Exception details: "); + this.LogError("Error on connect: {error}", ie.Message); + this.LogVerbose(ie, "Exception details: "); } disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) + if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); @@ -326,7 +326,7 @@ namespace PepperDash.Core disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) + if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); @@ -338,7 +338,7 @@ namespace PepperDash.Core this.LogVerbose(e, "Exception details: "); disconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) + if (AutoReconnect) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); @@ -473,7 +473,7 @@ namespace PepperDash.Core { connectLock.Release(); } - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) + if (AutoReconnect && ConnectEnabled) { this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); StartReconnectTimer(); @@ -516,10 +516,7 @@ namespace PepperDash.Core this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim()); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) - { - StartReconnectTimer(); - } + StartReconnectTimer(); } catch (Exception ex) { @@ -552,10 +549,7 @@ namespace PepperDash.Core this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes)); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - if (AutoReconnect && ConnectEnabled && !_isProgramStopping) - { - StartReconnectTimer(); - } + StartReconnectTimer(); } catch (Exception ex) { diff --git a/src/PepperDash.Core/PepperDash.Core.csproj b/src/PepperDash.Core/PepperDash.Core.csproj index 747aefb6..daa5c6da 100644 --- a/src/PepperDash.Core/PepperDash.Core.csproj +++ b/src/PepperDash.Core/PepperDash.Core.csproj @@ -43,7 +43,7 @@ - + diff --git a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj index b7f333bd..251ba316 100644 --- a/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj +++ b/src/PepperDash.Essentials.Core/PepperDash.Essentials.Core.csproj @@ -25,7 +25,7 @@ bin\$(Configuration)\PepperDash_Essentials_Core.xml - + diff --git a/src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs b/src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs new file mode 100644 index 00000000..19eb0d87 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs @@ -0,0 +1,329 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using Crestron.SimplSharpPro; +using PepperDash.Core; +using PepperDash.Core.Logging; +using Serilog.Events; + +namespace PepperDash.Essentials.Core.Touchpanels +{ + /// + /// A wrapper class for the touchpanel portion of an MPC4 class process to allow for configurable + /// behavior of the keypad buttons + /// + public class Mpc4TouchpanelController : Device + { + readonly MPC3Basic _touchpanel; + + readonly Dictionary _buttons; + + /// + /// Constructor + /// + /// device key + /// device name + /// control system processor + /// dictionary of keypad buttons + public Mpc4TouchpanelController(string key, string name, CrestronControlSystem processor, Dictionary buttons) + : base(key, name) + { + switch (processor.TouchscreenType) + { + case eTouchscreenType.MPC4x102: + _touchpanel = processor.MPC4x102TouchscreenSlot; + break; + + case eTouchscreenType.MPC4x201: + _touchpanel = processor.MPC4x201TouchscreenSlot; + break; + + case eTouchscreenType.MPC4x301: + _touchpanel = processor.MPC4x301TouchscreenSlot; + break; + + case eTouchscreenType.MPC4x302: + _touchpanel = processor.MPC4x302TouchscreenSlot; + break; + + default: + Debug.LogMessage(LogEventLevel.Error, this, "Unsupported touchpanel type '{0}' for MPC4 Touch Controller", processor.TouchscreenType); + break; + } + + if (_touchpanel == null) + { + Debug.LogMessage(LogEventLevel.Error, this, "Failed to construct MPC4 Touchpanel Controller with key {0}, check configuration, processor is type: {1}", key, processor.ControllerTouchScreenSlotDevice?.GetType().FullName ?? "null"); + return; + } + + if (_touchpanel.Registerable) + { + var registrationResponse = _touchpanel.Register(); + Debug.LogMessage(LogEventLevel.Information, this, "touchpanel registration response: {0}", registrationResponse); + } + + _touchpanel.BaseEvent += Touchpanel_BaseEvent; + _touchpanel.ButtonStateChange += Touchpanel_ButtonStateChange; + _touchpanel.PanelStateChange += Touchpanel_PanelStateChange; + + _buttons = buttons; + if (_buttons == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, + "Button properties are null, failed to setup MPC4 Touch Controller, check configuration"); + return; + } + + AddPostActivationAction(() => + { + foreach (var button in _buttons) + { + var buttonKey = button.Key.ToLower(); + var buttonConfig = button.Value; + + InitializeButton(buttonKey, buttonConfig); + InitializeButtonFeedback(buttonKey, buttonConfig); + } + + ListButtons(); + }); + } + + /// + /// Enables/disables buttons based on event type configuration + /// + /// + /// + public void InitializeButton(string key, KeypadButton config) + { + if (config == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' config is null, unable to initialize", key); + return; + } + + TryParseInt(key, out int buttonNumber); + + var buttonEventTypes = config.EventTypes; + BoolOutputSig enabledFb = null; + BoolOutputSig disabledFb = null; + + switch (key) + { + case ("power"): + { + if (buttonEventTypes == null || buttonEventTypes.Keys == null) + _touchpanel.DisablePowerButton(); + else + _touchpanel.EnablePowerButton(); + + + enabledFb = _touchpanel.PowerButtonEnabledFeedBack; + disabledFb = _touchpanel.PowerButtonDisabledFeedBack; + + break; + } + case ("mute"): + { + if (buttonEventTypes == null || buttonEventTypes.Keys == null) + _touchpanel.DisableMuteButton(); + else + _touchpanel.EnableMuteButton(); + + + enabledFb = _touchpanel.MuteButtonEnabledFeedBack; + disabledFb = _touchpanel.MuteButtonDisabledFeedBack; + + break; + } + default: + { + if (buttonNumber == 0 || buttonNumber > 9) + break; + + if (buttonEventTypes == null || buttonEventTypes.Keys == null) + _touchpanel.DisableNumericalButton((uint)buttonNumber); + else + _touchpanel.EnableNumericalButton((uint)buttonNumber); + + + if (_touchpanel.NumericalButtonEnabledFeedBack != null) + enabledFb = _touchpanel.NumericalButtonEnabledFeedBack[(uint)buttonNumber]; + + if (_touchpanel.NumericalButtonDisabledFeedBack != null) + disabledFb = _touchpanel.NumericalButtonDisabledFeedBack[(uint)buttonNumber]; + + break; + } + } + + Debug.LogMessage(LogEventLevel.Information, this, "InitializeButton: key-'{0}' enabledFb-'{1}', disabledFb-'{2}'", + key, enabledFb ?? (object)"null", disabledFb ?? (object)"null"); + } + + /// + /// Links button feedback if configured + /// + /// + /// + public void InitializeButtonFeedback(string key, KeypadButton config) + { + if (config == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' config is null, skipping.", key); + return; + } + + TryParseInt(key, out int buttonNumber); + + // Link up the button feedbacks to the specified device feedback + var buttonFeedback = config.Feedback; + if (buttonFeedback == null || string.IsNullOrEmpty(buttonFeedback.DeviceKey)) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback not configured, skipping.", + key); + return; + } + + Feedback deviceFeedback; + + try + { + if (!(DeviceManager.GetDeviceForKey(buttonFeedback.DeviceKey) is Device device)) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedback deviceKey '{1}' not found.", + key, buttonFeedback.DeviceKey); + return; + } + + deviceFeedback = device.GetFeedbackProperty(buttonFeedback.FeedbackName); + if (deviceFeedback == null) + { + Debug.LogMessage(LogEventLevel.Debug, this, "Button '{0}' feedbackName property '{1}' not found.", + key, buttonFeedback.FeedbackName); + return; + } + } + catch (Exception ex) + { + Debug.LogMessage(LogEventLevel.Debug, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') Exception Message: {0}", + ex.Message, key, buttonFeedback.DeviceKey); + Debug.LogMessage(LogEventLevel.Verbose, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') Exception StackTrace: {0}", + ex.StackTrace, key, buttonFeedback.DeviceKey); + if (ex.InnerException != null) Debug.LogMessage(LogEventLevel.Verbose, this, "InitializeButtonFeedback (button '{1}', deviceKey '{2}') InnerException: {0}", + ex.InnerException, key, buttonFeedback.DeviceKey); + + return; + } + + var boolFeedback = deviceFeedback as BoolFeedback; + + switch (key) + { + case ("power"): + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackPower); + break; + } + case ("volumeup"): + case ("volumedown"): + case ("volumefeedback"): + { + if (deviceFeedback is IntFeedback intFeedback) + { + var volumeFeedback = intFeedback; + volumeFeedback.LinkInputSig(_touchpanel.VolumeBargraph); + } + break; + } + case ("mute"): + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.FeedbackMute); + break; + } + default: + { + boolFeedback?.LinkCrestronFeedback(_touchpanel.Feedbacks[(uint)buttonNumber]); + break; + } + } + } + + /// + /// Try parse int helper method + /// + /// + /// + /// + public bool TryParseInt(string str, out int result) + { + try + { + result = int.Parse(str); + return true; + } + catch + { + result = 0; + return false; + } + } + + private void Touchpanel_BaseEvent(GenericBase device, BaseEventArgs args) + { + Debug.LogMessage(LogEventLevel.Debug, this, "BaseEvent: eventId-'{0}', index-'{1}'", args.EventId, args.Index); + } + + private void Touchpanel_ButtonStateChange(GenericBase device, Crestron.SimplSharpPro.DeviceSupport.ButtonEventArgs args) + { + Debug.LogMessage(LogEventLevel.Debug, this, "ButtonStateChange: buttonNumber-'{0}' buttonName-'{1}', buttonState-'{2}'", args.Button.Number, args.Button.Name, args.NewButtonState); + var type = args.NewButtonState.ToString(); + + if (_buttons.ContainsKey(args.Button.Number.ToString(CultureInfo.InvariantCulture))) + { + Press(args.Button.Number.ToString(CultureInfo.InvariantCulture), type); + } + else if (_buttons.ContainsKey(args.Button.Name.ToString())) + { + Press(args.Button.Name.ToString(), type); + } + } + + private void Touchpanel_PanelStateChange(GenericBase device, BaseEventArgs args) + { + Debug.LogMessage(LogEventLevel.Debug, this, "PanelStateChange: eventId-'{0}', index-'{1}'", args.EventId, args.Index); + } + + /// + /// Runs the function associated with this button/type. One of the following strings: + /// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased + /// + /// + /// + public void Press(string buttonKey, string type) + { + this.LogVerbose("Press: buttonKey-'{buttonKey}', type-'{type}'", buttonKey, type); + + if (!_buttons.ContainsKey(buttonKey)) return; + + var button = _buttons[buttonKey]; + if (!button.EventTypes.ContainsKey(type)) return; + + foreach (var eventType in button.EventTypes[type]) DeviceJsonApi.DoDeviceAction(eventType); + } + + /// + /// ListButtons method + /// + public void ListButtons() + { + this.LogVerbose("MPC4 Controller {0} - Available Buttons", Key); + + foreach (var button in _buttons) + { + this.LogVerbose("Key: {key}", button.Key); + } + } + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj index 317fa2d3..7be4372d 100644 --- a/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj +++ b/src/PepperDash.Essentials.Devices.Common/PepperDash.Essentials.Devices.Common.csproj @@ -29,6 +29,6 @@ - + \ No newline at end of file diff --git a/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj b/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj index a9223061..d13d1a09 100644 --- a/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj +++ b/src/PepperDash.Essentials.MobileControl.Messengers/PepperDash.Essentials.MobileControl.Messengers.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj b/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj index b0e2dd9f..235e0899 100644 --- a/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj +++ b/src/PepperDash.Essentials.MobileControl/PepperDash.Essentials.MobileControl.csproj @@ -38,7 +38,7 @@ - + diff --git a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs index 262cb34e..5830782d 100644 --- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs +++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs @@ -25,28 +25,11 @@ namespace PepperDash.Essentials.Touchpanel /// Mobile Control touchpanel controller that provides app control, Zoom integration, /// and mobile control functionality for Crestron touchpanels. /// - public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlCrestronTouchpanelController, ITheme, ICommunicationMonitor + public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlCrestronTouchpanelController, ITheme { private readonly MobileControlTouchpanelProperties localConfig; private IMobileControlRoomMessenger _bridge; - /// - /// Gets the CommunicationMonitor tracking the panel's online/offline state - /// - public StatusMonitorBase CommunicationMonitor { get; private set; } - - private sealed class NullCommunicationMonitor : StatusMonitorBase - { - public NullCommunicationMonitor(IKeyed parent) : base(parent, 120000, 300000) - { - Status = MonitorStatus.InError; - Message = "Panel is not initialized"; - } - - public override void Start() { } - public override void Stop() { } - } - private string _appUrl; /// @@ -145,11 +128,6 @@ namespace PepperDash.Essentials.Touchpanel { localConfig = config; - if (panel != null) - { - CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, panel, 120000, 300000); - } - AddPostActivationAction(SubscribeForMobileControlUpdates); ThemeFeedback = new StringFeedback($"{Key}-theme", () => Theme); @@ -388,8 +366,6 @@ namespace PepperDash.Essentials.Touchpanel /// public override bool CustomActivate() { - CommunicationMonitor?.Start(); - var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this); var zoomMessenger = new ITswZoomControlMessenger($"zoomControlMessenger-{Key}", $"/device/{Key}", this); @@ -417,17 +393,6 @@ namespace PepperDash.Essentials.Touchpanel return base.CustomActivate(); } - /// - /// Stops the CommunicationMonitor on deactivation. - /// - /// True if deactivation was successful; otherwise, false. - public override bool Deactivate() - { - CommunicationMonitor?.Stop(); - - return base.Deactivate(); - } - /// /// Handles device extender signal changes for system reserved signals. /// @@ -554,8 +519,15 @@ namespace PepperDash.Essentials.Touchpanel return false; }) ? csIpAddress.ToString() : processorIp; - // replace the host but preserve whatever scheme (http/https) is already present in the URL - var updatedUrl = Regex.Replace(url, @"^(https?)://[^:/]+", $"$1://{ip}"); + var match = Regex.Match(url, @"^http://([^:/]+):\d+/mc/app\?token=.+$"); + if (match.Success) + { + string ipa = match.Groups[1].Value; + // ip will be "192.168.1.100" + } + + // replace ipa with ip but leave the rest of the string intact + var updatedUrl = Regex.Replace(url, @"^http://[^:/]+", $"http://{ip}"); this.LogVerbose("Updated URL: {updatedUrl}", updatedUrl); @@ -768,7 +740,7 @@ namespace PepperDash.Essentials.Touchpanel /// public MobileControlTouchpanelControllerFactory() { - TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mctsw1080", "mcts1080", "mcxpanel", "mcdge1000" }; + TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" }; MinimumEssentialsFrameworkVersion = "2.0.0"; factories = new Dictionary> @@ -793,8 +765,6 @@ namespace PepperDash.Essentials.Touchpanel {"ts770", (id, controlSystem, projectName) => new Ts770(id, controlSystem)}, {"tsw1070", (id, controlSystem, projectName) => new Tsw1070(id, controlSystem)}, {"ts1070", (id, controlSystem, projectName) => new Ts1070(id, controlSystem)}, - {"tsw1080", (id, controlSystem, projectName) => new Tsw1080(id, controlSystem)}, - {"ts1080", (id, controlSystem, projectName) => new Ts1080(id, controlSystem)}, {"dge1000", (id, controlSystem, projectName) => new Dge1000(id, controlSystem)} }; } diff --git a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs index c96dc116..1c9ed37a 100644 --- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs +++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs @@ -127,16 +127,6 @@ namespace PepperDash.Essentials.WebSocketServer /// public int Port { get; private set; } - /// - /// Gets the HTTP scheme to use for generated URLs, based on whether the direct server is configured as secure - /// - private string HttpScheme => _parent.Config.DirectServer.Secure ? "https" : "http"; - - /// - /// Gets the WebSocket scheme to use for generated URLs, based on whether the direct server is configured as secure - /// - private string WsScheme => _parent.Config.DirectServer.Secure ? "wss" : "ws"; - /// /// Gets the user app URL prefix /// @@ -144,8 +134,7 @@ namespace PepperDash.Essentials.WebSocketServer { get { - return string.Format("{0}://{1}:{2}{3}?token=", - HttpScheme, + return string.Format("http://{0}:{1}{2}?token=", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), Port, _userAppBaseHref); @@ -284,7 +273,7 @@ namespace PepperDash.Essentials.WebSocketServer { base.Initialize(); - _server = new HttpServer(Port, _parent.Config.DirectServer.Secure); + _server = new HttpServer(Port, false); _server.OnGet += Server_OnGet; @@ -302,7 +291,7 @@ namespace PepperDash.Essentials.WebSocketServer { ClientCertificateRequired = false, CheckCertificateRevocation = false, - EnabledSslProtocols = SslProtocols.Tls12 + EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 }; } @@ -414,11 +403,11 @@ namespace PepperDash.Essentials.WebSocketServer ip = csIpAddress.ToString(); } - var appUrl = $"{HttpScheme}://{ip}:{Port}/mc/app?token={touchpanel.Key}"; + var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"; this.LogVerbose("Sending URL {appUrl} to touchpanel {touchpanelKey}", appUrl, touchpanel.Touchpanel.Key); - touchpanel.Touchpanel.SetAppUrl(appUrl); + touchpanel.Touchpanel.SetAppUrl($"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}"); } } @@ -498,7 +487,7 @@ namespace PepperDash.Essentials.WebSocketServer { var config = new MobileControlApplicationConfig { - ApiPath = string.Format("{0}://{1}:{2}/mc/api", HttpScheme, processorIp, Port), + ApiPath = string.Format("http://{0}:{1}/mc/api", processorIp, _parent.Config.DirectServer.Port), GatewayAppPath = "", LogoPath = _parent.Config.ApplicationConfig?.LogoPath ?? "logo/logo.png", EnableDev = _parent.Config.ApplicationConfig?.EnableDev ?? false, @@ -1109,7 +1098,6 @@ namespace PepperDash.Essentials.WebSocketServer res.StatusCode = 200; res.Close(); - // remote log collector has no dedicated secure flag; keep it on http regardless of DirectServer.Secure var logRequest = new HttpRequestMessage(HttpMethod.Post, $"http://{_parent.Config.DirectServer.Logging.Host}:{_parent.Config.DirectServer.Logging.Port}/logs") { Content = new StringContent(body, Encoding.UTF8, "application/json"), @@ -1162,11 +1150,6 @@ namespace PepperDash.Essentials.WebSocketServer var qp = req.QueryString; var token = qp["token"]; - // Each join mints a single-use clientId; the panel webview must never replay a cached - // response, or it reconnects forever with an already-consumed id (1008 loop). - res.Headers.Add("Cache-Control", "no-store"); - res.Headers.Add("Pragma", "no-cache"); - this.LogVerbose("Join Room Request with token: {token}", token); byte[] body; @@ -1230,7 +1213,8 @@ namespace PepperDash.Essentials.WebSocketServer this.LogVerbose("Assigning ClientId: {clientId} for token: {token} at {timestamp}", clientId, token, now); // Construct WebSocket URL with clientId query parameter - var wsUrl = $"{WsScheme}://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{Port}{_wsPath}{token}?clientId={clientId}"; + var wsProtocol = "ws"; + var wsUrl = $"{wsProtocol}://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{Port}{_wsPath}{token}?clientId={clientId}"; // Construct the response object JoinResponse jRes = new JoinResponse @@ -1242,8 +1226,7 @@ namespace PepperDash.Essentials.WebSocketServer Config = _parent.GetConfigWithPluginVersion(), CodeExpires = new DateTime().AddYears(1), UserCode = bridge.UserCode, - UserAppUrl = string.Format("{0}://{1}:{2}/mc/app", - HttpScheme, + UserAppUrl = string.Format("http://{0}:{1}/mc/app", CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0), Port), WebSocketUrl = wsUrl, @@ -1268,8 +1251,6 @@ namespace PepperDash.Essentials.WebSocketServer { res.StatusCode = 200; res.ContentType = "application/json"; - res.Headers.Add("Cache-Control", "no-store"); - res.Headers.Add("Pragma", "no-cache"); var version = new Version() { ServerVersion = _parent.GetConfigWithPluginVersion().RuntimeInfo.PluginVersion }; var message = JsonConvert.SerializeObject(version); this.LogVerbose("{message}", message); diff --git a/src/PepperDash.Essentials/ControlSystem.cs b/src/PepperDash.Essentials/ControlSystem.cs index 47de4d3e..f2888b8a 100644 --- a/src/PepperDash.Essentials/ControlSystem.cs +++ b/src/PepperDash.Essentials/ControlSystem.cs @@ -436,6 +436,25 @@ namespace PepperDash.Essentials "WARNING: Config file defines processor type as '{deviceType:l}' but actual processor is '{processorType:l}'! Some ports may not be available", devConf.Type.ToUpper(), Global.ControlSystem.ControllerPrompt.ToUpper()); + // Check if the processor is an MPC4 model + if (prompt.IndexOf("mpc4", StringComparison.OrdinalIgnoreCase) > -1) + { + Debug.LogMessage(LogEventLevel.Information, "MPC4 processor type detected. Adding Mpc4TouchpanelController."); + + var butToken = devConf.Properties["buttons"]; + if (butToken == null) + { + Debug.LogMessage(LogEventLevel.Warning, + "Error: Unable to deserialize buttons collection for device: {deviceKey}", devConf.Key); + continue; + } + + var buttons = Newtonsoft.Json.JsonConvert.DeserializeObject>(butToken.ToString()); + var tpController = new Core.Touchpanels.Mpc4TouchpanelController( + string.Format("{0}-keypadButtons", devConf.Key), devConf.Name, Global.ControlSystem, buttons); + + DeviceManager.AddDevice(tpController); + } continue; } diff --git a/src/PepperDash.Essentials/PepperDash.Essentials.csproj b/src/PepperDash.Essentials/PepperDash.Essentials.csproj index cb83bf84..20a42ffd 100644 --- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj +++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj @@ -48,7 +48,7 @@ - +