diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index ab9f2732..235fee48 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,6 +1,6 @@
- 2.36.6-local
+ 2.42.1-local
$(Version)
PepperDash Technology
PepperDash Technology
diff --git a/src/PepperDash.Core/Comm/GenericSshClient.cs b/src/PepperDash.Core/Comm/GenericSshClient.cs
index df44ab51..546a2a67 100644
--- a/src/PepperDash.Core/Comm/GenericSshClient.cs
+++ b/src/PepperDash.Core/Comm/GenericSshClient.cs
@@ -151,6 +151,8 @@ namespace PepperDash.Core
// Thread-safety lock for state changes
private readonly object _stateLock = new object();
+ private volatile bool _isProgramStopping;
+
private bool disconnectLogged = false;
///
@@ -207,11 +209,9 @@ namespace PepperDash.Core
{
if (programEventType == eProgramStatusEventType.Stopping)
{
- if (client != null)
- {
- this.LogDebug("Program stopping. Closing connection");
- Disconnect();
- }
+ _isProgramStopping = true;
+ this.LogDebug("Program stopping. Closing connection");
+ Disconnect();
}
}
@@ -228,6 +228,12 @@ namespace PepperDash.Core
return;
}
+ if (_isProgramStopping)
+ {
+ this.LogDebug("Skipping connect because program is stopping");
+ return;
+ }
+
ConnectEnabled = true;
try
@@ -287,13 +293,7 @@ namespace PepperDash.Core
}
catch (SshConnectionException e)
{
- var ie = e.InnerException; // The details are inside!!
-
- if (ie is SocketException)
- {
- this.LogError("CONNECTION failure: Cannot reach host");
- this.LogVerbose(ie, "Exception details: ");
- }
+ var ie = e.InnerException; // The details are inside, when present - remote can close the connection with no inner exception at all
if (ie is System.Net.Sockets.SocketException socketException)
{
@@ -301,20 +301,20 @@ namespace PepperDash.Core
Hostname, Port);
this.LogVerbose(socketException, "SocketException details: ");
}
- if (ie is SshAuthenticationException)
+ else 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);
- this.LogVerbose(ie, "Exception details: ");
+ this.LogError("Error on connect: {error}", ie?.Message ?? e.Message);
+ this.LogVerbose(ie ?? e, "Exception details: ");
}
disconnectLogged = true;
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
- if (AutoReconnect)
+ if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
{
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)
+ if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
{
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)
+ if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
{
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
StartReconnectTimer();
@@ -473,7 +473,7 @@ namespace PepperDash.Core
{
connectLock.Release();
}
- if (AutoReconnect && ConnectEnabled)
+ if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
{
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
StartReconnectTimer();
@@ -516,7 +516,10 @@ namespace PepperDash.Core
this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim());
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
- StartReconnectTimer();
+ if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
+ {
+ StartReconnectTimer();
+ }
}
catch (Exception ex)
{
@@ -549,7 +552,10 @@ namespace PepperDash.Core
this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes));
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
- StartReconnectTimer();
+ if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
+ {
+ StartReconnectTimer();
+ }
}
catch (Exception ex)
{
diff --git a/src/PepperDash.Core/PepperDash.Core.csproj b/src/PepperDash.Core/PepperDash.Core.csproj
index daa5c6da..747aefb6 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 251ba316..b7f333bd 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
deleted file mode 100644
index 85a7b987..00000000
--- a/src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs
+++ /dev/null
@@ -1,323 +0,0 @@
-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)
- {
- if (processor.MPC4x102TouchscreenSlot != null)
- {
- _touchpanel = processor.MPC4x102TouchscreenSlot;
- }
- else if (processor.MPC4x201TouchscreenSlot != null)
- {
- _touchpanel = processor.MPC4x201TouchscreenSlot;
- }
- else if (processor.MPC4x301TouchscreenSlot != null)
- {
- _touchpanel = processor.MPC4x301TouchscreenSlot;
- }
- else if (processor.MPC4x302TouchscreenSlot != null)
- {
- _touchpanel = processor.MPC4x302TouchscreenSlot;
- }
-
- 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 7be4372d..317fa2d3 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 d13d1a09..a9223061 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 235e0899..b0e2dd9f 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 5830782d..262cb34e 100644
--- a/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs
+++ b/src/PepperDash.Essentials.MobileControl/Touchpanel/MobileControlTouchpanelController.cs
@@ -25,11 +25,28 @@ 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
+ public class MobileControlTouchpanelController : TouchpanelBase, IHasFeedback, ITswAppControl, ITswZoomControl, IDeviceInfoProvider, IMobileControlCrestronTouchpanelController, ITheme, ICommunicationMonitor
{
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;
///
@@ -128,6 +145,11 @@ namespace PepperDash.Essentials.Touchpanel
{
localConfig = config;
+ if (panel != null)
+ {
+ CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, panel, 120000, 300000);
+ }
+
AddPostActivationAction(SubscribeForMobileControlUpdates);
ThemeFeedback = new StringFeedback($"{Key}-theme", () => Theme);
@@ -366,6 +388,8 @@ 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);
@@ -393,6 +417,17 @@ 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.
///
@@ -519,15 +554,8 @@ namespace PepperDash.Essentials.Touchpanel
return false;
}) ? csIpAddress.ToString() : processorIp;
- 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}");
+ // replace the host but preserve whatever scheme (http/https) is already present in the URL
+ var updatedUrl = Regex.Replace(url, @"^(https?)://[^:/]+", $"$1://{ip}");
this.LogVerbose("Updated URL: {updatedUrl}", updatedUrl);
@@ -740,7 +768,7 @@ namespace PepperDash.Essentials.Touchpanel
///
public MobileControlTouchpanelControllerFactory()
{
- TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" };
+ TypeNames = new List() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mctsw1080", "mcts1080", "mcxpanel", "mcdge1000" };
MinimumEssentialsFrameworkVersion = "2.0.0";
factories = new Dictionary>
@@ -765,6 +793,8 @@ 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 1c9ed37a..c96dc116 100644
--- a/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs
+++ b/src/PepperDash.Essentials.MobileControl/WebSocketServer/MobileControlWebsocketServer.cs
@@ -127,6 +127,16 @@ 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
///
@@ -134,7 +144,8 @@ namespace PepperDash.Essentials.WebSocketServer
{
get
{
- return string.Format("http://{0}:{1}{2}?token=",
+ return string.Format("{0}://{1}:{2}{3}?token=",
+ HttpScheme,
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
Port,
_userAppBaseHref);
@@ -273,7 +284,7 @@ namespace PepperDash.Essentials.WebSocketServer
{
base.Initialize();
- _server = new HttpServer(Port, false);
+ _server = new HttpServer(Port, _parent.Config.DirectServer.Secure);
_server.OnGet += Server_OnGet;
@@ -291,7 +302,7 @@ namespace PepperDash.Essentials.WebSocketServer
{
ClientCertificateRequired = false,
CheckCertificateRevocation = false,
- EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11
+ EnabledSslProtocols = SslProtocols.Tls12
};
}
@@ -403,11 +414,11 @@ namespace PepperDash.Essentials.WebSocketServer
ip = csIpAddress.ToString();
}
- var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}";
+ var appUrl = $"{HttpScheme}://{ip}:{Port}/mc/app?token={touchpanel.Key}";
this.LogVerbose("Sending URL {appUrl} to touchpanel {touchpanelKey}", appUrl, touchpanel.Touchpanel.Key);
- touchpanel.Touchpanel.SetAppUrl($"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}");
+ touchpanel.Touchpanel.SetAppUrl(appUrl);
}
}
@@ -487,7 +498,7 @@ namespace PepperDash.Essentials.WebSocketServer
{
var config = new MobileControlApplicationConfig
{
- ApiPath = string.Format("http://{0}:{1}/mc/api", processorIp, _parent.Config.DirectServer.Port),
+ ApiPath = string.Format("{0}://{1}:{2}/mc/api", HttpScheme, processorIp, Port),
GatewayAppPath = "",
LogoPath = _parent.Config.ApplicationConfig?.LogoPath ?? "logo/logo.png",
EnableDev = _parent.Config.ApplicationConfig?.EnableDev ?? false,
@@ -1098,6 +1109,7 @@ 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"),
@@ -1150,6 +1162,11 @@ 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;
@@ -1213,8 +1230,7 @@ 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 wsProtocol = "ws";
- var wsUrl = $"{wsProtocol}://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{Port}{_wsPath}{token}?clientId={clientId}";
+ var wsUrl = $"{WsScheme}://{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
@@ -1226,7 +1242,8 @@ namespace PepperDash.Essentials.WebSocketServer
Config = _parent.GetConfigWithPluginVersion(),
CodeExpires = new DateTime().AddYears(1),
UserCode = bridge.UserCode,
- UserAppUrl = string.Format("http://{0}:{1}/mc/app",
+ UserAppUrl = string.Format("{0}://{1}:{2}/mc/app",
+ HttpScheme,
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
Port),
WebSocketUrl = wsUrl,
@@ -1251,6 +1268,8 @@ 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 f2888b8a..47de4d3e 100644
--- a/src/PepperDash.Essentials/ControlSystem.cs
+++ b/src/PepperDash.Essentials/ControlSystem.cs
@@ -436,25 +436,6 @@ 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 20a42ffd..cb83bf84 100644
--- a/src/PepperDash.Essentials/PepperDash.Essentials.csproj
+++ b/src/PepperDash.Essentials/PepperDash.Essentials.csproj
@@ -48,7 +48,7 @@
-
+