mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-08-31 19:08:29 +00:00
Compare commits
4 commits
main
...
v2.40.0-ad
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c56623641 | ||
|
|
31fd665594 | ||
|
|
d713d65c7a | ||
|
|
f5d6a076ad |
12 changed files with 390 additions and 103 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>2.42.1-local</Version>
|
<Version>2.36.6-local</Version>
|
||||||
<InformationalVersion>$(Version)</InformationalVersion>
|
<InformationalVersion>$(Version)</InformationalVersion>
|
||||||
<Authors>PepperDash Technology</Authors>
|
<Authors>PepperDash Technology</Authors>
|
||||||
<Company>PepperDash Technology</Company>
|
<Company>PepperDash Technology</Company>
|
||||||
|
|
|
||||||
|
|
@ -151,8 +151,6 @@ namespace PepperDash.Core
|
||||||
// Thread-safety lock for state changes
|
// Thread-safety lock for state changes
|
||||||
private readonly object _stateLock = new object();
|
private readonly object _stateLock = new object();
|
||||||
|
|
||||||
private volatile bool _isProgramStopping;
|
|
||||||
|
|
||||||
private bool disconnectLogged = false;
|
private bool disconnectLogged = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -209,9 +207,11 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
if (programEventType == eProgramStatusEventType.Stopping)
|
if (programEventType == eProgramStatusEventType.Stopping)
|
||||||
{
|
{
|
||||||
_isProgramStopping = true;
|
if (client != null)
|
||||||
this.LogDebug("Program stopping. Closing connection");
|
{
|
||||||
Disconnect();
|
this.LogDebug("Program stopping. Closing connection");
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,12 +228,6 @@ namespace PepperDash.Core
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isProgramStopping)
|
|
||||||
{
|
|
||||||
this.LogDebug("Skipping connect because program is stopping");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectEnabled = true;
|
ConnectEnabled = true;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -293,7 +287,13 @@ namespace PepperDash.Core
|
||||||
}
|
}
|
||||||
catch (SshConnectionException e)
|
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)
|
if (ie is System.Net.Sockets.SocketException socketException)
|
||||||
{
|
{
|
||||||
|
|
@ -301,20 +301,20 @@ namespace PepperDash.Core
|
||||||
Hostname, Port);
|
Hostname, Port);
|
||||||
this.LogVerbose(socketException, "SocketException details: ");
|
this.LogVerbose(socketException, "SocketException details: ");
|
||||||
}
|
}
|
||||||
else if (ie is SshAuthenticationException)
|
if (ie is SshAuthenticationException)
|
||||||
{
|
{
|
||||||
this.LogError("Authentication failure for username {userName}", Username);
|
this.LogError("Authentication failure for username {userName}", Username);
|
||||||
this.LogVerbose(ie, "AuthenticationException details: ");
|
this.LogVerbose(ie, "AuthenticationException details: ");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.LogError("Error on connect: {error}", ie?.Message ?? e.Message);
|
this.LogError("Error on connect: {error}", ie.Message);
|
||||||
this.LogVerbose(ie ?? e, "Exception details: ");
|
this.LogVerbose(ie, "Exception details: ");
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectLogged = true;
|
disconnectLogged = true;
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
|
if (AutoReconnect)
|
||||||
{
|
{
|
||||||
this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
StartReconnectTimer();
|
StartReconnectTimer();
|
||||||
|
|
@ -326,7 +326,7 @@ namespace PepperDash.Core
|
||||||
|
|
||||||
disconnectLogged = true;
|
disconnectLogged = true;
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
|
if (AutoReconnect)
|
||||||
{
|
{
|
||||||
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
StartReconnectTimer();
|
StartReconnectTimer();
|
||||||
|
|
@ -338,7 +338,7 @@ namespace PepperDash.Core
|
||||||
this.LogVerbose(e, "Exception details: ");
|
this.LogVerbose(e, "Exception details: ");
|
||||||
disconnectLogged = true;
|
disconnectLogged = true;
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
|
if (AutoReconnect)
|
||||||
{
|
{
|
||||||
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
StartReconnectTimer();
|
StartReconnectTimer();
|
||||||
|
|
@ -473,7 +473,7 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
connectLock.Release();
|
connectLock.Release();
|
||||||
}
|
}
|
||||||
if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
|
if (AutoReconnect && ConnectEnabled)
|
||||||
{
|
{
|
||||||
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
StartReconnectTimer();
|
StartReconnectTimer();
|
||||||
|
|
@ -516,10 +516,7 @@ namespace PepperDash.Core
|
||||||
this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim());
|
this.LogError("ObjectDisposedException sending '{message}'. Restarting connection...", text.Trim());
|
||||||
|
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
|
StartReconnectTimer();
|
||||||
{
|
|
||||||
StartReconnectTimer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -552,10 +549,7 @@ namespace PepperDash.Core
|
||||||
this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes));
|
this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes));
|
||||||
|
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect && ConnectEnabled && !_isProgramStopping)
|
StartReconnectTimer();
|
||||||
{
|
|
||||||
StartReconnectTimer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.21.274" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.21.90" />
|
||||||
<PackageReference Include="Serilog" Version="3.1.1" />
|
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||||
<PackageReference Include="Serilog.Expressions" Version="4.0.0" />
|
<PackageReference Include="Serilog.Expressions" Version="4.0.0" />
|
||||||
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
|
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
<DocumentationFile>bin\$(Configuration)\PepperDash_Essentials_Core.xml</DocumentationFile>
|
<DocumentationFile>bin\$(Configuration)\PepperDash_Essentials_Core.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.274" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.90" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />
|
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />
|
||||||
|
|
|
||||||
323
src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs
Normal file
323
src/PepperDash.Essentials.Core/Touchpanels/Mpc4Touchpanel.cs
Normal file
|
|
@ -0,0 +1,323 @@
|
||||||
|
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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A wrapper class for the touchpanel portion of an MPC4 class process to allow for configurable
|
||||||
|
/// behavior of the keypad buttons
|
||||||
|
/// </summary>
|
||||||
|
public class Mpc4TouchpanelController : Device
|
||||||
|
{
|
||||||
|
readonly MPC3Basic _touchpanel;
|
||||||
|
|
||||||
|
readonly Dictionary<string, KeypadButton> _buttons;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">device key</param>
|
||||||
|
/// <param name="name">device name</param>
|
||||||
|
/// <param name="processor">control system processor</param>
|
||||||
|
/// <param name="buttons">dictionary of keypad buttons</param>
|
||||||
|
public Mpc4TouchpanelController(string key, string name, CrestronControlSystem processor, Dictionary<string, KeypadButton> 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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables/disables buttons based on event type configuration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Links button feedback if configured
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try parse int helper method
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str"></param>
|
||||||
|
/// <param name="result"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Runs the function associated with this button/type. One of the following strings:
|
||||||
|
/// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buttonKey"></param>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ListButtons method
|
||||||
|
/// </summary>
|
||||||
|
public void ListButtons()
|
||||||
|
{
|
||||||
|
this.LogVerbose("MPC4 Controller {0} - Available Buttons", Key);
|
||||||
|
|
||||||
|
foreach (var button in _buttons)
|
||||||
|
{
|
||||||
|
this.LogVerbose("Key: {key}", button.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,6 @@
|
||||||
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
|
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.274" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.90" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -33,7 +33,7 @@
|
||||||
<Compile Remove="Messengers\SIMPLVtcMessenger.cs" />
|
<Compile Remove="Messengers\SIMPLVtcMessenger.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.274" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.90" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\PepperDash.Core\PepperDash.Core.csproj" />
|
<ProjectReference Include="..\PepperDash.Core\PepperDash.Core.csproj" />
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
<Compile Remove="RoomBridges\SourceDeviceMapDictionary.cs" />
|
<Compile Remove="RoomBridges\SourceDeviceMapDictionary.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.274" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.90" />
|
||||||
<PackageReference Include="WebSocketSharp-netstandard" Version="1.0.1" />
|
<PackageReference Include="WebSocketSharp-netstandard" Version="1.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -25,28 +25,11 @@ namespace PepperDash.Essentials.Touchpanel
|
||||||
/// Mobile Control touchpanel controller that provides app control, Zoom integration,
|
/// Mobile Control touchpanel controller that provides app control, Zoom integration,
|
||||||
/// and mobile control functionality for Crestron touchpanels.
|
/// and mobile control functionality for Crestron touchpanels.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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 readonly MobileControlTouchpanelProperties localConfig;
|
||||||
private IMobileControlRoomMessenger _bridge;
|
private IMobileControlRoomMessenger _bridge;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the CommunicationMonitor tracking the panel's online/offline state
|
|
||||||
/// </summary>
|
|
||||||
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;
|
private string _appUrl;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -145,11 +128,6 @@ namespace PepperDash.Essentials.Touchpanel
|
||||||
{
|
{
|
||||||
localConfig = config;
|
localConfig = config;
|
||||||
|
|
||||||
if (panel != null)
|
|
||||||
{
|
|
||||||
CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, panel, 120000, 300000);
|
|
||||||
}
|
|
||||||
|
|
||||||
AddPostActivationAction(SubscribeForMobileControlUpdates);
|
AddPostActivationAction(SubscribeForMobileControlUpdates);
|
||||||
|
|
||||||
ThemeFeedback = new StringFeedback($"{Key}-theme", () => Theme);
|
ThemeFeedback = new StringFeedback($"{Key}-theme", () => Theme);
|
||||||
|
|
@ -388,8 +366,6 @@ namespace PepperDash.Essentials.Touchpanel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool CustomActivate()
|
public override bool CustomActivate()
|
||||||
{
|
{
|
||||||
CommunicationMonitor?.Start();
|
|
||||||
|
|
||||||
var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this);
|
var appMessenger = new ITswAppControlMessenger($"appControlMessenger-{Key}", $"/device/{Key}", this);
|
||||||
|
|
||||||
var zoomMessenger = new ITswZoomControlMessenger($"zoomControlMessenger-{Key}", $"/device/{Key}", this);
|
var zoomMessenger = new ITswZoomControlMessenger($"zoomControlMessenger-{Key}", $"/device/{Key}", this);
|
||||||
|
|
@ -417,17 +393,6 @@ namespace PepperDash.Essentials.Touchpanel
|
||||||
return base.CustomActivate();
|
return base.CustomActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Stops the CommunicationMonitor on deactivation.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if deactivation was successful; otherwise, false.</returns>
|
|
||||||
public override bool Deactivate()
|
|
||||||
{
|
|
||||||
CommunicationMonitor?.Stop();
|
|
||||||
|
|
||||||
return base.Deactivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles device extender signal changes for system reserved signals.
|
/// Handles device extender signal changes for system reserved signals.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -554,8 +519,15 @@ namespace PepperDash.Essentials.Touchpanel
|
||||||
return false;
|
return false;
|
||||||
}) ? csIpAddress.ToString() : processorIp;
|
}) ? csIpAddress.ToString() : processorIp;
|
||||||
|
|
||||||
// replace the host but preserve whatever scheme (http/https) is already present in the URL
|
var match = Regex.Match(url, @"^http://([^:/]+):\d+/mc/app\?token=.+$");
|
||||||
var updatedUrl = Regex.Replace(url, @"^(https?)://[^:/]+", $"$1://{ip}");
|
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);
|
this.LogVerbose("Updated URL: {updatedUrl}", updatedUrl);
|
||||||
|
|
||||||
|
|
@ -768,7 +740,7 @@ namespace PepperDash.Essentials.Touchpanel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MobileControlTouchpanelControllerFactory()
|
public MobileControlTouchpanelControllerFactory()
|
||||||
{
|
{
|
||||||
TypeNames = new List<string>() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mctsw1080", "mcts1080", "mcxpanel", "mcdge1000" };
|
TypeNames = new List<string>() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" };
|
||||||
MinimumEssentialsFrameworkVersion = "2.0.0";
|
MinimumEssentialsFrameworkVersion = "2.0.0";
|
||||||
|
|
||||||
factories = new Dictionary<string, Func<uint, CrestronControlSystem, string, BasicTriListWithSmartObject>>
|
factories = new Dictionary<string, Func<uint, CrestronControlSystem, string, BasicTriListWithSmartObject>>
|
||||||
|
|
@ -793,8 +765,6 @@ namespace PepperDash.Essentials.Touchpanel
|
||||||
{"ts770", (id, controlSystem, projectName) => new Ts770(id, controlSystem)},
|
{"ts770", (id, controlSystem, projectName) => new Ts770(id, controlSystem)},
|
||||||
{"tsw1070", (id, controlSystem, projectName) => new Tsw1070(id, controlSystem)},
|
{"tsw1070", (id, controlSystem, projectName) => new Tsw1070(id, controlSystem)},
|
||||||
{"ts1070", (id, controlSystem, projectName) => new Ts1070(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)}
|
{"dge1000", (id, controlSystem, projectName) => new Dge1000(id, controlSystem)}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,16 +127,6 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Port { get; private set; }
|
public int Port { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the HTTP scheme to use for generated URLs, based on whether the direct server is configured as secure
|
|
||||||
/// </summary>
|
|
||||||
private string HttpScheme => _parent.Config.DirectServer.Secure ? "https" : "http";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the WebSocket scheme to use for generated URLs, based on whether the direct server is configured as secure
|
|
||||||
/// </summary>
|
|
||||||
private string WsScheme => _parent.Config.DirectServer.Secure ? "wss" : "ws";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user app URL prefix
|
/// Gets the user app URL prefix
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -144,8 +134,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return string.Format("{0}://{1}:{2}{3}?token=",
|
return string.Format("http://{0}:{1}{2}?token=",
|
||||||
HttpScheme,
|
|
||||||
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
|
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
|
||||||
Port,
|
Port,
|
||||||
_userAppBaseHref);
|
_userAppBaseHref);
|
||||||
|
|
@ -284,7 +273,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_server = new HttpServer(Port, _parent.Config.DirectServer.Secure);
|
_server = new HttpServer(Port, false);
|
||||||
|
|
||||||
_server.OnGet += Server_OnGet;
|
_server.OnGet += Server_OnGet;
|
||||||
|
|
||||||
|
|
@ -302,7 +291,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
{
|
{
|
||||||
ClientCertificateRequired = false,
|
ClientCertificateRequired = false,
|
||||||
CheckCertificateRevocation = false,
|
CheckCertificateRevocation = false,
|
||||||
EnabledSslProtocols = SslProtocols.Tls12
|
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -414,11 +403,11 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
ip = csIpAddress.ToString();
|
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);
|
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
|
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 = "",
|
GatewayAppPath = "",
|
||||||
LogoPath = _parent.Config.ApplicationConfig?.LogoPath ?? "logo/logo.png",
|
LogoPath = _parent.Config.ApplicationConfig?.LogoPath ?? "logo/logo.png",
|
||||||
EnableDev = _parent.Config.ApplicationConfig?.EnableDev ?? false,
|
EnableDev = _parent.Config.ApplicationConfig?.EnableDev ?? false,
|
||||||
|
|
@ -1109,7 +1098,6 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
res.StatusCode = 200;
|
res.StatusCode = 200;
|
||||||
res.Close();
|
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")
|
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"),
|
Content = new StringContent(body, Encoding.UTF8, "application/json"),
|
||||||
|
|
@ -1162,11 +1150,6 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
var qp = req.QueryString;
|
var qp = req.QueryString;
|
||||||
var token = qp["token"];
|
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);
|
this.LogVerbose("Join Room Request with token: {token}", token);
|
||||||
|
|
||||||
byte[] body;
|
byte[] body;
|
||||||
|
|
@ -1230,7 +1213,8 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
this.LogVerbose("Assigning ClientId: {clientId} for token: {token} at {timestamp}", clientId, token, now);
|
this.LogVerbose("Assigning ClientId: {clientId} for token: {token} at {timestamp}", clientId, token, now);
|
||||||
|
|
||||||
// Construct WebSocket URL with clientId query parameter
|
// 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
|
// Construct the response object
|
||||||
JoinResponse jRes = new JoinResponse
|
JoinResponse jRes = new JoinResponse
|
||||||
|
|
@ -1242,8 +1226,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
Config = _parent.GetConfigWithPluginVersion(),
|
Config = _parent.GetConfigWithPluginVersion(),
|
||||||
CodeExpires = new DateTime().AddYears(1),
|
CodeExpires = new DateTime().AddYears(1),
|
||||||
UserCode = bridge.UserCode,
|
UserCode = bridge.UserCode,
|
||||||
UserAppUrl = string.Format("{0}://{1}:{2}/mc/app",
|
UserAppUrl = string.Format("http://{0}:{1}/mc/app",
|
||||||
HttpScheme,
|
|
||||||
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
|
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
|
||||||
Port),
|
Port),
|
||||||
WebSocketUrl = wsUrl,
|
WebSocketUrl = wsUrl,
|
||||||
|
|
@ -1268,8 +1251,6 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||||
{
|
{
|
||||||
res.StatusCode = 200;
|
res.StatusCode = 200;
|
||||||
res.ContentType = "application/json";
|
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 version = new Version() { ServerVersion = _parent.GetConfigWithPluginVersion().RuntimeInfo.PluginVersion };
|
||||||
var message = JsonConvert.SerializeObject(version);
|
var message = JsonConvert.SerializeObject(version);
|
||||||
this.LogVerbose("{message}", message);
|
this.LogVerbose("{message}", message);
|
||||||
|
|
|
||||||
|
|
@ -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",
|
"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());
|
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<System.Collections.Generic.Dictionary<string, Core.Touchpanels.KeypadButton>>(butToken.ToString());
|
||||||
|
var tpController = new Core.Touchpanels.Mpc4TouchpanelController(
|
||||||
|
string.Format("{0}-keypadButtons", devConf.Key), devConf.Name, Global.ControlSystem, buttons);
|
||||||
|
|
||||||
|
DeviceManager.AddDevice(tpController);
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.21.274" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.21.90" />
|
||||||
<PackageReference Include="System.IO.Compression" Version="4.0.0" />
|
<PackageReference Include="System.IO.Compression" Version="4.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue