mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-15 04:34:56 +00:00
1
.gitignore
vendored
1
.gitignore
vendored
@@ -396,3 +396,4 @@ _site/
|
|||||||
api/
|
api/
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
/._PepperDash.Essentials.4Series.sln
|
/._PepperDash.Essentials.4Series.sln
|
||||||
|
dotnet
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>2.15.1-local</Version>
|
<Version>2.19.4-local</Version>
|
||||||
<InformationalVersion>$(Version)</InformationalVersion>
|
<InformationalVersion>$(Version)</InformationalVersion>
|
||||||
<Authors>PepperDash Technology</Authors>
|
<Authors>PepperDash Technology</Authors>
|
||||||
<Company>PepperDash Technology</Company>
|
<Company>PepperDash Technology</Company>
|
||||||
|
|||||||
43
src/PepperDash.Core/ComTextHelper.cs
Normal file
43
src/PepperDash.Core/ComTextHelper.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace PepperDash.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helper class for formatting communication text and byte data for debugging purposes.
|
||||||
|
/// </summary>
|
||||||
|
public class ComTextHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets escaped text for a byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bytes"></param>
|
||||||
|
/// <returns>string with all bytes escaped</returns>
|
||||||
|
public static string GetEscapedText(byte[] bytes)
|
||||||
|
{
|
||||||
|
return string.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets escaped text for a string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// <returns>string with all bytes escaped</returns>
|
||||||
|
public static string GetEscapedText(string text)
|
||||||
|
{
|
||||||
|
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
|
||||||
|
return string.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets debug text for a string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// <returns>string with all non-printable characters escaped</returns>
|
||||||
|
public static string GetDebugText(string text)
|
||||||
|
{
|
||||||
|
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
@@ -37,14 +36,14 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _DebugTimeoutInMs/60000;
|
return _DebugTimeoutInMs / 60000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the RxStreamDebuggingIsEnabled
|
/// Gets or sets the RxStreamDebuggingIsEnabled
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RxStreamDebuggingIsEnabled{ get; private set; }
|
public bool RxStreamDebuggingIsEnabled { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that transmit stream debugging is enabled
|
/// Indicates that transmit stream debugging is enabled
|
||||||
@@ -136,51 +135,4 @@ namespace PepperDash.Core
|
|||||||
DebugExpiryPeriod = null;
|
DebugExpiryPeriod = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The available settings for stream debugging
|
|
||||||
/// </summary>
|
|
||||||
[Flags]
|
|
||||||
/// <summary>
|
|
||||||
/// Enumeration of eStreamDebuggingSetting values
|
|
||||||
/// </summary>
|
|
||||||
public enum eStreamDebuggingSetting
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Debug off
|
|
||||||
/// </summary>
|
|
||||||
Off = 0,
|
|
||||||
/// <summary>
|
|
||||||
/// Debug received data
|
|
||||||
/// </summary>
|
|
||||||
Rx = 1,
|
|
||||||
/// <summary>
|
|
||||||
/// Debug transmitted data
|
|
||||||
/// </summary>
|
|
||||||
Tx = 2,
|
|
||||||
/// <summary>
|
|
||||||
/// Debug both received and transmitted data
|
|
||||||
/// </summary>
|
|
||||||
Both = Rx | Tx
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The available settings for stream debugging response types
|
|
||||||
/// </summary>
|
|
||||||
[Flags]
|
|
||||||
public enum eStreamDebuggingDataTypeSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Debug data in byte format
|
|
||||||
/// </summary>
|
|
||||||
Bytes = 0,
|
|
||||||
/// <summary>
|
|
||||||
/// Debug data in text format
|
|
||||||
/// </summary>
|
|
||||||
Text = 1,
|
|
||||||
/// <summary>
|
|
||||||
/// Debug data in both byte and text formats
|
|
||||||
/// </summary>
|
|
||||||
Both = Bytes | Text,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
@@ -11,11 +12,12 @@ using Renci.SshNet.Common;
|
|||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// SSH Client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
|
public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
|
||||||
{
|
{
|
||||||
private const string SPlusKey = "Uninitialized SshClient";
|
private const string SPlusKey = "Uninitialized SshClient";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Object to enable stream debugging
|
/// Object to enable stream debugging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -36,11 +38,6 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
|
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/////
|
|
||||||
///// </summary>
|
|
||||||
//public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Hostname
|
/// Gets or sets the Hostname
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -67,7 +64,7 @@ namespace PepperDash.Core
|
|||||||
public bool IsConnected
|
public bool IsConnected
|
||||||
{
|
{
|
||||||
// returns false if no client or not connected
|
// returns false if no client or not connected
|
||||||
get { return Client != null && ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
|
get { return client != null && ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -83,16 +80,26 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public SocketStatus ClientStatus
|
public SocketStatus ClientStatus
|
||||||
{
|
{
|
||||||
get { return _ClientStatus; }
|
get { lock (_stateLock) { return _ClientStatus; } }
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
if (_ClientStatus == value)
|
bool shouldFireEvent = false;
|
||||||
return;
|
lock (_stateLock)
|
||||||
_ClientStatus = value;
|
{
|
||||||
OnConnectionChange();
|
if (_ClientStatus != value)
|
||||||
|
{
|
||||||
|
_ClientStatus = value;
|
||||||
|
shouldFireEvent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fire event outside lock to avoid deadlock
|
||||||
|
if (shouldFireEvent)
|
||||||
|
OnConnectionChange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SocketStatus _ClientStatus;
|
|
||||||
|
private SocketStatus _ClientStatus;
|
||||||
|
private bool _ConnectEnabled;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the familiar Simpl analog status values. This drives the ConnectionChange event
|
/// Contains the familiar Simpl analog status values. This drives the ConnectionChange event
|
||||||
@@ -100,7 +107,7 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ushort UStatus
|
public ushort UStatus
|
||||||
{
|
{
|
||||||
get { return (ushort)_ClientStatus; }
|
get { lock (_stateLock) { return (ushort)_ClientStatus; } }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -111,7 +118,11 @@ namespace PepperDash.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Will be set and unset by connect and disconnect only
|
/// Will be set and unset by connect and disconnect only
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ConnectEnabled { get; private set; }
|
public bool ConnectEnabled
|
||||||
|
{
|
||||||
|
get { lock (_stateLock) { return _ConnectEnabled; } }
|
||||||
|
private set { lock (_stateLock) { _ConnectEnabled = value; } }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// S+ helper for AutoReconnect
|
/// S+ helper for AutoReconnect
|
||||||
@@ -127,17 +138,25 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int AutoReconnectIntervalMs { get; set; }
|
public int AutoReconnectIntervalMs { get; set; }
|
||||||
|
|
||||||
SshClient Client;
|
private SshClient client;
|
||||||
|
|
||||||
ShellStream TheStream;
|
private ShellStream shellStream;
|
||||||
|
|
||||||
CTimer ReconnectTimer;
|
private readonly Timer reconnectTimer;
|
||||||
|
|
||||||
//Lock object to prevent simulatneous connect/disconnect operations
|
//Lock object to prevent simulatneous connect/disconnect operations
|
||||||
//private CCriticalSection connectLock = new CCriticalSection();
|
//private CCriticalSection connectLock = new CCriticalSection();
|
||||||
private SemaphoreSlim connectLock = new SemaphoreSlim(1);
|
private readonly SemaphoreSlim connectLock = new SemaphoreSlim(1);
|
||||||
|
|
||||||
private bool DisconnectLogged = false;
|
// Thread-safety lock for state changes
|
||||||
|
private readonly object _stateLock = new object();
|
||||||
|
|
||||||
|
private bool disconnectLogged = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When true, turns off echo for the SSH session
|
||||||
|
/// </summary>
|
||||||
|
public bool DisableEcho { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Typical constructor.
|
/// Typical constructor.
|
||||||
@@ -154,13 +173,13 @@ namespace PepperDash.Core
|
|||||||
Password = password;
|
Password = password;
|
||||||
AutoReconnectIntervalMs = 5000;
|
AutoReconnectIntervalMs = 5000;
|
||||||
|
|
||||||
ReconnectTimer = new CTimer(o =>
|
reconnectTimer = new Timer(o =>
|
||||||
{
|
{
|
||||||
if (ConnectEnabled)
|
if (ConnectEnabled) // Now thread-safe property access
|
||||||
{
|
{
|
||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
}, System.Threading.Timeout.Infinite);
|
}, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -172,23 +191,23 @@ namespace PepperDash.Core
|
|||||||
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
||||||
AutoReconnectIntervalMs = 5000;
|
AutoReconnectIntervalMs = 5000;
|
||||||
|
|
||||||
ReconnectTimer = new CTimer(o =>
|
reconnectTimer = new Timer(o =>
|
||||||
{
|
{
|
||||||
if (ConnectEnabled)
|
if (ConnectEnabled) // Now thread-safe property access
|
||||||
{
|
{
|
||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
}, System.Threading.Timeout.Infinite);
|
}, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles closing this up when the program shuts down
|
/// Handles closing this up when the program shuts down
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
|
private void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
|
||||||
{
|
{
|
||||||
if (programEventType == eProgramStatusEventType.Stopping)
|
if (programEventType == eProgramStatusEventType.Stopping)
|
||||||
{
|
{
|
||||||
if (Client != null)
|
if (client != null)
|
||||||
{
|
{
|
||||||
this.LogDebug("Program stopping. Closing connection");
|
this.LogDebug("Program stopping. Closing connection");
|
||||||
Disconnect();
|
Disconnect();
|
||||||
@@ -223,10 +242,10 @@ namespace PepperDash.Core
|
|||||||
this.LogDebug("Attempting connect");
|
this.LogDebug("Attempting connect");
|
||||||
|
|
||||||
// Cancel reconnect if running.
|
// Cancel reconnect if running.
|
||||||
ReconnectTimer?.Stop();
|
StopReconnectTimer();
|
||||||
|
|
||||||
// Cleanup the old client if it already exists
|
// Cleanup the old client if it already exists
|
||||||
if (Client != null)
|
if (client != null)
|
||||||
{
|
{
|
||||||
this.LogDebug("Cleaning up disconnected client");
|
this.LogDebug("Cleaning up disconnected client");
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
||||||
@@ -239,29 +258,36 @@ namespace PepperDash.Core
|
|||||||
|
|
||||||
this.LogDebug("Creating new SshClient");
|
this.LogDebug("Creating new SshClient");
|
||||||
ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth);
|
ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth);
|
||||||
Client = new SshClient(connectionInfo);
|
client = new SshClient(connectionInfo);
|
||||||
Client.ErrorOccurred += Client_ErrorOccurred;
|
client.ErrorOccurred += Client_ErrorOccurred;
|
||||||
|
|
||||||
//Attempt to connect
|
//Attempt to connect
|
||||||
ClientStatus = SocketStatus.SOCKET_STATUS_WAITING;
|
ClientStatus = SocketStatus.SOCKET_STATUS_WAITING;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Client.Connect();
|
client.Connect();
|
||||||
TheStream = Client.CreateShellStream("PDTShell", 0, 0, 0, 0, 65534);
|
|
||||||
if (TheStream.DataAvailable)
|
var modes = new Dictionary<TerminalModes, uint>();
|
||||||
|
|
||||||
|
if (DisableEcho)
|
||||||
|
{
|
||||||
|
modes.Add(TerminalModes.ECHO, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
shellStream = client.CreateShellStream("PDTShell", 0, 0, 0, 0, 65534, modes);
|
||||||
|
if (shellStream.DataAvailable)
|
||||||
{
|
{
|
||||||
// empty the buffer if there is data
|
// empty the buffer if there is data
|
||||||
string str = TheStream.Read();
|
shellStream.Read();
|
||||||
}
|
}
|
||||||
TheStream.DataReceived += Stream_DataReceived;
|
shellStream.DataReceived += Stream_DataReceived;
|
||||||
this.LogInformation("Connected");
|
this.LogInformation("Connected");
|
||||||
ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED;
|
ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED;
|
||||||
DisconnectLogged = false;
|
disconnectLogged = false;
|
||||||
}
|
}
|
||||||
catch (SshConnectionException e)
|
catch (SshConnectionException e)
|
||||||
{
|
{
|
||||||
var ie = e.InnerException; // The details are inside!!
|
var ie = e.InnerException; // The details are inside!!
|
||||||
var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error;
|
|
||||||
|
|
||||||
if (ie is SocketException)
|
if (ie is SocketException)
|
||||||
{
|
{
|
||||||
@@ -286,37 +312,36 @@ namespace PepperDash.Core
|
|||||||
this.LogVerbose(ie, "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)
|
if (AutoReconnect)
|
||||||
{
|
{
|
||||||
this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {autoReconnect}, {autoReconnectInterval}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
StartReconnectTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (SshOperationTimeoutException ex)
|
catch (SshOperationTimeoutException ex)
|
||||||
{
|
{
|
||||||
this.LogWarning("Connection attempt timed out: {message}", ex.Message);
|
this.LogWarning("Connection attempt timed out: {message}", ex.Message);
|
||||||
|
|
||||||
DisconnectLogged = true;
|
disconnectLogged = true;
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect)
|
if (AutoReconnect)
|
||||||
{
|
{
|
||||||
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
StartReconnectTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error;
|
|
||||||
this.LogError("Unhandled exception on connect: {error}", e.Message);
|
this.LogError("Unhandled exception on connect: {error}", e.Message);
|
||||||
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)
|
if (AutoReconnect)
|
||||||
{
|
{
|
||||||
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
StartReconnectTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,11 +359,7 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
ConnectEnabled = false;
|
ConnectEnabled = false;
|
||||||
// Stop trying reconnects, if we are
|
// Stop trying reconnects, if we are
|
||||||
if (ReconnectTimer != null)
|
StopReconnectTimer();
|
||||||
{
|
|
||||||
ReconnectTimer.Stop();
|
|
||||||
// ReconnectTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
||||||
}
|
}
|
||||||
@@ -352,12 +373,12 @@ namespace PepperDash.Core
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Client != null)
|
if (client != null)
|
||||||
{
|
{
|
||||||
Client.ErrorOccurred -= Client_ErrorOccurred;
|
client.ErrorOccurred -= Client_ErrorOccurred;
|
||||||
Client.Disconnect();
|
client.Disconnect();
|
||||||
Client.Dispose();
|
client.Dispose();
|
||||||
Client = null;
|
client = null;
|
||||||
ClientStatus = status;
|
ClientStatus = status;
|
||||||
this.LogDebug("Disconnected");
|
this.LogDebug("Disconnected");
|
||||||
}
|
}
|
||||||
@@ -371,16 +392,16 @@ namespace PepperDash.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Kills the stream
|
/// Kills the stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void KillStream()
|
private void KillStream()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (TheStream != null)
|
if (shellStream != null)
|
||||||
{
|
{
|
||||||
TheStream.DataReceived -= Stream_DataReceived;
|
shellStream.DataReceived -= Stream_DataReceived;
|
||||||
TheStream.Close();
|
shellStream.Close();
|
||||||
TheStream.Dispose();
|
shellStream.Dispose();
|
||||||
TheStream = null;
|
shellStream = null;
|
||||||
this.LogDebug("Disconnected stream");
|
this.LogDebug("Disconnected stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,7 +414,7 @@ namespace PepperDash.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the keyboard interactive authentication, should it be required.
|
/// Handles the keyboard interactive authentication, should it be required.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e)
|
private void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e)
|
||||||
{
|
{
|
||||||
foreach (AuthenticationPrompt prompt in e.Prompts)
|
foreach (AuthenticationPrompt prompt in e.Prompts)
|
||||||
if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
|
if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1)
|
||||||
@@ -403,7 +424,7 @@ namespace PepperDash.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for data receive on ShellStream. Passes data across to queue for line parsing.
|
/// Handler for data receive on ShellStream. Passes data across to queue for line parsing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Stream_DataReceived(object sender, ShellDataEventArgs e)
|
private void Stream_DataReceived(object sender, ShellDataEventArgs e)
|
||||||
{
|
{
|
||||||
if (((ShellStream)sender).Length <= 0L)
|
if (((ShellStream)sender).Length <= 0L)
|
||||||
{
|
{
|
||||||
@@ -416,18 +437,14 @@ namespace PepperDash.Core
|
|||||||
if (bytesHandler != null)
|
if (bytesHandler != null)
|
||||||
{
|
{
|
||||||
var bytes = Encoding.UTF8.GetBytes(response);
|
var bytes = Encoding.UTF8.GetBytes(response);
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedBytes(bytes);
|
||||||
{
|
|
||||||
this.LogInformation("Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
|
|
||||||
}
|
|
||||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
var textHandler = TextReceived;
|
var textHandler = TextReceived;
|
||||||
if (textHandler != null)
|
if (textHandler != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedText(response);
|
||||||
this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response));
|
|
||||||
|
|
||||||
textHandler(this, new GenericCommMethodReceiveTextArgs(response));
|
textHandler(this, new GenericCommMethodReceiveTextArgs(response));
|
||||||
}
|
}
|
||||||
@@ -439,7 +456,7 @@ namespace PepperDash.Core
|
|||||||
/// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange
|
/// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange
|
||||||
/// event
|
/// event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Client_ErrorOccurred(object sender, ExceptionEventArgs e)
|
private void Client_ErrorOccurred(object sender, ExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
CrestronInvoke.BeginInvoke(o =>
|
CrestronInvoke.BeginInvoke(o =>
|
||||||
{
|
{
|
||||||
@@ -459,7 +476,7 @@ namespace PepperDash.Core
|
|||||||
if (AutoReconnect && ConnectEnabled)
|
if (AutoReconnect && ConnectEnabled)
|
||||||
{
|
{
|
||||||
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
StartReconnectTimer();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -467,7 +484,7 @@ namespace PepperDash.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper for ConnectionChange event
|
/// Helper for ConnectionChange event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void OnConnectionChange()
|
private void OnConnectionChange()
|
||||||
{
|
{
|
||||||
ConnectionChange?.Invoke(this, new GenericSocketStatusChageEventArgs(this));
|
ConnectionChange?.Invoke(this, new GenericSocketStatusChageEventArgs(this));
|
||||||
}
|
}
|
||||||
@@ -482,16 +499,12 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Client != null && TheStream != null && IsConnected)
|
if (client != null && shellStream != null && IsConnected)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentText(text);
|
||||||
this.LogInformation(
|
|
||||||
"Sending {length} characters of text: '{text}'",
|
|
||||||
text.Length,
|
|
||||||
ComTextHelper.GetDebugText(text));
|
|
||||||
|
|
||||||
TheStream.Write(text);
|
shellStream.Write(text);
|
||||||
TheStream.Flush();
|
shellStream.Flush();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -503,7 +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);
|
||||||
ReconnectTimer.Reset();
|
StartReconnectTimer();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -519,13 +532,12 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Client != null && TheStream != null && IsConnected)
|
if (client != null && shellStream != null && IsConnected)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentBytes(bytes);
|
||||||
this.LogInformation("Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
|
|
||||||
|
|
||||||
TheStream.Write(bytes, 0, bytes.Length);
|
shellStream.Write(bytes, 0, bytes.Length);
|
||||||
TheStream.Flush();
|
shellStream.Flush();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -537,7 +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);
|
||||||
ReconnectTimer.Reset();
|
StartReconnectTimer();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -546,6 +558,83 @@ namespace PepperDash.Core
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Safely starts the reconnect timer with exception handling
|
||||||
|
/// </summary>
|
||||||
|
private void StartReconnectTimer()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
reconnectTimer?.Change(AutoReconnectIntervalMs, System.Threading.Timeout.Infinite);
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// Timer was disposed, ignore
|
||||||
|
this.LogDebug("Attempted to start timer but it was already disposed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Safely stops the reconnect timer with exception handling
|
||||||
|
/// </summary>
|
||||||
|
private void StopReconnectTimer()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
reconnectTimer?.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// Timer was disposed, ignore
|
||||||
|
this.LogDebug("Attempted to stop timer but it was already disposed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deactivate method - properly dispose of resources
|
||||||
|
/// </summary>
|
||||||
|
public override bool Deactivate()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.LogDebug("Deactivating SSH client - disposing resources");
|
||||||
|
|
||||||
|
// Stop trying reconnects
|
||||||
|
ConnectEnabled = false;
|
||||||
|
StopReconnectTimer();
|
||||||
|
|
||||||
|
// Disconnect and cleanup client
|
||||||
|
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
||||||
|
|
||||||
|
// Dispose timer
|
||||||
|
try
|
||||||
|
{
|
||||||
|
reconnectTimer?.Dispose();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// Already disposed, ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dispose semaphore
|
||||||
|
try
|
||||||
|
{
|
||||||
|
connectLock?.Dispose();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
// Already disposed, ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.Deactivate();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.LogException(ex, "Error during SSH client deactivation");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//*****************************************************************************************************
|
//*****************************************************************************************************
|
||||||
|
|||||||
@@ -19,44 +19,44 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public CommunicationStreamDebugging StreamDebugging { get; private set; }
|
public CommunicationStreamDebugging StreamDebugging { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fires when data is received from the server and returns it as a Byte array
|
/// Fires when data is received from the server and returns it as a Byte array
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fires when data is received from the server and returns it as text
|
/// Fires when data is received from the server and returns it as text
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
//public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
|
//public event GenericSocketStatusChangeEventDelegate SocketStatusChange;
|
||||||
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
|
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
|
||||||
|
|
||||||
|
|
||||||
private string _hostname;
|
private string _hostname;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Address of server
|
/// Address of server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Hostname
|
public string Hostname
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _hostname;
|
return _hostname;
|
||||||
}
|
}
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_hostname = value;
|
_hostname = value;
|
||||||
if (_client != null)
|
if (_client != null)
|
||||||
{
|
{
|
||||||
_client.AddressClientConnectedTo = _hostname;
|
_client.AddressClientConnectedTo = _hostname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Port
|
/// Gets or sets the Port
|
||||||
@@ -78,15 +78,15 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int BufferSize { get; set; }
|
public int BufferSize { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The actual client class
|
/// The actual client class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private TCPClient _client;
|
private TCPClient _client;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bool showing if socket is connected
|
/// Bool showing if socket is connected
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsConnected
|
public bool IsConnected
|
||||||
{
|
{
|
||||||
get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
|
get { return _client != null && _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
|
||||||
}
|
}
|
||||||
@@ -99,10 +99,10 @@ namespace PepperDash.Core
|
|||||||
get { return (ushort)(IsConnected ? 1 : 0); }
|
get { return (ushort)(IsConnected ? 1 : 0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// _client socket status Read only
|
/// _client socket status Read only
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SocketStatus ClientStatus
|
public SocketStatus ClientStatus
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -119,26 +119,26 @@ namespace PepperDash.Core
|
|||||||
get { return (ushort)ClientStatus; }
|
get { return (ushort)ClientStatus; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Status text shows the message associated with socket status
|
/// Status text shows the message associated with socket status
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ClientStatusText { get { return ClientStatus.ToString(); } }
|
public string ClientStatusText { get { return ClientStatus.ToString(); } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ushort representation of client status
|
/// Ushort representation of client status
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete]
|
[Obsolete]
|
||||||
public ushort UClientStatus { get { return (ushort)ClientStatus; } }
|
public ushort UClientStatus { get { return (ushort)ClientStatus; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connection failure reason
|
/// Connection failure reason
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string ConnectionFailure { get { return ClientStatus.ToString(); } }
|
public string ConnectionFailure { get { return ClientStatus.ToString(); } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the AutoReconnect
|
/// Gets or sets the AutoReconnect
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AutoReconnect { get; set; }
|
public bool AutoReconnect { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// S+ helper for AutoReconnect
|
/// S+ helper for AutoReconnect
|
||||||
@@ -149,29 +149,29 @@ namespace PepperDash.Core
|
|||||||
set { AutoReconnect = value == 1; }
|
set { AutoReconnect = value == 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Milliseconds to wait before attempting to reconnect. Defaults to 5000
|
/// Milliseconds to wait before attempting to reconnect. Defaults to 5000
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int AutoReconnectIntervalMs { get; set; }
|
public int AutoReconnectIntervalMs { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set only when the disconnect method is called
|
/// Set only when the disconnect method is called
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool DisconnectCalledByUser;
|
bool DisconnectCalledByUser;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Connected
|
public bool Connected
|
||||||
{
|
{
|
||||||
get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
|
get { return _client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
|
||||||
}
|
}
|
||||||
|
|
||||||
//Lock object to prevent simulatneous connect/disconnect operations
|
//Lock object to prevent simulatneous connect/disconnect operations
|
||||||
private CCriticalSection connectLock = new CCriticalSection();
|
private CCriticalSection connectLock = new CCriticalSection();
|
||||||
|
|
||||||
// private Timer for auto reconnect
|
// private Timer for auto reconnect
|
||||||
private CTimer RetryTimer;
|
private CTimer RetryTimer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor
|
/// Constructor
|
||||||
@@ -181,8 +181,8 @@ namespace PepperDash.Core
|
|||||||
/// <param name="port"></param>
|
/// <param name="port"></param>
|
||||||
/// <param name="bufferSize"></param>
|
/// <param name="bufferSize"></param>
|
||||||
public GenericTcpIpClient(string key, string address, int port, int bufferSize)
|
public GenericTcpIpClient(string key, string address, int port, int bufferSize)
|
||||||
: base(key)
|
: base(key)
|
||||||
{
|
{
|
||||||
StreamDebugging = new CommunicationStreamDebugging(key);
|
StreamDebugging = new CommunicationStreamDebugging(key);
|
||||||
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
||||||
AutoReconnectIntervalMs = 5000;
|
AutoReconnectIntervalMs = 5000;
|
||||||
@@ -218,18 +218,18 @@ namespace PepperDash.Core
|
|||||||
/// Default constructor for S+
|
/// Default constructor for S+
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GenericTcpIpClient()
|
public GenericTcpIpClient()
|
||||||
: base(SplusKey)
|
: base(SplusKey)
|
||||||
{
|
{
|
||||||
StreamDebugging = new CommunicationStreamDebugging(SplusKey);
|
StreamDebugging = new CommunicationStreamDebugging(SplusKey);
|
||||||
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
|
||||||
AutoReconnectIntervalMs = 5000;
|
AutoReconnectIntervalMs = 5000;
|
||||||
BufferSize = 2000;
|
BufferSize = 2000;
|
||||||
|
|
||||||
RetryTimer = new CTimer(o =>
|
RetryTimer = new CTimer(o =>
|
||||||
{
|
{
|
||||||
Reconnect();
|
Reconnect();
|
||||||
}, Timeout.Infinite);
|
}, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize method
|
/// Initialize method
|
||||||
@@ -255,26 +255,26 @@ namespace PepperDash.Core
|
|||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deactivate method
|
/// Deactivate method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override bool Deactivate()
|
public override bool Deactivate()
|
||||||
{
|
{
|
||||||
RetryTimer.Stop();
|
RetryTimer.Stop();
|
||||||
RetryTimer.Dispose();
|
RetryTimer.Dispose();
|
||||||
if (_client != null)
|
if (_client != null)
|
||||||
{
|
{
|
||||||
_client.SocketStatusChange -= this.Client_SocketStatusChange;
|
_client.SocketStatusChange -= this.Client_SocketStatusChange;
|
||||||
DisconnectClient();
|
DisconnectClient();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connect method
|
/// Connect method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Connect()
|
public void Connect()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(Hostname))
|
if (string.IsNullOrEmpty(Hostname))
|
||||||
{
|
{
|
||||||
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': No address set", Key);
|
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericTcpIpClient '{0}': No address set", Key);
|
||||||
@@ -310,7 +310,7 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
connectLock.Leave();
|
connectLock.Leave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Reconnect()
|
private void Reconnect()
|
||||||
{
|
{
|
||||||
@@ -337,11 +337,11 @@ namespace PepperDash.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnect method
|
/// Disconnect method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
connectLock.Enter();
|
connectLock.Enter();
|
||||||
@@ -355,7 +355,7 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
connectLock.Leave();
|
connectLock.Leave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DisconnectClient method
|
/// DisconnectClient method
|
||||||
@@ -375,7 +375,7 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="c"></param>
|
/// <param name="c"></param>
|
||||||
void ConnectToServerCallback(TCPClient c)
|
void ConnectToServerCallback(TCPClient c)
|
||||||
{
|
{
|
||||||
if (c.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED)
|
if (c.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, "Server connection result: {0}", c.ClientStatus);
|
Debug.Console(0, this, "Server connection result: {0}", c.ClientStatus);
|
||||||
@@ -385,13 +385,13 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
Debug.Console(1, this, "Server connection result: {0}", c.ClientStatus);
|
Debug.Console(1, this, "Server connection result: {0}", c.ClientStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnects, waits and attemtps to connect again
|
/// Disconnects, waits and attemtps to connect again
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void WaitAndTryReconnect()
|
void WaitAndTryReconnect()
|
||||||
{
|
{
|
||||||
CrestronInvoke.BeginInvoke(o =>
|
CrestronInvoke.BeginInvoke(o =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -409,7 +409,7 @@ namespace PepperDash.Core
|
|||||||
connectLock.Leave();
|
connectLock.Leave();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Recieves incoming data
|
/// Recieves incoming data
|
||||||
@@ -417,7 +417,7 @@ namespace PepperDash.Core
|
|||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
/// <param name="numBytes"></param>
|
/// <param name="numBytes"></param>
|
||||||
void Receive(TCPClient client, int numBytes)
|
void Receive(TCPClient client, int numBytes)
|
||||||
{
|
{
|
||||||
if (client != null)
|
if (client != null)
|
||||||
{
|
{
|
||||||
if (numBytes > 0)
|
if (numBytes > 0)
|
||||||
@@ -426,10 +426,7 @@ namespace PepperDash.Core
|
|||||||
var bytesHandler = BytesReceived;
|
var bytesHandler = BytesReceived;
|
||||||
if (bytesHandler != null)
|
if (bytesHandler != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedBytes(bytes);
|
||||||
{
|
|
||||||
Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
|
|
||||||
}
|
|
||||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||||
}
|
}
|
||||||
var textHandler = TextReceived;
|
var textHandler = TextReceived;
|
||||||
@@ -437,58 +434,53 @@ namespace PepperDash.Core
|
|||||||
{
|
{
|
||||||
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
|
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
|
||||||
|
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedText(str);
|
||||||
{
|
|
||||||
Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
|
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.ReceiveDataAsync(Receive);
|
client.ReceiveDataAsync(Receive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SendText method
|
/// SendText method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendText(string text)
|
public void SendText(string text)
|
||||||
{
|
{
|
||||||
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
|
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
|
||||||
// Check debug level before processing byte array
|
// Check debug level before processing byte array
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentText(text);
|
||||||
Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text));
|
|
||||||
if (_client != null)
|
if (_client != null)
|
||||||
_client.SendData(bytes, bytes.Length);
|
_client.SendData(bytes, bytes.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SendEscapedText method
|
/// SendEscapedText method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendEscapedText(string text)
|
public void SendEscapedText(string text)
|
||||||
{
|
{
|
||||||
var unescapedText = Regex.Replace(text, @"\\x([0-9a-fA-F][0-9a-fA-F])", s =>
|
var unescapedText = Regex.Replace(text, @"\\x([0-9a-fA-F][0-9a-fA-F])", s =>
|
||||||
{
|
{
|
||||||
var hex = s.Groups[1].Value;
|
var hex = s.Groups[1].Value;
|
||||||
return ((char)Convert.ToByte(hex, 16)).ToString();
|
return ((char)Convert.ToByte(hex, 16)).ToString();
|
||||||
});
|
});
|
||||||
SendText(unescapedText);
|
SendText(unescapedText);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends Bytes to the server
|
/// Sends Bytes to the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes"></param>
|
/// <param name="bytes"></param>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SendBytes method
|
/// SendBytes method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendBytes(byte[] bytes)
|
public void SendBytes(byte[] bytes)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentBytes(bytes);
|
||||||
Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
|
|
||||||
if (_client != null)
|
if (_client != null)
|
||||||
_client.SendData(bytes, bytes.Length);
|
_client.SendData(bytes, bytes.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Socket Status Change Handler
|
/// Socket Status Change Handler
|
||||||
@@ -496,7 +488,7 @@ namespace PepperDash.Core
|
|||||||
/// <param name="client"></param>
|
/// <param name="client"></param>
|
||||||
/// <param name="clientSocketStatus"></param>
|
/// <param name="clientSocketStatus"></param>
|
||||||
void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus)
|
void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus)
|
||||||
{
|
{
|
||||||
if (clientSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED)
|
if (clientSocketStatus != SocketStatus.SOCKET_STATUS_CONNECTED)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText);
|
Debug.Console(0, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText);
|
||||||
@@ -505,68 +497,73 @@ namespace PepperDash.Core
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText);
|
Debug.Console(1, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText);
|
||||||
_client.ReceiveDataAsync(Receive);
|
_client.ReceiveDataAsync(Receive);
|
||||||
}
|
}
|
||||||
|
|
||||||
var handler = ConnectionChange;
|
var handler = ConnectionChange;
|
||||||
if (handler != null)
|
if (handler != null)
|
||||||
ConnectionChange(this, new GenericSocketStatusChageEventArgs(this));
|
ConnectionChange(this, new GenericSocketStatusChageEventArgs(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a TcpSshPropertiesConfig
|
/// Represents a TcpSshPropertiesConfig
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TcpSshPropertiesConfig
|
public class TcpSshPropertiesConfig
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Address to connect to
|
/// Address to connect to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty(Required = Required.Always)]
|
[JsonProperty(Required = Required.Always)]
|
||||||
public string Address { get; set; }
|
public string Address { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Port to connect to
|
/// Port to connect to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty(Required = Required.Always)]
|
[JsonProperty(Required = Required.Always)]
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Username credential
|
/// Username credential
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Password
|
/// Gets or sets the Password
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defaults to 32768
|
/// Defaults to 32768
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int BufferSize { get; set; }
|
public int BufferSize { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the AutoReconnect
|
/// Gets or sets the AutoReconnect
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AutoReconnect { get; set; }
|
public bool AutoReconnect { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the AutoReconnectIntervalMs
|
/// Gets or sets the AutoReconnectIntervalMs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int AutoReconnectIntervalMs { get; set; }
|
public int AutoReconnectIntervalMs { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When true, turns off echo for the SSH session
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("disableSshEcho")]
|
||||||
|
public bool DisableSshEcho { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TcpSshPropertiesConfig()
|
public TcpSshPropertiesConfig()
|
||||||
{
|
{
|
||||||
BufferSize = 32768;
|
BufferSize = 32768;
|
||||||
AutoReconnect = true;
|
AutoReconnect = true;
|
||||||
AutoReconnectIntervalMs = 5000;
|
AutoReconnectIntervalMs = 5000;
|
||||||
Username = "";
|
Username = "";
|
||||||
Password = "";
|
Password = "";
|
||||||
}
|
DisableSshEcho = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
{
|
{
|
||||||
if(Server != null)
|
if (Server != null)
|
||||||
Server.DisableUDPServer();
|
Server.DisableUDPServer();
|
||||||
|
|
||||||
IsConnected = false;
|
IsConnected = false;
|
||||||
@@ -281,17 +281,13 @@ namespace PepperDash.Core
|
|||||||
var bytesHandler = BytesReceived;
|
var bytesHandler = BytesReceived;
|
||||||
if (bytesHandler != null)
|
if (bytesHandler != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedBytes(bytes);
|
||||||
{
|
|
||||||
Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
|
|
||||||
}
|
|
||||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||||
}
|
}
|
||||||
var textHandler = TextReceived;
|
var textHandler = TextReceived;
|
||||||
if (textHandler != null)
|
if (textHandler != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedText(str);
|
||||||
Debug.Console(0, this, "Received {1} characters of text: '{0}'", ComTextHelper.GetDebugText(str), str.Length);
|
|
||||||
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
|
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,8 +314,7 @@ namespace PepperDash.Core
|
|||||||
|
|
||||||
if (IsConnected && Server != null)
|
if (IsConnected && Server != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentText(text);
|
||||||
Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text));
|
|
||||||
|
|
||||||
Server.SendData(bytes, bytes.Length);
|
Server.SendData(bytes, bytes.Length);
|
||||||
}
|
}
|
||||||
@@ -334,8 +329,7 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendBytes(byte[] bytes)
|
public void SendBytes(byte[] bytes)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentBytes(bytes);
|
||||||
Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
|
|
||||||
|
|
||||||
if (IsConnected && Server != null)
|
if (IsConnected && Server != null)
|
||||||
Server.SendData(bytes, bytes.Length);
|
Server.SendData(bytes, bytes.Length);
|
||||||
@@ -343,11 +337,11 @@ namespace PepperDash.Core
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a GenericUdpReceiveTextExtraArgs
|
/// Represents a GenericUdpReceiveTextExtraArgs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericUdpReceiveTextExtraArgs : EventArgs
|
public class GenericUdpReceiveTextExtraArgs : EventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -359,7 +353,7 @@ namespace PepperDash.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Port { get; private set; }
|
public int Port { get; private set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -373,18 +367,18 @@ namespace PepperDash.Core
|
|||||||
/// <param name="port"></param>
|
/// <param name="port"></param>
|
||||||
/// <param name="bytes"></param>
|
/// <param name="bytes"></param>
|
||||||
public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes)
|
public GenericUdpReceiveTextExtraArgs(string text, string ipAddress, int port, byte[] bytes)
|
||||||
{
|
{
|
||||||
Text = text;
|
Text = text;
|
||||||
IpAddress = ipAddress;
|
IpAddress = ipAddress;
|
||||||
Port = port;
|
Port = port;
|
||||||
Bytes = bytes;
|
Bytes = bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stupid S+ Constructor
|
/// Stupid S+ Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GenericUdpReceiveTextExtraArgs() { }
|
public GenericUdpReceiveTextExtraArgs() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|||||||
69
src/PepperDash.Core/Comm/StreamDebuggingExtensions.cs
Normal file
69
src/PepperDash.Core/Comm/StreamDebuggingExtensions.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using Crestron.SimplSharp;
|
||||||
|
|
||||||
|
namespace PepperDash.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for stream debugging
|
||||||
|
/// </summary>
|
||||||
|
public static class StreamDebuggingExtensions
|
||||||
|
{
|
||||||
|
private static readonly string app = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? $"App {InitialParametersClass.ApplicationNumber}" : $"{InitialParametersClass.RoomId}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Print the sent bytes to the console
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="comms">comms device</param>
|
||||||
|
/// <param name="bytes">bytes to print</param>
|
||||||
|
public static void PrintSentBytes(this IStreamDebugging comms, byte[] bytes)
|
||||||
|
{
|
||||||
|
if (!comms.StreamDebugging.TxStreamDebuggingIsEnabled) return;
|
||||||
|
|
||||||
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||||
|
|
||||||
|
CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Sending {bytes.Length} bytes: '{ComTextHelper.GetEscapedText(bytes)}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Print the received bytes to the console
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="comms">comms device</param>
|
||||||
|
/// <param name="bytes">bytes to print</param>
|
||||||
|
public static void PrintReceivedBytes(this IStreamDebugging comms, byte[] bytes)
|
||||||
|
{
|
||||||
|
if (!comms.StreamDebugging.RxStreamDebuggingIsEnabled) return;
|
||||||
|
|
||||||
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||||
|
|
||||||
|
CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Received {bytes.Length} bytes: '{ComTextHelper.GetEscapedText(bytes)}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Print the sent text to the console
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="comms">comms device</param>
|
||||||
|
/// <param name="text">text to print</param>
|
||||||
|
public static void PrintSentText(this IStreamDebugging comms, string text)
|
||||||
|
{
|
||||||
|
if (!comms.StreamDebugging.TxStreamDebuggingIsEnabled) return;
|
||||||
|
|
||||||
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||||
|
|
||||||
|
CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Sending Text: '{ComTextHelper.GetDebugText(text)}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Print the received text to the console
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="comms">comms device</param>
|
||||||
|
/// <param name="text">text to print</param>
|
||||||
|
public static void PrintReceivedText(this IStreamDebugging comms, string text)
|
||||||
|
{
|
||||||
|
if (!comms.StreamDebugging.RxStreamDebuggingIsEnabled) return;
|
||||||
|
|
||||||
|
var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||||
|
|
||||||
|
CrestronConsole.PrintLine($"[{timestamp}][{app}][{comms.Key}] Received Text: '{ComTextHelper.GetDebugText(text)}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,6 +78,10 @@ namespace PepperDash.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used when comms needs to be handled in SIMPL and bridged opposite the normal direction
|
/// Used when comms needs to be handled in SIMPL and bridged opposite the normal direction
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ComBridge
|
ComBridge,
|
||||||
|
/// <summary>
|
||||||
|
/// InfinetEX control
|
||||||
|
/// </summary>
|
||||||
|
InfinetEx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
24
src/PepperDash.Core/Comm/eStreamDebuggingDataTypeSettings.cs
Normal file
24
src/PepperDash.Core/Comm/eStreamDebuggingDataTypeSettings.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PepperDash.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The available settings for stream debugging data format types
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum eStreamDebuggingDataTypeSettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Debug data in byte format
|
||||||
|
/// </summary>
|
||||||
|
Bytes = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Debug data in text format
|
||||||
|
/// </summary>
|
||||||
|
Text = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// Debug data in both byte and text formats
|
||||||
|
/// </summary>
|
||||||
|
Both = Bytes | Text
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs
Normal file
28
src/PepperDash.Core/Comm/eStreamDebuggingSetting.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PepperDash.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The available settings for stream debugging
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum eStreamDebuggingSetting
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Debug off
|
||||||
|
/// </summary>
|
||||||
|
Off = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// Debug received data
|
||||||
|
/// </summary>
|
||||||
|
Rx = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// Debug transmitted data
|
||||||
|
/// </summary>
|
||||||
|
Tx = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// Debug both received and transmitted data
|
||||||
|
/// </summary>
|
||||||
|
Both = Rx | Tx
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronSockets;
|
using Crestron.SimplSharp.CrestronSockets;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
@@ -42,7 +39,7 @@ namespace PepperDash.Core
|
|||||||
/// Defines the contract for IBasicCommunication
|
/// Defines the contract for IBasicCommunication
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IBasicCommunication : ICommunicationReceiver
|
public interface IBasicCommunication : ICommunicationReceiver
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send text to the device
|
/// Send text to the device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -54,7 +51,7 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes"></param>
|
/// <param name="bytes"></param>
|
||||||
void SendBytes(byte[] bytes);
|
void SendBytes(byte[] bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a device that implements IBasicCommunication and IStreamDebugging
|
/// Represents a device that implements IBasicCommunication and IStreamDebugging
|
||||||
@@ -67,7 +64,7 @@ namespace PepperDash.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a device with stream debugging capablities
|
/// Represents a device with stream debugging capablities
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IStreamDebugging
|
public interface IStreamDebugging : IKeyed
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Object to enable stream debugging
|
/// Object to enable stream debugging
|
||||||
@@ -76,12 +73,12 @@ namespace PepperDash.Core
|
|||||||
CommunicationStreamDebugging StreamDebugging { get; }
|
CommunicationStreamDebugging StreamDebugging { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
|
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
|
||||||
/// GenericTcpIpClient
|
/// GenericTcpIpClient
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISocketStatus : IBasicCommunication
|
public interface ISocketStatus : IBasicCommunication
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Notifies of socket status changes
|
/// Notifies of socket status changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -93,7 +90,7 @@ namespace PepperDash.Core
|
|||||||
[JsonProperty("clientStatus")]
|
[JsonProperty("clientStatus")]
|
||||||
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||||
SocketStatus ClientStatus { get; }
|
SocketStatus ClientStatus { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes a device that implements ISocketStatus and IStreamDebugging
|
/// Describes a device that implements ISocketStatus and IStreamDebugging
|
||||||
@@ -107,24 +104,24 @@ namespace PepperDash.Core
|
|||||||
/// Describes a device that can automatically attempt to reconnect
|
/// Describes a device that can automatically attempt to reconnect
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IAutoReconnect
|
public interface IAutoReconnect
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enable automatic recconnect
|
/// Enable automatic recconnect
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("autoReconnect")]
|
[JsonProperty("autoReconnect")]
|
||||||
bool AutoReconnect { get; set; }
|
bool AutoReconnect { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interval in ms to attempt automatic recconnections
|
/// Interval in ms to attempt automatic recconnections
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("autoReconnectIntervalMs")]
|
[JsonProperty("autoReconnectIntervalMs")]
|
||||||
int AutoReconnectIntervalMs { get; set; }
|
int AutoReconnectIntervalMs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum eGenericCommMethodStatusChangeType
|
public enum eGenericCommMethodStatusChangeType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connected
|
/// Connected
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -133,45 +130,45 @@ namespace PepperDash.Core
|
|||||||
/// Disconnected
|
/// Disconnected
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Disconnected
|
Disconnected
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This delegate defines handler for IBasicCommunication status changes
|
/// This delegate defines handler for IBasicCommunication status changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="comm">Device firing the status change</param>
|
/// <param name="comm">Device firing the status change</param>
|
||||||
/// <param name="status"></param>
|
/// <param name="status"></param>
|
||||||
public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status);
|
public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericCommMethodReceiveBytesArgs : EventArgs
|
public class GenericCommMethodReceiveBytesArgs : EventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Bytes
|
/// Gets or sets the Bytes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte[] Bytes { get; private set; }
|
public byte[] Bytes { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes"></param>
|
/// <param name="bytes"></param>
|
||||||
public GenericCommMethodReceiveBytesArgs(byte[] bytes)
|
public GenericCommMethodReceiveBytesArgs(byte[] bytes)
|
||||||
{
|
{
|
||||||
Bytes = bytes;
|
Bytes = bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// S+ Constructor
|
/// S+ Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GenericCommMethodReceiveBytesArgs() { }
|
public GenericCommMethodReceiveBytesArgs() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericCommMethodReceiveTextArgs : EventArgs
|
public class GenericCommMethodReceiveTextArgs : EventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -185,9 +182,9 @@ namespace PepperDash.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text"></param>
|
/// <param name="text"></param>
|
||||||
public GenericCommMethodReceiveTextArgs(string text)
|
public GenericCommMethodReceiveTextArgs(string text)
|
||||||
{
|
{
|
||||||
Text = text;
|
Text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -195,59 +192,14 @@ namespace PepperDash.Core
|
|||||||
/// <param name="text"></param>
|
/// <param name="text"></param>
|
||||||
/// <param name="delimiter"></param>
|
/// <param name="delimiter"></param>
|
||||||
public GenericCommMethodReceiveTextArgs(string text, string delimiter)
|
public GenericCommMethodReceiveTextArgs(string text, string delimiter)
|
||||||
:this(text)
|
: this(text)
|
||||||
{
|
{
|
||||||
Delimiter = delimiter;
|
Delimiter = delimiter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// S+ Constructor
|
|
||||||
/// </summary>
|
|
||||||
public GenericCommMethodReceiveTextArgs() { }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public class ComTextHelper
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets escaped text for a byte array
|
/// S+ Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes"></param>
|
public GenericCommMethodReceiveTextArgs() { }
|
||||||
/// <returns></returns>
|
}
|
||||||
public static string GetEscapedText(byte[] bytes)
|
|
||||||
{
|
|
||||||
return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets escaped text for a string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <summary>
|
|
||||||
/// GetEscapedText method
|
|
||||||
/// </summary>
|
|
||||||
public static string GetEscapedText(string text)
|
|
||||||
{
|
|
||||||
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
|
|
||||||
return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets debug text for a string
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <summary>
|
|
||||||
/// GetDebugText method
|
|
||||||
/// </summary>
|
|
||||||
public static string GetDebugText(string text)
|
|
||||||
{
|
|
||||||
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -9,40 +9,59 @@ using Serilog.Events;
|
|||||||
|
|
||||||
namespace PepperDash.Core.Config
|
namespace PepperDash.Core.Config
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a Portal formatted config file
|
/// Reads a Portal formatted config file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PortalConfigReader
|
public class PortalConfigReader
|
||||||
{
|
{
|
||||||
/// <summary>
|
const string template = "template";
|
||||||
/// Reads the config file, checks if it needs a merge, merges and saves, then returns the merged Object.
|
const string system = "system";
|
||||||
/// </summary>
|
const string systemUrl = "system_url";
|
||||||
/// <returns>JObject of config file</returns>
|
const string templateUrl = "template_url";
|
||||||
public static void ReadAndMergeFileIfNecessary(string filePath, string savePath)
|
const string info = "info";
|
||||||
|
const string devices = "devices";
|
||||||
|
const string rooms = "rooms";
|
||||||
|
const string sourceLists = "sourceLists";
|
||||||
|
const string destinationLists = "destinationLists";
|
||||||
|
const string cameraLists = "cameraLists";
|
||||||
|
const string audioControlPointLists = "audioControlPointLists";
|
||||||
|
|
||||||
|
const string tieLines = "tieLines";
|
||||||
|
const string joinMaps = "joinMaps";
|
||||||
|
const string global = "global";
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the config file, checks if it needs a merge, merges and saves, then returns the merged Object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>JObject of config file</returns>
|
||||||
|
public static void ReadAndMergeFileIfNecessary(string filePath, string savePath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!File.Exists(filePath))
|
if (!File.Exists(filePath))
|
||||||
{
|
{
|
||||||
Debug.Console(1, Debug.ErrorLogLevel.Error,
|
Debug.LogError(
|
||||||
"ERROR: Configuration file not present. Please load file to {0} and reset program", filePath);
|
"ERROR: Configuration file not present. Please load file to {0} and reset program", filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (StreamReader fs = new StreamReader(filePath))
|
using (StreamReader fs = new StreamReader(filePath))
|
||||||
{
|
{
|
||||||
var jsonObj = JObject.Parse(fs.ReadToEnd());
|
var jsonObj = JObject.Parse(fs.ReadToEnd());
|
||||||
if(jsonObj["template"] != null && jsonObj["system"] != null)
|
if(jsonObj[template] != null && jsonObj[system] != null)
|
||||||
{
|
{
|
||||||
// it's a double-config, merge it.
|
// it's a double-config, merge it.
|
||||||
var merged = MergeConfigs(jsonObj);
|
var merged = MergeConfigs(jsonObj);
|
||||||
if (jsonObj["system_url"] != null)
|
if (jsonObj[systemUrl] != null)
|
||||||
{
|
{
|
||||||
merged["systemUrl"] = jsonObj["system_url"].Value<string>();
|
merged[systemUrl] = jsonObj[systemUrl].Value<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jsonObj["template_url"] != null)
|
if (jsonObj[templateUrl] != null)
|
||||||
{
|
{
|
||||||
merged["templateUrl"] = jsonObj["template_url"].Value<string>();
|
merged[templateUrl] = jsonObj[templateUrl].Value<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonObj = merged;
|
jsonObj = merged;
|
||||||
@@ -77,62 +96,62 @@ namespace PepperDash.Core.Config
|
|||||||
var merged = new JObject();
|
var merged = new JObject();
|
||||||
|
|
||||||
// Put together top-level objects
|
// Put together top-level objects
|
||||||
if (system["info"] != null)
|
if (system[info] != null)
|
||||||
merged.Add("info", Merge(template["info"], system["info"], "infO"));
|
merged.Add(info, Merge(template[info], system[info], info));
|
||||||
else
|
else
|
||||||
merged.Add("info", template["info"]);
|
merged.Add(info, template[info]);
|
||||||
|
|
||||||
merged.Add("devices", MergeArraysOnTopLevelProperty(template["devices"] as JArray,
|
merged.Add(devices, MergeArraysOnTopLevelProperty(template[devices] as JArray,
|
||||||
system["devices"] as JArray, "key", "devices"));
|
system[devices] as JArray, "key", devices));
|
||||||
|
|
||||||
if (system["rooms"] == null)
|
if (system[rooms] == null)
|
||||||
merged.Add("rooms", template["rooms"]);
|
merged.Add(rooms, template[rooms]);
|
||||||
else
|
else
|
||||||
merged.Add("rooms", MergeArraysOnTopLevelProperty(template["rooms"] as JArray,
|
merged.Add(rooms, MergeArraysOnTopLevelProperty(template[rooms] as JArray,
|
||||||
system["rooms"] as JArray, "key", "rooms"));
|
system[rooms] as JArray, "key", rooms));
|
||||||
|
|
||||||
if (system["sourceLists"] == null)
|
if (system[sourceLists] == null)
|
||||||
merged.Add("sourceLists", template["sourceLists"]);
|
merged.Add(sourceLists, template[sourceLists]);
|
||||||
else
|
else
|
||||||
merged.Add("sourceLists", Merge(template["sourceLists"], system["sourceLists"], "sourceLists"));
|
merged.Add(sourceLists, Merge(template[sourceLists], system[sourceLists], sourceLists));
|
||||||
|
|
||||||
if (system["destinationLists"] == null)
|
if (system[destinationLists] == null)
|
||||||
merged.Add("destinationLists", template["destinationLists"]);
|
merged.Add(destinationLists, template[destinationLists]);
|
||||||
else
|
else
|
||||||
merged.Add("destinationLists",
|
merged.Add(destinationLists,
|
||||||
Merge(template["destinationLists"], system["destinationLists"], "destinationLists"));
|
Merge(template[destinationLists], system[destinationLists], destinationLists));
|
||||||
|
|
||||||
|
|
||||||
if (system["cameraLists"] == null)
|
if (system[cameraLists] == null)
|
||||||
merged.Add("cameraLists", template["cameraLists"]);
|
merged.Add(cameraLists, template[cameraLists]);
|
||||||
else
|
else
|
||||||
merged.Add("cameraLists", Merge(template["cameraLists"], system["cameraLists"], "cameraLists"));
|
merged.Add(cameraLists, Merge(template[cameraLists], system[cameraLists], cameraLists));
|
||||||
|
|
||||||
if (system["audioControlPointLists"] == null)
|
if (system[audioControlPointLists] == null)
|
||||||
merged.Add("audioControlPointLists", template["audioControlPointLists"]);
|
merged.Add(audioControlPointLists, template[audioControlPointLists]);
|
||||||
else
|
else
|
||||||
merged.Add("audioControlPointLists",
|
merged.Add(audioControlPointLists,
|
||||||
Merge(template["audioControlPointLists"], system["audioControlPointLists"], "audioControlPointLists"));
|
Merge(template[audioControlPointLists], system[audioControlPointLists], audioControlPointLists));
|
||||||
|
|
||||||
|
|
||||||
// Template tie lines take precedence. Config tool doesn't do them at system
|
// Template tie lines take precedence. Config tool doesn't do them at system
|
||||||
// level anyway...
|
// level anyway...
|
||||||
if (template["tieLines"] != null)
|
if (template[tieLines] != null)
|
||||||
merged.Add("tieLines", template["tieLines"]);
|
merged.Add(tieLines, template[tieLines]);
|
||||||
else if (system["tieLines"] != null)
|
else if (system[tieLines] != null)
|
||||||
merged.Add("tieLines", system["tieLines"]);
|
merged.Add(tieLines, system[tieLines]);
|
||||||
else
|
else
|
||||||
merged.Add("tieLines", new JArray());
|
merged.Add(tieLines, new JArray());
|
||||||
|
|
||||||
if (template["joinMaps"] != null)
|
if (template[joinMaps] != null)
|
||||||
merged.Add("joinMaps", template["joinMaps"]);
|
merged.Add(joinMaps, template[joinMaps]);
|
||||||
else
|
else
|
||||||
merged.Add("joinMaps", new JObject());
|
merged.Add(joinMaps, new JObject());
|
||||||
|
|
||||||
if (system["global"] != null)
|
if (system[global] != null)
|
||||||
merged.Add("global", Merge(template["global"], system["global"], "global"));
|
merged.Add(global, Merge(template[global], system[global], global));
|
||||||
else
|
else
|
||||||
merged.Add("global", template["global"]);
|
merged.Add(global, template[global]);
|
||||||
|
|
||||||
//Debug.Console(2, "MERGED CONFIG RESULT: \x0d\x0a{0}", merged);
|
//Debug.Console(2, "MERGED CONFIG RESULT: \x0d\x0a{0}", merged);
|
||||||
return merged;
|
return merged;
|
||||||
@@ -228,7 +247,7 @@ namespace PepperDash.Core.Config
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.Console(1, Debug.ErrorLogLevel.Warning, "Cannot merge items at path {0}: \r{1}", propPath, e);
|
Debug.LogError($"Cannot merge items at path {propPath}: \r{e}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ namespace PepperDash.Core
|
|||||||
.WriteTo.File(new RenderedCompactJsonFormatter(), logFilePath,
|
.WriteTo.File(new RenderedCompactJsonFormatter(), logFilePath,
|
||||||
rollingInterval: RollingInterval.Day,
|
rollingInterval: RollingInterval.Day,
|
||||||
restrictedToMinimumLevel: LogEventLevel.Debug,
|
restrictedToMinimumLevel: LogEventLevel.Debug,
|
||||||
retainedFileCountLimit: CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? 30 : 60,
|
retainedFileCountLimit: CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? 7 : 14,
|
||||||
levelSwitch: _fileLogLevelSwitch
|
levelSwitch: _fileLogLevelSwitch
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1081,9 +1081,6 @@ namespace PepperDash.Core
|
|||||||
/// Logs to Console when at-level, and all messages to error log
|
/// Logs to Console when at-level, and all messages to error log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")]
|
[Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")]
|
||||||
/// <summary>
|
|
||||||
/// Console method
|
|
||||||
/// </summary>
|
|
||||||
public static void Console(uint level, ErrorLogLevel errorLogLevel,
|
public static void Console(uint level, ErrorLogLevel errorLogLevel,
|
||||||
string format, params object[] items)
|
string format, params object[] items)
|
||||||
{
|
{
|
||||||
@@ -1096,9 +1093,6 @@ namespace PepperDash.Core
|
|||||||
/// it will only be written to the log.
|
/// it will only be written to the log.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")]
|
[Obsolete("Use LogMessage methods, Will be removed in 2.2.0 and later versions")]
|
||||||
/// <summary>
|
|
||||||
/// ConsoleWithLog method
|
|
||||||
/// </summary>
|
|
||||||
public static void ConsoleWithLog(uint level, string format, params object[] items)
|
public static void ConsoleWithLog(uint level, string format, params object[] items)
|
||||||
{
|
{
|
||||||
LogMessage(level, format, items);
|
LogMessage(level, format, items);
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ using Serilog.Events;
|
|||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a CecPortController
|
/// Represents a CecPortController
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CecPortController : Device, IBasicCommunicationWithStreamDebugging
|
public class CecPortController : Device, IBasicCommunicationWithStreamDebugging
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the StreamDebugging
|
/// Gets or sets the StreamDebugging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommunicationStreamDebugging StreamDebugging { get; private set; }
|
public CommunicationStreamDebugging StreamDebugging { get; private set; }
|
||||||
|
|
||||||
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
||||||
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
||||||
@@ -33,9 +33,9 @@ namespace PepperDash.Essentials.Core
|
|||||||
ICec Port;
|
ICec Port;
|
||||||
|
|
||||||
public CecPortController(string key, Func<EssentialsControlPropertiesConfig, ICec> postActivationFunc,
|
public CecPortController(string key, Func<EssentialsControlPropertiesConfig, ICec> postActivationFunc,
|
||||||
EssentialsControlPropertiesConfig config):base(key)
|
EssentialsControlPropertiesConfig config) : base(key)
|
||||||
{
|
{
|
||||||
StreamDebugging = new CommunicationStreamDebugging(key);
|
StreamDebugging = new CommunicationStreamDebugging(key);
|
||||||
|
|
||||||
AddPostActivationAction(() =>
|
AddPostActivationAction(() =>
|
||||||
{
|
{
|
||||||
@@ -58,27 +58,25 @@ namespace PepperDash.Essentials.Core
|
|||||||
if (args.EventId == CecEventIds.CecMessageReceivedEventId)
|
if (args.EventId == CecEventIds.CecMessageReceivedEventId)
|
||||||
OnDataReceived(cecDevice.Received.StringValue);
|
OnDataReceived(cecDevice.Received.StringValue);
|
||||||
else if (args.EventId == CecEventIds.ErrorFeedbackEventId)
|
else if (args.EventId == CecEventIds.ErrorFeedbackEventId)
|
||||||
if(cecDevice.ErrorFeedback.BoolValue)
|
if (cecDevice.ErrorFeedback.BoolValue)
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "CEC NAK Error");
|
Debug.LogMessage(LogEventLevel.Verbose, this, "CEC NAK Error");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDataReceived(string s)
|
void OnDataReceived(string s)
|
||||||
{
|
{
|
||||||
var bytesHandler = BytesReceived;
|
var bytesHandler = BytesReceived;
|
||||||
if (bytesHandler != null)
|
if (bytesHandler != null)
|
||||||
{
|
{
|
||||||
var bytes = Encoding.GetEncoding(28591).GetBytes(s);
|
var bytes = Encoding.GetEncoding(28591).GetBytes(s);
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedBytes(bytes);
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes));
|
|
||||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||||
}
|
}
|
||||||
var textHandler = TextReceived;
|
var textHandler = TextReceived;
|
||||||
if (textHandler != null)
|
if (textHandler != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedText(s);
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s);
|
textHandler(this, new GenericCommMethodReceiveTextArgs(s));
|
||||||
textHandler(this, new GenericCommMethodReceiveTextArgs(s));
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IBasicCommunication Members
|
#region IBasicCommunication Members
|
||||||
@@ -90,8 +88,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
{
|
{
|
||||||
if (Port == null)
|
if (Port == null)
|
||||||
return;
|
return;
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentText(text);
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text);
|
|
||||||
Port.StreamCec.Send.StringValue = text;
|
Port.StreamCec.Send.StringValue = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,8 +100,8 @@ namespace PepperDash.Essentials.Core
|
|||||||
if (Port == null)
|
if (Port == null)
|
||||||
return;
|
return;
|
||||||
var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
|
var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentBytes(bytes);
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
|
Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
|
||||||
Port.StreamCec.Send.StringValue = text;
|
Port.StreamCec.Send.StringValue = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +1,78 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharpPro;
|
using Crestron.SimplSharpPro;
|
||||||
|
using Crestron.SimplSharpPro.GeneralIO;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Core.Logging;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a ComPortController
|
/// Represents a ComPortController
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ComPortController : Device, IBasicCommunicationWithStreamDebugging
|
public class ComPortController : Device, IBasicCommunicationWithStreamDebugging
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the StreamDebugging
|
/// Gets or sets the StreamDebugging
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CommunicationStreamDebugging StreamDebugging { get; private set; }
|
public CommunicationStreamDebugging StreamDebugging { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired when bytes are received
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event fired when text is received
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the IsConnected
|
/// Gets or sets the IsConnected
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsConnected { get { return true; } }
|
public bool IsConnected { get { return true; } }
|
||||||
|
|
||||||
ComPort Port;
|
ComPort Port;
|
||||||
ComPort.ComPortSpec Spec;
|
ComPort.ComPortSpec Spec;
|
||||||
|
|
||||||
public ComPortController(string key, Func<EssentialsControlPropertiesConfig, ComPort> postActivationFunc,
|
/// <summary>
|
||||||
ComPort.ComPortSpec spec, EssentialsControlPropertiesConfig config) : base(key)
|
/// Constructor
|
||||||
{
|
/// </summary>
|
||||||
StreamDebugging = new CommunicationStreamDebugging(key);
|
/// <param name="key"></param>
|
||||||
|
/// <param name="postActivationFunc"></param>
|
||||||
|
/// <param name="spec"></param>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
public ComPortController(string key, Func<EssentialsControlPropertiesConfig, ComPort> postActivationFunc,
|
||||||
|
ComPort.ComPortSpec spec, EssentialsControlPropertiesConfig config) : base(key)
|
||||||
|
{
|
||||||
|
StreamDebugging = new CommunicationStreamDebugging(key);
|
||||||
|
|
||||||
Spec = spec;
|
Spec = spec;
|
||||||
|
|
||||||
AddPostActivationAction(() =>
|
AddPostActivationAction(() =>
|
||||||
{
|
{
|
||||||
Port = postActivationFunc(config);
|
Port = postActivationFunc(config);
|
||||||
|
|
||||||
RegisterAndConfigureComPort();
|
RegisterAndConfigureComPort();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Device key</param>
|
||||||
|
/// <param name="port">COM port instance</param>
|
||||||
|
/// <param name="spec">COM port specification</param>
|
||||||
public ComPortController(string key, ComPort port, ComPort.ComPortSpec spec)
|
public ComPortController(string key, ComPort port, ComPort.ComPortSpec spec)
|
||||||
: base(key)
|
: base(key)
|
||||||
{
|
{
|
||||||
if (port == null)
|
if (port == null)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Invalid com port, continuing but comms will not function");
|
Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Invalid com port, continuing but comms will not function");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,71 +83,77 @@ namespace PepperDash.Essentials.Core
|
|||||||
RegisterAndConfigureComPort();
|
RegisterAndConfigureComPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RegisterAndConfigureComPort()
|
private void RegisterAndConfigureComPort()
|
||||||
{
|
{
|
||||||
if (Port == null)
|
if (Port == null)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Configured com Port for this device does not exist.");
|
this.LogInformation($"Configured {Port.Parent.GetType().Name}-comport-{Port.ID} for {Key} does not exist.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Port.Parent is CrestronControlSystem)
|
|
||||||
{
|
|
||||||
var result = Port.Register();
|
|
||||||
if (result != eDeviceRegistrationUnRegistrationResponse.Success)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "ERROR: Cannot register Com port: {0}", result);
|
|
||||||
return; // false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var specResult = Port.SetComPortSpec(Spec);
|
|
||||||
if (specResult != 0)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "WARNING: Cannot set comspec");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Port.SerialDataReceived += Port_SerialDataReceived;
|
|
||||||
}
|
|
||||||
|
|
||||||
~ComPortController()
|
if (Port.Parent is CrestronControlSystem || Port.Parent is CenIoCom102)
|
||||||
|
{
|
||||||
|
var result = Port.Register();
|
||||||
|
if (result != eDeviceRegistrationUnRegistrationResponse.Success)
|
||||||
|
{
|
||||||
|
this.LogError($"Cannot register {Key} using {Port.Parent.GetType().Name}-comport-{Port.ID} (result == {result})");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.LogInformation($"Successfully registered {Key} using {Port.Parent.GetType().Name}-comport-{Port.ID} (result == {result})");
|
||||||
|
}
|
||||||
|
|
||||||
|
var specResult = Port.SetComPortSpec(Spec);
|
||||||
|
if (specResult != 0)
|
||||||
|
{
|
||||||
|
this.LogError($"Cannot set comspec for {Key} using {Port.Parent.GetType().Name}-comport-{Port.ID} (result == {specResult})");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.LogInformation($"Successfully set comspec for {Key} using {Port.Parent.GetType().Name}-comport-{Port.ID} (result == {specResult})");
|
||||||
|
|
||||||
|
Port.SerialDataReceived += Port_SerialDataReceived;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Destructor
|
||||||
|
/// </summary>
|
||||||
|
~ComPortController()
|
||||||
{
|
{
|
||||||
Port.SerialDataReceived -= Port_SerialDataReceived;
|
Port.SerialDataReceived -= Port_SerialDataReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Port_SerialDataReceived(ComPort ReceivingComPort, ComPortSerialDataEventArgs args)
|
void Port_SerialDataReceived(ComPort ReceivingComPort, ComPortSerialDataEventArgs args)
|
||||||
{
|
{
|
||||||
OnDataReceived(args.SerialData);
|
OnDataReceived(args.SerialData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDataReceived(string s)
|
void OnDataReceived(string s)
|
||||||
{
|
{
|
||||||
var eventSubscribed = false;
|
var eventSubscribed = false;
|
||||||
|
|
||||||
var bytesHandler = BytesReceived;
|
var bytesHandler = BytesReceived;
|
||||||
if (bytesHandler != null)
|
if (bytesHandler != null)
|
||||||
{
|
{
|
||||||
var bytes = Encoding.GetEncoding(28591).GetBytes(s);
|
var bytes = Encoding.GetEncoding(28591).GetBytes(s);
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedBytes(bytes);
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes));
|
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
|
||||||
eventSubscribed = true;
|
eventSubscribed = true;
|
||||||
}
|
}
|
||||||
var textHandler = TextReceived;
|
var textHandler = TextReceived;
|
||||||
if (textHandler != null)
|
if (textHandler != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
this.PrintReceivedText(s);
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s);
|
textHandler(this, new GenericCommMethodReceiveTextArgs(s));
|
||||||
textHandler(this, new GenericCommMethodReceiveTextArgs(s));
|
|
||||||
eventSubscribed = true;
|
eventSubscribed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!eventSubscribed) Debug.LogMessage(LogEventLevel.Warning, this, "Received data but no handler is registered");
|
if (!eventSubscribed) Debug.LogMessage(LogEventLevel.Warning, this, "Received data but no handler is registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deactivate method
|
/// Deactivate method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool Deactivate()
|
public override bool Deactivate()
|
||||||
{
|
{
|
||||||
return Port.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success;
|
return Port.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success;
|
||||||
@@ -136,70 +161,68 @@ namespace PepperDash.Essentials.Core
|
|||||||
|
|
||||||
#region IBasicCommunication Members
|
#region IBasicCommunication Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SendText method
|
/// SendText method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendText(string text)
|
public void SendText(string text)
|
||||||
{
|
{
|
||||||
if (Port == null)
|
if (Port == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentText(text);
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} characters of text: '{1}'", text.Length, text);
|
Port.Send(text);
|
||||||
Port.Send(text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SendBytes method
|
/// SendBytes method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendBytes(byte[] bytes)
|
public void SendBytes(byte[] bytes)
|
||||||
{
|
{
|
||||||
if (Port == null)
|
if (Port == null)
|
||||||
return;
|
return;
|
||||||
var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
|
var text = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
this.PrintSentBytes(bytes);
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
|
|
||||||
|
|
||||||
Port.Send(text);
|
Port.Send(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connect method
|
/// Connect method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Connect()
|
public void Connect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnect method
|
/// Disconnect method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="s"></param>
|
/// <param name="s"></param>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SimulateReceive method
|
/// SimulateReceive method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SimulateReceive(string s)
|
public void SimulateReceive(string s)
|
||||||
{
|
{
|
||||||
// split out hex chars and build string
|
// split out hex chars and build string
|
||||||
var split = Regex.Split(s, @"(\\[Xx][0-9a-fA-F][0-9a-fA-F])");
|
var split = Regex.Split(s, @"(\\[Xx][0-9a-fA-F][0-9a-fA-F])");
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
foreach (var t in split)
|
foreach (var t in split)
|
||||||
{
|
{
|
||||||
if (t.StartsWith(@"\") && t.Length == 4)
|
if (t.StartsWith(@"\") && t.Length == 4)
|
||||||
b.Append((char)(Convert.ToByte(t.Substring(2, 2), 16)));
|
b.Append((char)(Convert.ToByte(t.Substring(2, 2), 16)));
|
||||||
else
|
else
|
||||||
b.Append(t);
|
b.Append(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnDataReceived(b.ToString());
|
OnDataReceived(b.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,8 +64,11 @@ namespace PepperDash.Essentials.Core
|
|||||||
break;
|
break;
|
||||||
case eControlMethod.Ssh:
|
case eControlMethod.Ssh:
|
||||||
{
|
{
|
||||||
var ssh = new GenericSshClient(deviceConfig.Key + "-ssh", c.Address, c.Port, c.Username, c.Password);
|
var ssh = new GenericSshClient(deviceConfig.Key + "-ssh", c.Address, c.Port, c.Username, c.Password)
|
||||||
ssh.AutoReconnect = c.AutoReconnect;
|
{
|
||||||
|
AutoReconnect = c.AutoReconnect,
|
||||||
|
DisableEcho = c.DisableSshEcho
|
||||||
|
};
|
||||||
if (ssh.AutoReconnect)
|
if (ssh.AutoReconnect)
|
||||||
ssh.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
ssh.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
||||||
comm = ssh;
|
comm = ssh;
|
||||||
@@ -73,8 +76,10 @@ namespace PepperDash.Essentials.Core
|
|||||||
}
|
}
|
||||||
case eControlMethod.Tcpip:
|
case eControlMethod.Tcpip:
|
||||||
{
|
{
|
||||||
var tcp = new GenericTcpIpClient(deviceConfig.Key + "-tcp", c.Address, c.Port, c.BufferSize);
|
var tcp = new GenericTcpIpClient(deviceConfig.Key + "-tcp", c.Address, c.Port, c.BufferSize)
|
||||||
tcp.AutoReconnect = c.AutoReconnect;
|
{
|
||||||
|
AutoReconnect = c.AutoReconnect
|
||||||
|
};
|
||||||
if (tcp.AutoReconnect)
|
if (tcp.AutoReconnect)
|
||||||
tcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
tcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
||||||
comm = tcp;
|
comm = tcp;
|
||||||
@@ -90,8 +95,10 @@ namespace PepperDash.Essentials.Core
|
|||||||
break;
|
break;
|
||||||
case eControlMethod.SecureTcpIp:
|
case eControlMethod.SecureTcpIp:
|
||||||
{
|
{
|
||||||
var secureTcp = new GenericSecureTcpIpClient(deviceConfig.Key + "-secureTcp", c.Address, c.Port, c.BufferSize);
|
var secureTcp = new GenericSecureTcpIpClient(deviceConfig.Key + "-secureTcp", c.Address, c.Port, c.BufferSize)
|
||||||
secureTcp.AutoReconnect = c.AutoReconnect;
|
{
|
||||||
|
AutoReconnect = c.AutoReconnect
|
||||||
|
};
|
||||||
if (secureTcp.AutoReconnect)
|
if (secureTcp.AutoReconnect)
|
||||||
secureTcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
secureTcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
||||||
comm = secureTcp;
|
comm = secureTcp;
|
||||||
|
|||||||
@@ -127,19 +127,32 @@ namespace PepperDash.Essentials.Core.Config
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var doubleObj = JObject.Parse(fs.ReadToEnd());
|
var parsedConfig = JObject.Parse(fs.ReadToEnd());
|
||||||
ConfigObject = PortalConfigReader.MergeConfigs(doubleObj).ToObject<EssentialsConfig>();
|
|
||||||
|
|
||||||
// Extract SystemUrl and TemplateUrl into final config output
|
// Check if it's a v2 config (check for "version" node)
|
||||||
|
// this means it's already merged by the Portal API
|
||||||
|
// from the v2 config tool
|
||||||
|
var isV2Config = parsedConfig["versions"] != null;
|
||||||
|
|
||||||
if (doubleObj["system_url"] != null)
|
if (isV2Config)
|
||||||
{
|
{
|
||||||
ConfigObject.SystemUrl = doubleObj["system_url"].Value<string>();
|
Debug.LogMessage(LogEventLevel.Information, "Config file is a v2 format, no merge necessary.");
|
||||||
|
ConfigObject = parsedConfig.ToObject<EssentialsConfig>();
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "Successfully Loaded v2 Config");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doubleObj["template_url"] != null)
|
// Extract SystemUrl and TemplateUrl into final config output
|
||||||
|
ConfigObject = PortalConfigReader.MergeConfigs(parsedConfig).ToObject<EssentialsConfig>();
|
||||||
|
|
||||||
|
if (parsedConfig["system_url"] != null)
|
||||||
{
|
{
|
||||||
ConfigObject.TemplateUrl = doubleObj["template_url"].Value<string>();
|
ConfigObject.SystemUrl = parsedConfig["system_url"].Value<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedConfig["template_url"] != null)
|
||||||
|
{
|
||||||
|
ConfigObject.TemplateUrl = parsedConfig["template_url"].Value<string>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,86 +11,169 @@ using PepperDash.Core;
|
|||||||
|
|
||||||
namespace PepperDash.Essentials.Core.Config
|
namespace PepperDash.Essentials.Core.Config
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads the ConfigObject from the file
|
/// Loads the ConfigObject from the file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EssentialsConfig : BasicConfig
|
public class EssentialsConfig : BasicConfig
|
||||||
{
|
{
|
||||||
[JsonProperty("system_url")]
|
/// <summary>
|
||||||
|
/// Gets or sets the SystemUrl
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("system_url")]
|
||||||
public string SystemUrl { get; set; }
|
public string SystemUrl { get; set; }
|
||||||
|
|
||||||
[JsonProperty("template_url")]
|
/// <summary>
|
||||||
|
/// Gets or sets the TemplateUrl
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("template_url")]
|
||||||
public string TemplateUrl { get; set; }
|
public string TemplateUrl { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the SystemUuid extracted from the SystemUrl
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("systemUuid")]
|
[JsonProperty("systemUuid")]
|
||||||
public string SystemUuid
|
public string SystemUuid
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(SystemUrl))
|
string uuid;
|
||||||
return "missing url";
|
|
||||||
|
|
||||||
if (SystemUrl.Contains("#"))
|
if (string.IsNullOrEmpty(SystemUrl))
|
||||||
{
|
{
|
||||||
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*");
|
uuid = "missing url";
|
||||||
string uuid = result.Groups[1].Value;
|
}
|
||||||
return uuid;
|
else if (SystemUrl.Contains("#"))
|
||||||
} else
|
{
|
||||||
{
|
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/#.*");
|
||||||
|
uuid = result.Groups[1].Value;
|
||||||
|
}
|
||||||
|
else if (SystemUrl.Contains("detail"))
|
||||||
|
{
|
||||||
|
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/detail\/(.*)\/.*");
|
||||||
|
uuid = result.Groups[1].Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/.*");
|
var result = Regex.Match(SystemUrl, @"https?:\/\/.*\/systems\/(.*)\/.*");
|
||||||
string uuid = result.Groups[1].Value;
|
uuid = result.Groups[1].Value;
|
||||||
return uuid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return uuid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the TemplateUuid extracted from the TemplateUrl
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("templateUuid")]
|
[JsonProperty("templateUuid")]
|
||||||
public string TemplateUuid
|
public string TemplateUuid
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(TemplateUrl))
|
string uuid;
|
||||||
return "missing template url";
|
|
||||||
|
|
||||||
if (TemplateUrl.Contains("#"))
|
if (string.IsNullOrEmpty(TemplateUrl))
|
||||||
{
|
{
|
||||||
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/templates\/(.*)\/#.*");
|
uuid = "missing template url";
|
||||||
string uuid = result.Groups[1].Value;
|
|
||||||
return uuid;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/(.*)\/system-template-versions\/(.*)\/.*");
|
|
||||||
string uuid = result.Groups[2].Value;
|
|
||||||
return uuid;
|
|
||||||
}
|
}
|
||||||
|
else if (TemplateUrl.Contains("#"))
|
||||||
|
{
|
||||||
|
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/templates\/(.*)\/#.*");
|
||||||
|
uuid = result.Groups[1].Value;
|
||||||
|
}
|
||||||
|
else if (TemplateUrl.Contains("detail"))
|
||||||
|
{
|
||||||
|
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/detail\/(.*)\/system-template-versions\/detail\/(.*)\/.*");
|
||||||
|
uuid = result.Groups[2].Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = Regex.Match(TemplateUrl, @"https?:\/\/.*\/system-templates\/(.*)\/system-template-versions\/(.*)\/.*");
|
||||||
|
uuid = result.Groups[2].Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uuid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonProperty("rooms")]
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Rooms
|
/// Gets or sets the Rooms
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonProperty("rooms")]
|
||||||
public List<DeviceConfig> Rooms { get; set; }
|
public List<DeviceConfig> Rooms { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Versions
|
||||||
|
/// </summary>
|
||||||
|
public VersionData Versions { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EssentialsConfig"/> class.
|
||||||
|
/// </summary>
|
||||||
public EssentialsConfig()
|
public EssentialsConfig()
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
Rooms = new List<DeviceConfig>();
|
Rooms = new List<DeviceConfig>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a SystemTemplateConfigs
|
/// Represents version data for Essentials and its packages
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SystemTemplateConfigs
|
public class VersionData
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the System
|
/// Gets or sets the Essentials version
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonProperty("essentials")]
|
||||||
|
public NugetVersion Essentials { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the list of Packages
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("packages")]
|
||||||
|
public List<NugetVersion> Packages { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="VersionData"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public VersionData()
|
||||||
|
{
|
||||||
|
Packages = new List<NugetVersion>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a NugetVersion
|
||||||
|
/// </summary>
|
||||||
|
public class NugetVersion
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Version
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("version")]
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the PackageId
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("packageId")]
|
||||||
|
public string PackageId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a SystemTemplateConfigs
|
||||||
|
/// </summary>
|
||||||
|
public class SystemTemplateConfigs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the System
|
||||||
|
/// </summary>
|
||||||
public EssentialsConfig System { get; set; }
|
public EssentialsConfig System { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Template
|
||||||
|
/// </summary>
|
||||||
public EssentialsConfig Template { get; set; }
|
public EssentialsConfig Template { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,9 +60,9 @@ namespace PepperDash.Essentials.Core
|
|||||||
ConsoleAccessLevelEnum.AccessOperator);
|
ConsoleAccessLevelEnum.AccessOperator);
|
||||||
CrestronConsole.AddNewConsoleCommand(DeviceJsonApi.DoDeviceActionWithJson, "devjson", "",
|
CrestronConsole.AddNewConsoleCommand(DeviceJsonApi.DoDeviceActionWithJson, "devjson", "",
|
||||||
ConsoleAccessLevelEnum.AccessOperator);
|
ConsoleAccessLevelEnum.AccessOperator);
|
||||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetProperties(s)), "devprops", "", ConsoleAccessLevelEnum.AccessOperator);
|
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetProperties(s).Replace(Environment.NewLine, "\r\n")), "devprops", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetMethods(s)), "devmethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetMethods(s).Replace(Environment.NewLine, "\r\n")), "devmethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetApiMethods(s)), "apimethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
CrestronConsole.AddNewConsoleCommand(s => CrestronConsole.ConsoleCommandResponse(DeviceJsonApi.GetApiMethods(s).Replace(Environment.NewLine, "\r\n")), "apimethods", "", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
CrestronConsole.AddNewConsoleCommand(SimulateComReceiveOnDevice, "devsimreceive",
|
CrestronConsole.AddNewConsoleCommand(SimulateComReceiveOnDevice, "devsimreceive",
|
||||||
"Simulates incoming data on a com device", ConsoleAccessLevelEnum.AccessOperator);
|
"Simulates incoming data on a com device", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
|
|||||||
@@ -16,121 +16,201 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Processor Attributes
|
// Processor Attributes
|
||||||
|
/// <summary>
|
||||||
|
/// Processor IP 1
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorIp1")]
|
[JoinName("ProcessorIp1")]
|
||||||
public JoinDataComplete ProcessorIp1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Info - Processor - IP 1" },
|
public JoinDataComplete ProcessorIp1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Info - Processor - IP 1" },
|
||||||
new JoinMetadata { Description = "Info - Processor - IP 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - IP 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor IP 2
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorIp2")]
|
[JoinName("ProcessorIp2")]
|
||||||
public JoinDataComplete ProcessorIp2 = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1, AttributeName = "Info - Processor - IP 2" },
|
public JoinDataComplete ProcessorIp2 = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1, AttributeName = "Info - Processor - IP 2" },
|
||||||
new JoinMetadata { Description = "Info - Processor - IP 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - IP 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor Gateway
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorGateway")]
|
[JoinName("ProcessorGateway")]
|
||||||
public JoinDataComplete ProcessorGateway = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1, AttributeName = "Info - Processor - Gateway" },
|
public JoinDataComplete ProcessorGateway = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1, AttributeName = "Info - Processor - Gateway" },
|
||||||
new JoinMetadata { Description = "Info - Processor - Gateway", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - Gateway", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor Hostname
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorHostname")]
|
[JoinName("ProcessorHostname")]
|
||||||
public JoinDataComplete ProcessorHostname = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1, AttributeName = "Info - Processor - Hostname" },
|
public JoinDataComplete ProcessorHostname = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1, AttributeName = "Info - Processor - Hostname" },
|
||||||
new JoinMetadata { Description = "Info - Processor - Hostname", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - Hostname", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor Domain
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorDomain")]
|
[JoinName("ProcessorDomain")]
|
||||||
public JoinDataComplete ProcessorDomain = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1, AttributeName = "Info - Processor - Domain" },
|
public JoinDataComplete ProcessorDomain = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1, AttributeName = "Info - Processor - Domain" },
|
||||||
new JoinMetadata { Description = "Info - Processor - Domain", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - Domain", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor DNS 1
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorDns1")]
|
[JoinName("ProcessorDns1")]
|
||||||
public JoinDataComplete ProcessorDns1 = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1, AttributeName = "Info - Processor - DNS 1" },
|
public JoinDataComplete ProcessorDns1 = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1, AttributeName = "Info - Processor - DNS 1" },
|
||||||
new JoinMetadata { Description = "Info - Processor - DNS 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - DNS 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor DNS 2
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorDns2")]
|
[JoinName("ProcessorDns2")]
|
||||||
public JoinDataComplete ProcessorDns2 = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1, AttributeName = "Info - Processor - DNS 2" },
|
public JoinDataComplete ProcessorDns2 = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1, AttributeName = "Info - Processor - DNS 2" },
|
||||||
new JoinMetadata { Description = "Info - Processor - DNS 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - DNS 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor MAC 1
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorMac1")]
|
[JoinName("ProcessorMac1")]
|
||||||
public JoinDataComplete ProcessorMac1 = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1, AttributeName = "Info - Processor - MAC 1" },
|
public JoinDataComplete ProcessorMac1 = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1, AttributeName = "Info - Processor - MAC 1" },
|
||||||
new JoinMetadata { Description = "Info - Processor - MAC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - MAC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor MAC 2
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorMac2")]
|
[JoinName("ProcessorMac2")]
|
||||||
public JoinDataComplete ProcessorMac2 = new JoinDataComplete(new JoinData { JoinNumber = 58, JoinSpan = 1, AttributeName = "Info - Processor - MAC 2" },
|
public JoinDataComplete ProcessorMac2 = new JoinDataComplete(new JoinData { JoinNumber = 58, JoinSpan = 1, AttributeName = "Info - Processor - MAC 2" },
|
||||||
new JoinMetadata { Description = "Info - Processor - MAC 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - MAC 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor Net Mask 1
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorNetMask1")]
|
[JoinName("ProcessorNetMask1")]
|
||||||
public JoinDataComplete ProcessorNetMask1 = new JoinDataComplete(new JoinData { JoinNumber = 59, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 1" },
|
public JoinDataComplete ProcessorNetMask1 = new JoinDataComplete(new JoinData { JoinNumber = 59, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 1" },
|
||||||
new JoinMetadata { Description = "Info - Processor - Net Mask 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - Net Mask 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor Net Mask 2
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorNetMask2")]
|
[JoinName("ProcessorNetMask2")]
|
||||||
public JoinDataComplete ProcessorNetMask2 = new JoinDataComplete(new JoinData { JoinNumber = 60, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 2" },
|
public JoinDataComplete ProcessorNetMask2 = new JoinDataComplete(new JoinData { JoinNumber = 60, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 2" },
|
||||||
new JoinMetadata { Description = "Info - Processor - Net Mask 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - Net Mask 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor Firmware
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorFirmware")]
|
[JoinName("ProcessorFirmware")]
|
||||||
public JoinDataComplete ProcessorFirmware = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1, AttributeName = "Info - Processor - Firmware" },
|
public JoinDataComplete ProcessorFirmware = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1, AttributeName = "Info - Processor - Firmware" },
|
||||||
new JoinMetadata { Description = "Info - Processor - Firmware", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - Firmware", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Program Name Start
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProgramNameStart")]
|
[JoinName("ProgramNameStart")]
|
||||||
public JoinDataComplete ProgramNameStart = new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 10, AttributeName = "Info - Processor - Program" },
|
public JoinDataComplete ProgramNameStart = new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 10, AttributeName = "Info - Processor - Program" },
|
||||||
new JoinMetadata { Description = "Info - Processor - Program", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Info - Processor - Program", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processor Reboot
|
||||||
|
/// </summary>
|
||||||
[JoinName("ProcessorReboot")]
|
[JoinName("ProcessorReboot")]
|
||||||
public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 74, JoinSpan = 1, AttributeName = "Processor - Reboot" },
|
public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 74, JoinSpan = 1, AttributeName = "Processor - Reboot" },
|
||||||
new JoinMetadata { Description = "Processor - Reboot", JoinCapabilities = eJoinCapabilities.FromFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Processor - Reboot", JoinCapabilities = eJoinCapabilities.FromFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
// Volume Controls
|
// Volume Controls
|
||||||
|
/// <summary>
|
||||||
|
/// Volume Fader 1
|
||||||
|
/// </summary>
|
||||||
[JoinName("VolumeFader1")]
|
[JoinName("VolumeFader1")]
|
||||||
public JoinDataComplete VolumeFader1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Volume - Fader01" },
|
public JoinDataComplete VolumeFader1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Volume - Fader01" },
|
||||||
new JoinMetadata { Description = "Volume - Fader01", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Analog });
|
new JoinMetadata { Description = "Volume - Fader01", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Analog });
|
||||||
|
|
||||||
// Codec Info
|
// Codec Info
|
||||||
|
/// <summary>
|
||||||
|
/// VC Codec In Call
|
||||||
|
/// </summary>
|
||||||
[JoinName("VcCodecInCall")]
|
[JoinName("VcCodecInCall")]
|
||||||
public JoinDataComplete VcCodecInCall = new JoinDataComplete(new JoinData { JoinNumber = 69, JoinSpan = 1, AttributeName = "Conf - VC 1 In Call" },
|
public JoinDataComplete VcCodecInCall = new JoinDataComplete(new JoinData { JoinNumber = 69, JoinSpan = 1, AttributeName = "Conf - VC 1 In Call" },
|
||||||
new JoinMetadata { Description = "Conf - VC 1 In Call", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Conf - VC 1 In Call", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VC Codec Online
|
||||||
|
/// </summary>
|
||||||
[JoinName("VcCodecOnline")]
|
[JoinName("VcCodecOnline")]
|
||||||
public JoinDataComplete VcCodecOnline = new JoinDataComplete(new JoinData { JoinNumber = 122, JoinSpan = 1, AttributeName = "Online - VC 1" },
|
public JoinDataComplete VcCodecOnline = new JoinDataComplete(new JoinData { JoinNumber = 122, JoinSpan = 1, AttributeName = "Online - VC 1" },
|
||||||
new JoinMetadata { Description = "Online - VC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Online - VC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VC Codec IP Address
|
||||||
|
/// </summary>
|
||||||
[JoinName("VcCodecIpAddress")]
|
[JoinName("VcCodecIpAddress")]
|
||||||
public JoinDataComplete VcCodecIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 121, JoinSpan = 1, AttributeName = "IP Address - VC" },
|
public JoinDataComplete VcCodecIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 121, JoinSpan = 1, AttributeName = "IP Address - VC" },
|
||||||
new JoinMetadata { Description = "IP Address - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "IP Address - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// VC Codec IP Port
|
||||||
|
/// </summary>
|
||||||
[JoinName("VcCodecIpPort")]
|
[JoinName("VcCodecIpPort")]
|
||||||
public JoinDataComplete VcCodecIpPort = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 1, AttributeName = "IP Port - VC" },
|
public JoinDataComplete VcCodecIpPort = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 1, AttributeName = "IP Port - VC" },
|
||||||
new JoinMetadata { Description = "IP Port - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "IP Port - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
// Source Attributes
|
// Source Attributes
|
||||||
|
/// <summary>
|
||||||
|
/// Display 1 Current Source Name
|
||||||
|
/// </summary>
|
||||||
[JoinName("Display1CurrentSourceName")]
|
[JoinName("Display1CurrentSourceName")]
|
||||||
public JoinDataComplete Display1CurrentSourceName = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1, AttributeName = "Display 1 - Current Source" },
|
public JoinDataComplete Display1CurrentSourceName = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1, AttributeName = "Display 1 - Current Source" },
|
||||||
new JoinMetadata { Description = "Display 1 - Current Source", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
new JoinMetadata { Description = "Display 1 - Current Source", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial });
|
||||||
|
|
||||||
|
|
||||||
// Device Online Status
|
// Device Online Status
|
||||||
|
/// <summary>
|
||||||
|
/// Touchpanel Online Start
|
||||||
|
/// </summary>
|
||||||
[JoinName("TouchpanelOnlineStart")]
|
[JoinName("TouchpanelOnlineStart")]
|
||||||
public JoinDataComplete TouchpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 10, AttributeName = "Online - Touch Panel" },
|
public JoinDataComplete TouchpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 10, AttributeName = "Online - Touch Panel" },
|
||||||
new JoinMetadata { Description = "Online - Touch Panel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Online - Touch Panel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Xpanel Online Start
|
||||||
|
/// </summary>
|
||||||
[JoinName("XpanelOnlineStart")]
|
[JoinName("XpanelOnlineStart")]
|
||||||
public JoinDataComplete XpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 160, JoinSpan = 5, AttributeName = "Online - XPanel" },
|
public JoinDataComplete XpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 160, JoinSpan = 5, AttributeName = "Online - XPanel" },
|
||||||
new JoinMetadata { Description = "Online - XPanel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Online - XPanel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display Online Start
|
||||||
|
/// </summary>
|
||||||
[JoinName("DisplayOnlineStart")]
|
[JoinName("DisplayOnlineStart")]
|
||||||
public JoinDataComplete DisplayOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 170, JoinSpan = 10, AttributeName = "Online - Display" },
|
public JoinDataComplete DisplayOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 170, JoinSpan = 10, AttributeName = "Online - Display" },
|
||||||
new JoinMetadata { Description = "Online - Display", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Online - Display", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display 1 Laptop Source Start
|
||||||
|
/// </summary>
|
||||||
[JoinName("Display1LaptopSourceStart")]
|
[JoinName("Display1LaptopSourceStart")]
|
||||||
public JoinDataComplete Display1LaptopSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 166, JoinSpan = 5, AttributeName = "Display 1 - Source Laptop" },
|
public JoinDataComplete Display1LaptopSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 165, JoinSpan = 5, AttributeName = "Display 1 - Source Laptop" },
|
||||||
new JoinMetadata { Description = "Display 1 - Source Laptop", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Display 1 - Source Laptop", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display 1 Disc Player Source Start
|
||||||
|
/// </summary>
|
||||||
[JoinName("Display1DiscPlayerSourceStart")]
|
[JoinName("Display1DiscPlayerSourceStart")]
|
||||||
public JoinDataComplete Display1DiscPlayerSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 181, JoinSpan = 5, AttributeName = "Display 1 - Source Disc Player" },
|
public JoinDataComplete Display1DiscPlayerSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 180, JoinSpan = 5, AttributeName = "Display 1 - Source Disc Player" },
|
||||||
new JoinMetadata { Description = "Display 1 - Source Disc Player", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Display 1 - Source Disc Player", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Display 1 Set Top Box Source Start
|
||||||
|
/// </summary>
|
||||||
[JoinName("Display1SetTopBoxSourceStart")]
|
[JoinName("Display1SetTopBoxSourceStart")]
|
||||||
public JoinDataComplete Display1SetTopBoxSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 188, JoinSpan = 5, AttributeName = "Display 1 - Source TV" },
|
public JoinDataComplete Display1SetTopBoxSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 185, JoinSpan = 5, AttributeName = "Display 1 - Source TV" },
|
||||||
new JoinMetadata { Description = "Display 1 - Source TV", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Display 1 - Source TV", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
// Display 1
|
// Display 1
|
||||||
|
/// <summary>
|
||||||
|
/// Display 1 Start
|
||||||
|
/// </summary>
|
||||||
[JoinName("Display1Start")]
|
[JoinName("Display1Start")]
|
||||||
public JoinDataComplete Display1Start = new JoinDataComplete(new JoinData { JoinNumber = 158, JoinSpan = 1 },
|
public JoinDataComplete Display1Start = new JoinDataComplete(new JoinData { JoinNumber = 190, JoinSpan = 1 },
|
||||||
new JoinMetadata { Description = "Display 1 Start", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital });
|
new JoinMetadata { Description = "Display 1 Start", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital });
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor to use when instantiating this Join Map without inheriting from it
|
/// Constructor to use when instantiating this Join Map without inheriting from it
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
|
using Crestron.SimplSharp;
|
||||||
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using Crestron.SimplSharp.CrestronXml;
|
using Crestron.SimplSharp.CrestronXml;
|
||||||
using Crestron.SimplSharp.CrestronXml.Serialization;
|
using Crestron.SimplSharp.CrestronXml.Serialization;
|
||||||
@@ -8,6 +6,7 @@ using Crestron.SimplSharpPro;
|
|||||||
using Crestron.SimplSharpPro.Fusion;
|
using Crestron.SimplSharpPro.Fusion;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Core.Logging;
|
||||||
using PepperDash.Essentials.Core.Config;
|
using PepperDash.Essentials.Core.Config;
|
||||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
@@ -21,26 +20,42 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a EssentialsHuddleSpaceFusionSystemControllerBase
|
/// Represents a EssentialsHuddleSpaceFusionSystemControllerBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider
|
public class IEssentialsRoomFusionController : EssentialsDevice, IOccupancyStatusProvider, IFusionHelpRequest, IHasFeedback
|
||||||
{
|
{
|
||||||
private readonly EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap;
|
private IEssentialsRoomFusionControllerPropertiesConfig _config;
|
||||||
|
|
||||||
|
private EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap;
|
||||||
|
|
||||||
private const string RemoteOccupancyXml = "<Occupancy><Type>Local</Type><State>{0}</State></Occupancy>";
|
private const string RemoteOccupancyXml = "<Occupancy><Type>Local</Type><State>{0}</State></Occupancy>";
|
||||||
private readonly bool _guidFileExists;
|
private bool _guidFileExists;
|
||||||
|
|
||||||
private readonly Dictionary<Device, BoolInputSig> _sourceToFeedbackSigs =
|
private readonly Dictionary<Device, BoolInputSig> _sourceToFeedbackSigs =
|
||||||
new Dictionary<Device, BoolInputSig>();
|
new Dictionary<Device, BoolInputSig>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the CurrentRoomSourceNameSig
|
||||||
|
/// </summary>
|
||||||
protected StringSigData CurrentRoomSourceNameSig;
|
protected StringSigData CurrentRoomSourceNameSig;
|
||||||
|
|
||||||
private readonly FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge();
|
private readonly FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the FusionOccSensor
|
||||||
|
/// </summary>
|
||||||
protected FusionOccupancySensorAsset FusionOccSensor;
|
protected FusionOccupancySensorAsset FusionOccSensor;
|
||||||
private readonly FusionRemoteOccupancySensor FusionRemoteOccSensor;
|
private readonly FusionRemoteOccupancySensor FusionRemoteOccSensor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the FusionRoom
|
||||||
|
/// </summary>
|
||||||
protected FusionRoom FusionRoom;
|
protected FusionRoom FusionRoom;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the FusionStaticAssets
|
||||||
|
/// </summary>
|
||||||
protected Dictionary<int, FusionAsset> FusionStaticAssets;
|
protected Dictionary<int, FusionAsset> FusionStaticAssets;
|
||||||
private readonly long PushNotificationTimeout = 5000;
|
private readonly long PushNotificationTimeout = 5000;
|
||||||
private readonly IEssentialsRoom Room;
|
private IEssentialsRoom Room;
|
||||||
private readonly long SchedulePollInterval = 300000;
|
private readonly long SchedulePollInterval = 300000;
|
||||||
|
|
||||||
private Event _currentMeeting;
|
private Event _currentMeeting;
|
||||||
@@ -48,8 +63,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
private CTimer _dailyTimeRequestTimer;
|
private CTimer _dailyTimeRequestTimer;
|
||||||
private StatusMonitorCollection _errorMessageRollUp;
|
private StatusMonitorCollection _errorMessageRollUp;
|
||||||
|
|
||||||
private FusionRoomGuids _guiDs;
|
private FusionRoomGuids _guids;
|
||||||
private uint _ipId;
|
|
||||||
|
|
||||||
private bool _isRegisteredForSchedulePushNotifications;
|
private bool _isRegisteredForSchedulePushNotifications;
|
||||||
private Event _nextMeeting;
|
private Event _nextMeeting;
|
||||||
@@ -60,6 +74,20 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
private string _roomOccupancyRemoteString;
|
private string _roomOccupancyRemoteString;
|
||||||
|
|
||||||
|
private bool _helpRequestSent;
|
||||||
|
|
||||||
|
private eFusionHelpResponse _helpRequestStatus;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public StringFeedback HelpRequestResponseFeedback { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public BoolFeedback HelpRequestSentFeedback { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public StringFeedback HelpRequestStatusFeedback { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
#region System Info Sigs
|
#region System Info Sigs
|
||||||
|
|
||||||
//StringSigData SystemName;
|
//StringSigData SystemName;
|
||||||
@@ -93,17 +121,88 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public EssentialsHuddleSpaceFusionSystemControllerBase(IEssentialsRoom room, uint ipId, string joinMapKey)
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
public IEssentialsRoomFusionController(string key, string name, IEssentialsRoomFusionControllerPropertiesConfig config)
|
||||||
|
: base(key, name)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
|
||||||
|
AddPostActivationAction(() =>
|
||||||
|
{
|
||||||
|
var room = DeviceManager.GetDeviceForKey<IEssentialsRoom>(_config.RoomKey);
|
||||||
|
|
||||||
|
if (room == null)
|
||||||
|
{
|
||||||
|
this.LogError("Error Creating Fusion Room Controller. No room found with key '{0}'", _config.RoomKey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.LogInformation("Creating Fusion Room Controller for room '{0}' at IPID: {1:X2}", room.Key, _config.IpIdInt);
|
||||||
|
|
||||||
|
ConstructorHelper(room, _config.IpIdInt, _config.JoinMapKey);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="room"></param>
|
||||||
|
/// <param name="ipId"></param>
|
||||||
|
/// <param name="joinMapKey"></param>
|
||||||
|
public IEssentialsRoomFusionController(IEssentialsRoom room, string ipId, string joinMapKey)
|
||||||
: base(room.Key + "-fusion")
|
: base(room.Key + "-fusion")
|
||||||
|
{
|
||||||
|
_config = new IEssentialsRoomFusionControllerPropertiesConfig()
|
||||||
|
{
|
||||||
|
IpId = ipId,
|
||||||
|
RoomKey = room.Key,
|
||||||
|
JoinMapKey = joinMapKey
|
||||||
|
};
|
||||||
|
|
||||||
|
ConstructorHelper(room, _config.IpIdInt, joinMapKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConstructorHelper(IEssentialsRoom room, uint ipId, string joinMapKey)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
this.LogDebug("ConstructorHelper called for Fusion Room Controller for room '{0}' with IPID {1:X2}", room.Key, ipId);
|
||||||
|
|
||||||
|
this.LogDebug("JoinMap Key: {0}", joinMapKey);
|
||||||
|
|
||||||
JoinMap = new EssentialsHuddleSpaceRoomFusionRoomJoinMap(1);
|
JoinMap = new EssentialsHuddleSpaceRoomFusionRoomJoinMap(1);
|
||||||
|
|
||||||
CrestronConsole.AddNewConsoleCommand((o) => JoinMap.PrintJoinMapInfo(), string.Format("ptjnmp-{0}", Key), "Prints Attribute Join Map", ConsoleAccessLevelEnum.AccessOperator);
|
this.LogDebug("JoinMap created");
|
||||||
|
|
||||||
|
CrestronConsole.AddNewConsoleCommand((o) =>
|
||||||
|
{
|
||||||
|
if (o is string deviceKey)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(deviceKey) || deviceKey == "?")
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Please provide a device key for a Fusion Room instance");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (deviceKey != this.Key)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Invalid parameter. Please provide a device key for a Fusion Room instance");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JoinMap.PrintJoinMapInfo();
|
||||||
|
}, "printfusionjoinmap", "Prints Attribute Join Map", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(joinMapKey))
|
if (!string.IsNullOrEmpty(joinMapKey))
|
||||||
{
|
{
|
||||||
|
// this.LogDebug("Attempting to get custom join map for key: {0}", joinMapKey);
|
||||||
var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey);
|
var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey);
|
||||||
if (customJoins != null)
|
if (customJoins != null)
|
||||||
{
|
{
|
||||||
@@ -113,51 +212,19 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
Room = room;
|
Room = room;
|
||||||
|
|
||||||
_ipId = ipId;
|
this.LogDebug("Room found: {0}", Room.Key);
|
||||||
|
|
||||||
FusionStaticAssets = new Dictionary<int, FusionAsset>();
|
FusionStaticAssets = new Dictionary<int, FusionAsset>();
|
||||||
|
|
||||||
_guiDs = new FusionRoomGuids();
|
this.LogDebug("FusionStaticAssets dictionary created");
|
||||||
|
|
||||||
var mac =
|
_guids = new FusionRoomGuids();
|
||||||
CrestronEthernetHelper.GetEthernetParameter(
|
|
||||||
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0);
|
|
||||||
|
|
||||||
var slot = Global.ControlSystem.ProgramNumber;
|
|
||||||
|
|
||||||
var guidFilePath = Global.FilePathPrefix +
|
|
||||||
string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _ipId);
|
|
||||||
|
|
||||||
var oldGuidFilePath = Global.FilePathPrefix +
|
|
||||||
string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag);
|
|
||||||
|
|
||||||
if (File.Exists(oldGuidFilePath))
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Migrating from old Fusion GUID file to new Fusion GUID File");
|
|
||||||
|
|
||||||
File.Copy(oldGuidFilePath, guidFilePath);
|
|
||||||
|
|
||||||
File.Delete(oldGuidFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
_guidFileExists = File.Exists(guidFilePath);
|
|
||||||
|
|
||||||
// Check if file exists
|
|
||||||
if (!_guidFileExists)
|
|
||||||
{
|
|
||||||
// Does not exist. Create GUIDs
|
|
||||||
_guiDs = new FusionRoomGuids(Room.Name, ipId, _guiDs.GenerateNewRoomGuid(slot, mac),
|
|
||||||
FusionStaticAssets);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Exists. Read GUIDs
|
|
||||||
ReadGuidFile(guidFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.LogDebug("FusionRoomGuids created");
|
||||||
|
|
||||||
if (Room is IRoomOccupancy occupancyRoom)
|
if (Room is IRoomOccupancy occupancyRoom)
|
||||||
{
|
{
|
||||||
|
Debug.LogDebug(this, "Room '{0}' supports IRoomOccupancy", Room.Key);
|
||||||
if (occupancyRoom.RoomOccupancy != null)
|
if (occupancyRoom.RoomOccupancy != null)
|
||||||
{
|
{
|
||||||
if (occupancyRoom.OccupancyStatusProviderIsRemote)
|
if (occupancyRoom.OccupancyStatusProviderIsRemote)
|
||||||
@@ -171,8 +238,21 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.LogDebug("Occupancy setup complete");
|
||||||
|
|
||||||
|
HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.OutputSig.StringValue);
|
||||||
|
|
||||||
|
HelpRequestSentFeedback = new BoolFeedback("HelpRequestSent", () => _helpRequestSent);
|
||||||
|
HelpRequestStatusFeedback = new StringFeedback("HelpRequestStatus", () => _helpRequestStatus.ToString());
|
||||||
|
|
||||||
|
Feedbacks.Add(HelpRequestResponseFeedback);
|
||||||
|
Feedbacks.Add(HelpRequestSentFeedback);
|
||||||
|
Feedbacks.Add(HelpRequestStatusFeedback);
|
||||||
|
if (RoomOccupancyRemoteStringFeedback != null)
|
||||||
|
Feedbacks.Add(RoomOccupancyRemoteStringFeedback);
|
||||||
|
if (RoomIsOccupiedFeedback != null)
|
||||||
|
Feedbacks.Add(RoomIsOccupiedFeedback);
|
||||||
|
|
||||||
AddPostActivationAction(() => PostActivate(guidFilePath));
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -180,9 +260,54 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PostActivate(string guidFilePath)
|
private string GetGuidFilePath(uint ipId)
|
||||||
{
|
{
|
||||||
CreateSymbolAndBasicSigs(_ipId);
|
var mac =
|
||||||
|
CrestronEthernetHelper.GetEthernetParameter(
|
||||||
|
CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0);
|
||||||
|
|
||||||
|
var slot = Global.ControlSystem.ProgramNumber;
|
||||||
|
|
||||||
|
var guidFilePath = Global.FilePathPrefix +
|
||||||
|
string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _config.IpIdInt);
|
||||||
|
|
||||||
|
var oldGuidFilePath = Global.FilePathPrefix +
|
||||||
|
string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag);
|
||||||
|
|
||||||
|
if (File.Exists(oldGuidFilePath))
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, this, "Migrating from old Fusion GUID file to new Fusion GUID File");
|
||||||
|
|
||||||
|
File.Copy(oldGuidFilePath, guidFilePath);
|
||||||
|
|
||||||
|
File.Delete(oldGuidFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
_guidFileExists = File.Exists(guidFilePath);
|
||||||
|
|
||||||
|
// Check if file exists
|
||||||
|
if (!_guidFileExists)
|
||||||
|
{
|
||||||
|
// Does not exist. Create GUIDs
|
||||||
|
_guids = new FusionRoomGuids(Room.Name, ipId, _guids.GenerateNewRoomGuid(slot, mac),
|
||||||
|
FusionStaticAssets);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Exists. Read GUIDs
|
||||||
|
ReadGuidFile(guidFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return guidFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
GenerateGuidFile(GetGuidFilePath(_config.IpIdInt));
|
||||||
|
|
||||||
|
CreateSymbolAndBasicSigs(_config.IpIdInt);
|
||||||
SetUpSources();
|
SetUpSources();
|
||||||
SetUpCommunitcationMonitors();
|
SetUpCommunitcationMonitors();
|
||||||
SetUpDisplay();
|
SetUpDisplay();
|
||||||
@@ -191,12 +316,14 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
FusionRVI.GenerateFileForAllFusionDevices();
|
FusionRVI.GenerateFileForAllFusionDevices();
|
||||||
|
|
||||||
GenerateGuidFile(guidFilePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the RoomGuid
|
||||||
|
/// </summary>
|
||||||
protected string RoomGuid
|
protected string RoomGuid
|
||||||
{
|
{
|
||||||
get { return _guiDs.RoomGuid; }
|
get { return _guids.RoomGuid; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -204,6 +331,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public StringFeedback RoomOccupancyRemoteStringFeedback { get; private set; }
|
public StringFeedback RoomOccupancyRemoteStringFeedback { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the RoomIsOccupiedFeedbackFunc
|
||||||
|
/// </summary>
|
||||||
protected Func<bool> RoomIsOccupiedFeedbackFunc
|
protected Func<bool> RoomIsOccupiedFeedbackFunc
|
||||||
{
|
{
|
||||||
get { return () => FusionRemoteOccSensor.RoomOccupied.OutputSig.BoolValue; }
|
get { return () => FusionRemoteOccSensor.RoomOccupied.OutputSig.BoolValue; }
|
||||||
@@ -218,10 +348,21 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public FeedbackCollection<Feedback> Feedbacks { get; private set; } = new FeedbackCollection<Feedback>();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ScheduleChange event
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<ScheduleChangeEventArgs> ScheduleChange;
|
public event EventHandler<ScheduleChangeEventArgs> ScheduleChange;
|
||||||
//public event EventHandler<MeetingChangeEventArgs> MeetingEndWarning;
|
//public event EventHandler<MeetingChangeEventArgs> MeetingEndWarning;
|
||||||
//public event EventHandler<MeetingChangeEventArgs> NextMeetingBeginWarning;
|
//public event EventHandler<MeetingChangeEventArgs> NextMeetingBeginWarning;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RoomInfoChange event
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<EventArgs> RoomInfoChange;
|
public event EventHandler<EventArgs> RoomInfoChange;
|
||||||
|
|
||||||
//ScheduleResponseEvent NextMeeting;
|
//ScheduleResponseEvent NextMeeting;
|
||||||
@@ -258,11 +399,11 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, this, "Writing GUIDs to file");
|
Debug.LogMessage(LogEventLevel.Debug, this, "Writing GUIDs to file");
|
||||||
|
|
||||||
_guiDs = FusionOccSensor == null
|
_guids = FusionOccSensor == null
|
||||||
? new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets)
|
? new FusionRoomGuids(Room.Name, _config.IpIdInt, RoomGuid, FusionStaticAssets)
|
||||||
: new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets, FusionOccSensor);
|
: new FusionRoomGuids(Room.Name, _config.IpIdInt, RoomGuid, FusionStaticAssets, FusionOccSensor);
|
||||||
|
|
||||||
var json = JsonConvert.SerializeObject(_guiDs, Newtonsoft.Json.Formatting.Indented);
|
var json = JsonConvert.SerializeObject(_guids, Newtonsoft.Json.Formatting.Indented);
|
||||||
|
|
||||||
using (var sw = new StreamWriter(filePath))
|
using (var sw = new StreamWriter(filePath))
|
||||||
{
|
{
|
||||||
@@ -312,17 +453,17 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
{
|
{
|
||||||
var json = File.ReadToEnd(filePath, Encoding.ASCII);
|
var json = File.ReadToEnd(filePath, Encoding.ASCII);
|
||||||
|
|
||||||
_guiDs = JsonConvert.DeserializeObject<FusionRoomGuids>(json);
|
_guids = JsonConvert.DeserializeObject<FusionRoomGuids>(json);
|
||||||
|
|
||||||
_ipId = _guiDs.IpId;
|
// _config.IpId = _guids.IpId;
|
||||||
|
|
||||||
FusionStaticAssets = _guiDs.StaticAssets;
|
FusionStaticAssets = _guids.StaticAssets;
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Fusion Guids successfully read from file: {0}",
|
Debug.LogMessage(LogEventLevel.Information, this, "Fusion Guids successfully read from file: {0}",
|
||||||
filePath);
|
filePath);
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, this, "\r\n********************\r\n\tRoom Name: {0}\r\n\tIPID: {1:X}\r\n\tRoomGuid: {2}\r\n*******************", Room.Name, _ipId, RoomGuid);
|
Debug.LogMessage(LogEventLevel.Debug, this, "\r\n********************\r\n\tRoom Name: {0}\r\n\tIPID: {1:X}\r\n\tRoomGuid: {2}\r\n*******************", Room.Name, _config.IpIdInt, RoomGuid);
|
||||||
|
|
||||||
foreach (var item in FusionStaticAssets)
|
foreach (var item in FusionStaticAssets)
|
||||||
{
|
{
|
||||||
@@ -343,6 +484,10 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CreateSymbolAndBasicSigs method
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ipId"></param>
|
||||||
protected virtual void CreateSymbolAndBasicSigs(uint ipId)
|
protected virtual void CreateSymbolAndBasicSigs(uint ipId)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId);
|
Debug.LogMessage(LogEventLevel.Information, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId);
|
||||||
@@ -405,6 +550,10 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
|
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CrestronEnvironment_EthernetEventHandler method
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ethernetEventArgs"></param>
|
||||||
protected void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs)
|
protected void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs)
|
||||||
{
|
{
|
||||||
if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp)
|
if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp)
|
||||||
@@ -413,6 +562,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GetSystemInfo method
|
||||||
|
/// </summary>
|
||||||
protected void GetSystemInfo()
|
protected void GetSystemInfo()
|
||||||
{
|
{
|
||||||
//SystemName.InputSig.StringValue = Room.Name;
|
//SystemName.InputSig.StringValue = Room.Name;
|
||||||
@@ -426,6 +578,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
() => CrestronConsole.SendControlSystemCommand("reboot", ref response));
|
() => CrestronConsole.SendControlSystemCommand("reboot", ref response));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SetUpEthernetValues method
|
||||||
|
/// </summary>
|
||||||
protected void SetUpEthernetValues()
|
protected void SetUpEthernetValues()
|
||||||
{
|
{
|
||||||
_ip1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp1.JoinNumber, JoinMap.ProcessorIp1.AttributeName, eSigIoMask.InputSigOnly);
|
_ip1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp1.JoinNumber, JoinMap.ProcessorIp1.AttributeName, eSigIoMask.InputSigOnly);
|
||||||
@@ -441,6 +596,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
_netMask2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask2.JoinNumber, JoinMap.ProcessorNetMask2.AttributeName, eSigIoMask.InputSigOnly);
|
_netMask2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask2.JoinNumber, JoinMap.ProcessorNetMask2.AttributeName, eSigIoMask.InputSigOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GetProcessorEthernetValues method
|
||||||
|
/// </summary>
|
||||||
protected void GetProcessorEthernetValues()
|
protected void GetProcessorEthernetValues()
|
||||||
{
|
{
|
||||||
_ip1.InputSig.StringValue =
|
_ip1.InputSig.StringValue =
|
||||||
@@ -475,7 +633,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
// Interface 1
|
// Interface 1
|
||||||
|
|
||||||
if (InitialParametersClass.NumberOfEthernetInterfaces > 1)
|
if (InitialParametersClass.NumberOfEthernetInterfaces > 1)
|
||||||
// Only get these values if the processor has more than 1 NIC
|
// Only get these values if the processor has more than 1 NIC
|
||||||
{
|
{
|
||||||
_ip2.InputSig.StringValue =
|
_ip2.InputSig.StringValue =
|
||||||
CrestronEthernetHelper.GetEthernetParameter(
|
CrestronEthernetHelper.GetEthernetParameter(
|
||||||
@@ -489,6 +647,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GetProcessorInfo method
|
||||||
|
/// </summary>
|
||||||
protected void GetProcessorInfo()
|
protected void GetProcessorInfo()
|
||||||
{
|
{
|
||||||
_firmware = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorFirmware.JoinNumber, JoinMap.ProcessorFirmware.AttributeName, eSigIoMask.InputSigOnly);
|
_firmware = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorFirmware.JoinNumber, JoinMap.ProcessorFirmware.AttributeName, eSigIoMask.InputSigOnly);
|
||||||
@@ -499,7 +660,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
{
|
{
|
||||||
var join = JoinMap.ProgramNameStart.JoinNumber + i;
|
var join = JoinMap.ProgramNameStart.JoinNumber + i;
|
||||||
var progNum = i + 1;
|
var progNum = i + 1;
|
||||||
_program[i] = FusionRoom.CreateOffsetStringSig((uint) join,
|
_program[i] = FusionRoom.CreateOffsetStringSig((uint)join,
|
||||||
string.Format("{0} {1}", JoinMap.ProgramNameStart.AttributeName, progNum), eSigIoMask.InputSigOnly);
|
string.Format("{0} {1}", JoinMap.ProgramNameStart.AttributeName, progNum), eSigIoMask.InputSigOnly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -507,6 +668,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
_firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion;
|
_firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// GetCustomProperties method
|
||||||
|
/// </summary>
|
||||||
protected void GetCustomProperties()
|
protected void GetCustomProperties()
|
||||||
{
|
{
|
||||||
if (FusionRoom.IsOnline)
|
if (FusionRoom.IsOnline)
|
||||||
@@ -524,11 +688,16 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
// TODO: Get IP and Project Name from TP
|
// TODO: Get IP and Project Name from TP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// FusionRoom_OnlineStatusChange method
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="currentDevice"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
protected void FusionRoom_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args)
|
protected void FusionRoom_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.DeviceOnLine)
|
if (args.DeviceOnLine)
|
||||||
{
|
{
|
||||||
CrestronInvoke.BeginInvoke( (o) =>
|
CrestronInvoke.BeginInvoke((o) =>
|
||||||
{
|
{
|
||||||
CrestronEnvironment.Sleep(200);
|
CrestronEnvironment.Sleep(200);
|
||||||
|
|
||||||
@@ -676,7 +845,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
var extendTime = _currentMeeting.dtEnd - DateTime.Now;
|
var extendTime = _currentMeeting.dtEnd - DateTime.Now;
|
||||||
var extendMinutesRaw = extendTime.TotalMinutes;
|
var extendMinutesRaw = extendTime.TotalMinutes;
|
||||||
|
|
||||||
extendMinutes += (int) Math.Round(extendMinutesRaw);
|
extendMinutes += (int)Math.Round(extendMinutesRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -784,11 +953,11 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
var parameters = actionResponse["Parameters"];
|
var parameters = actionResponse["Parameters"];
|
||||||
|
|
||||||
foreach (var isRegistered in from XmlElement parameter in parameters
|
foreach (var isRegistered in from XmlElement parameter in parameters
|
||||||
where parameter.HasAttributes
|
where parameter.HasAttributes
|
||||||
select parameter.Attributes
|
select parameter.Attributes
|
||||||
into attributes
|
into attributes
|
||||||
where attributes["ID"].Value == "Registered"
|
where attributes["ID"].Value == "Registered"
|
||||||
select Int32.Parse(attributes["Value"].Value))
|
select Int32.Parse(attributes["Value"].Value))
|
||||||
{
|
{
|
||||||
switch (isRegistered)
|
switch (isRegistered)
|
||||||
{
|
{
|
||||||
@@ -845,9 +1014,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
Debug.LogMessage(LogEventLevel.Debug, this, "DateTime from Fusion Server: {0}", currentTime);
|
Debug.LogMessage(LogEventLevel.Debug, this, "DateTime from Fusion Server: {0}", currentTime);
|
||||||
|
|
||||||
// Parse time and date from response and insert values
|
// Parse time and date from response and insert values
|
||||||
CrestronEnvironment.SetTimeAndDate((ushort) currentTime.Hour, (ushort) currentTime.Minute,
|
CrestronEnvironment.SetTimeAndDate((ushort)currentTime.Hour, (ushort)currentTime.Minute,
|
||||||
(ushort) currentTime.Second, (ushort) currentTime.Month, (ushort) currentTime.Day,
|
(ushort)currentTime.Second, (ushort)currentTime.Month, (ushort)currentTime.Day,
|
||||||
(ushort) currentTime.Year);
|
(ushort)currentTime.Year);
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, this, "Processor time set to {0}", CrestronEnvironment.GetLocalTime());
|
Debug.LogMessage(LogEventLevel.Debug, this, "Processor time set to {0}", CrestronEnvironment.GetLocalTime());
|
||||||
}
|
}
|
||||||
@@ -1065,6 +1234,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SetUpSources method
|
||||||
|
/// </summary>
|
||||||
protected virtual void SetUpSources()
|
protected virtual void SetUpSources()
|
||||||
{
|
{
|
||||||
// Sources
|
// Sources
|
||||||
@@ -1074,10 +1246,10 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
// NEW PROCESS:
|
// NEW PROCESS:
|
||||||
// Make these lists and insert the fusion attributes by iterating these
|
// Make these lists and insert the fusion attributes by iterating these
|
||||||
var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls);
|
var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls);
|
||||||
uint i = 1;
|
uint i = 0;
|
||||||
foreach (var kvp in setTopBoxes)
|
foreach (var kvp in setTopBoxes)
|
||||||
{
|
{
|
||||||
TryAddRouteActionSigs(JoinMap.Display1SetTopBoxSourceStart.AttributeName + " " + i, JoinMap.Display1SetTopBoxSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice);
|
TryAddRouteActionSigs(JoinMap.Display1SetTopBoxSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1SetTopBoxSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice);
|
||||||
i++;
|
i++;
|
||||||
if (i > JoinMap.Display1SetTopBoxSourceStart.JoinSpan) // We only have five spots
|
if (i > JoinMap.Display1SetTopBoxSourceStart.JoinSpan) // We only have five spots
|
||||||
{
|
{
|
||||||
@@ -1086,10 +1258,10 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
|
|
||||||
var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls);
|
var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls);
|
||||||
i = 1;
|
i = 0;
|
||||||
foreach (var kvp in discPlayers)
|
foreach (var kvp in discPlayers)
|
||||||
{
|
{
|
||||||
TryAddRouteActionSigs(JoinMap.Display1DiscPlayerSourceStart.AttributeName + " " + i, JoinMap.Display1DiscPlayerSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice);
|
TryAddRouteActionSigs(JoinMap.Display1DiscPlayerSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1DiscPlayerSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice);
|
||||||
i++;
|
i++;
|
||||||
if (i > JoinMap.Display1DiscPlayerSourceStart.JoinSpan) // We only have five spots
|
if (i > JoinMap.Display1DiscPlayerSourceStart.JoinSpan) // We only have five spots
|
||||||
{
|
{
|
||||||
@@ -1098,10 +1270,10 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
|
|
||||||
var laptops = dict.Where(d => d.Value.SourceDevice is IRoutingSource);
|
var laptops = dict.Where(d => d.Value.SourceDevice is IRoutingSource);
|
||||||
i = 1;
|
i = 0;
|
||||||
foreach (var kvp in laptops)
|
foreach (var kvp in laptops)
|
||||||
{
|
{
|
||||||
TryAddRouteActionSigs(JoinMap.Display1LaptopSourceStart.AttributeName + " " + i, JoinMap.Display1LaptopSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice);
|
TryAddRouteActionSigs(JoinMap.Display1LaptopSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1LaptopSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice);
|
||||||
i++;
|
i++;
|
||||||
if (i > JoinMap.Display1LaptopSourceStart.JoinSpan) // We only have ten spots???
|
if (i > JoinMap.Display1LaptopSourceStart.JoinSpan) // We only have ten spots???
|
||||||
{
|
{
|
||||||
@@ -1111,7 +1283,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
foreach (var usageDevice in dict.Select(kvp => kvp.Value.SourceDevice).OfType<IUsageTracking>())
|
foreach (var usageDevice in dict.Select(kvp => kvp.Value.SourceDevice).OfType<IUsageTracking>())
|
||||||
{
|
{
|
||||||
usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) {UsageIsTracked = true};
|
usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) { UsageIsTracked = true };
|
||||||
usageDevice.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
|
usageDevice.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1157,17 +1329,31 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
Debug.LogMessage(LogEventLevel.Debug, this, "Device usage string: {0}", deviceUsage);
|
Debug.LogMessage(LogEventLevel.Debug, this, "Device usage string: {0}", deviceUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to add route action sigs for a source
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="attrName"></param>
|
||||||
|
/// <param name="attrNum"></param>
|
||||||
|
/// <param name="routeKey"></param>
|
||||||
|
/// <param name="pSrc"></param>
|
||||||
protected void TryAddRouteActionSigs(string attrName, uint attrNum, string routeKey, Device pSrc)
|
protected void TryAddRouteActionSigs(string attrName, uint attrNum, string routeKey, Device pSrc)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Creating attribute '{0}' with join {1} for source {2}",
|
this.LogVerbose("Creating attribute '{0}' with join {1} for source {2}",
|
||||||
attrName, attrNum, pSrc.Key);
|
attrName, attrNum, pSrc.Key);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputOutputSig);
|
var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputOutputSig);
|
||||||
// Need feedback when this source is selected
|
// Need feedback when this source is selected
|
||||||
// Event handler, added below, will compare source changes with this sig dict
|
// Event handler, added below, will compare source changes with this sig dict
|
||||||
_sourceToFeedbackSigs.Add(pSrc, sigD.InputSig);
|
if (!_sourceToFeedbackSigs.ContainsKey(pSrc))
|
||||||
|
{
|
||||||
|
_sourceToFeedbackSigs.Add(pSrc, sigD.InputSig);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.LogWarning("Source '{0}' already has a feedback sig mapped. Overwriting.", pSrc.Key);
|
||||||
|
_sourceToFeedbackSigs[pSrc] = sigD.InputSig;
|
||||||
|
}
|
||||||
|
|
||||||
// And respond to selection in Fusion
|
// And respond to selection in Fusion
|
||||||
sigD.OutputSig.SetSigFalseAction(() =>
|
sigD.OutputSig.SetSigFalseAction(() =>
|
||||||
@@ -1180,14 +1366,12 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING",
|
this.LogVerbose("Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING",
|
||||||
attrNum, attrName, pSrc.Key);
|
attrNum, attrName, pSrc.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
private void SetUpCommunitcationMonitors()
|
private void SetUpCommunitcationMonitors()
|
||||||
{
|
{
|
||||||
uint displayNum = 0;
|
uint displayNum = 0;
|
||||||
@@ -1274,6 +1458,8 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
if (attrName != null)
|
if (attrName != null)
|
||||||
{
|
{
|
||||||
|
this.LogDebug("Linking communication monitor for device '{0}' to Fusion attribute '{1}' at join {2}",
|
||||||
|
dev.Key, attrName, attrNum);
|
||||||
// Link comm status to sig and update
|
// Link comm status to sig and update
|
||||||
var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly);
|
var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly);
|
||||||
var smd = dev as ICommunicationMonitor;
|
var smd = dev as ICommunicationMonitor;
|
||||||
@@ -1285,6 +1471,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SetUpDisplay method
|
||||||
|
/// </summary>
|
||||||
protected virtual void SetUpDisplay()
|
protected virtual void SetUpDisplay()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -1297,7 +1486,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
foreach (var display in displays.Cast<IDisplay>())
|
foreach (var display in displays.Cast<IDisplay>())
|
||||||
{
|
{
|
||||||
display.UsageTracker = new UsageTracking(display as Device) {UsageIsTracked = true};
|
display.UsageTracker = new UsageTracking(display as Device) { UsageIsTracked = true };
|
||||||
display.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
|
display.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1410,7 +1599,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
|
|
||||||
|
|
||||||
// Power on
|
// Power on
|
||||||
var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint) joinOffset, displayName + "Power On",
|
var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On",
|
||||||
eSigIoMask.InputOutputSig);
|
eSigIoMask.InputOutputSig);
|
||||||
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b =>
|
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b =>
|
||||||
{
|
{
|
||||||
@@ -1421,7 +1610,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Power Off
|
// Power Off
|
||||||
var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 1, displayName + "Power Off",
|
var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 1, displayName + "Power Off",
|
||||||
eSigIoMask.InputOutputSig);
|
eSigIoMask.InputOutputSig);
|
||||||
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b =>
|
defaultDisplayPowerOn.OutputSig.UserObject = new Action<bool>(b =>
|
||||||
{
|
{
|
||||||
@@ -1439,7 +1628,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Current Source
|
// Current Source
|
||||||
var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 8,
|
var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8,
|
||||||
displayName + "Source None", eSigIoMask.InputOutputSig);
|
displayName + "Source None", eSigIoMask.InputOutputSig);
|
||||||
defaultDisplaySourceNone.OutputSig.UserObject = new Action<bool>(b =>
|
defaultDisplaySourceNone.OutputSig.UserObject = new Action<bool>(b =>
|
||||||
{
|
{
|
||||||
@@ -1507,7 +1696,7 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
//if (Room.OccupancyObj != null)
|
//if (Room.OccupancyObj != null)
|
||||||
//{
|
//{
|
||||||
|
|
||||||
var tempOccAsset = _guiDs.OccupancyAsset;
|
var tempOccAsset = _guids.OccupancyAsset;
|
||||||
|
|
||||||
if (tempOccAsset == null)
|
if (tempOccAsset == null)
|
||||||
{
|
{
|
||||||
@@ -1588,12 +1777,74 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event handler for Fusion state changes
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args)
|
protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args)
|
||||||
{
|
{
|
||||||
|
if (args.EventId == FusionEventIds.HelpMessageReceivedEventId)
|
||||||
|
{
|
||||||
|
this.LogInformation("Help message received from Fusion for room '{0}'",
|
||||||
|
Room.Name);
|
||||||
|
|
||||||
|
this.LogDebug("Help message content: {0}", FusionRoom.Help.OutputSig.StringValue);
|
||||||
|
// Fire help request event
|
||||||
|
HelpRequestResponseFeedback.FireUpdate();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(FusionRoom.Help.OutputSig.StringValue))
|
||||||
|
{
|
||||||
|
switch (FusionRoom.Help.OutputSig.StringValue)
|
||||||
|
{
|
||||||
|
case "Please wait, a technician is on his / her way.":
|
||||||
|
// this.LogInformation("Please wait, a technician is on his / her way.",
|
||||||
|
// Room.Name);
|
||||||
|
|
||||||
|
_helpRequestStatus = eFusionHelpResponse.HelpOnTheWay;
|
||||||
|
break;
|
||||||
|
case "Please call the helpdesk.":
|
||||||
|
// this.LogInformation("Please call the helpdesk.");
|
||||||
|
// _helpRequestStatus = eFusionHelpResponse.CallHelpDesk;
|
||||||
|
break;
|
||||||
|
case "Please wait, I will reschedule your meeting to a different room.":
|
||||||
|
// this.LogInformation("Please wait, I will reschedule your meeting to a different room.",
|
||||||
|
// Room.Name);
|
||||||
|
|
||||||
|
_helpRequestStatus = eFusionHelpResponse.ReschedulingMeeting;
|
||||||
|
break;
|
||||||
|
case "I will be taking control of your system. Please be patient while I adjust the settings.":
|
||||||
|
// this.LogInformation("I will be taking control of your system. Please be patient while I adjust the settings.",
|
||||||
|
// Room.Name);
|
||||||
|
|
||||||
|
_helpRequestStatus = eFusionHelpResponse.TakingControl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// this.LogInformation("Unknown help request code received from Fusion for room '{0}'",
|
||||||
|
// Room.Name);
|
||||||
|
|
||||||
|
_helpRequestStatus = eFusionHelpResponse.None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_helpRequestStatus = eFusionHelpResponse.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_helpRequestStatus == eFusionHelpResponse.None)
|
||||||
|
{
|
||||||
|
_helpRequestSent = false;
|
||||||
|
HelpRequestSentFeedback.FireUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
HelpRequestStatusFeedback.FireUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// The sig/UO method: Need separate handlers for fixed and user sigs, all flavors,
|
// The sig/UO method: Need separate handlers for fixed and user sigs, all flavors,
|
||||||
// even though they all contain sigs.
|
// even though they all contain sigs.
|
||||||
|
|
||||||
|
|
||||||
BoolOutputSig outSig;
|
BoolOutputSig outSig;
|
||||||
if (args.UserConfiguredSigDetail is BooleanSigDataFixedName sigData)
|
if (args.UserConfiguredSigDetail is BooleanSigDataFixedName sigData)
|
||||||
{
|
{
|
||||||
@@ -1632,9 +1883,69 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
(outSig.UserObject as Action<string>).Invoke(outSig.StringValue);
|
(outSig.UserObject as Action<string>).Invoke(outSig.StringValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void SendHelpRequest()
|
||||||
|
{
|
||||||
|
|
||||||
|
var now = DateTime.Now;
|
||||||
|
|
||||||
|
var breakString = _config.UseHtmlFormatForHelpRequests ? "<BR>" : "\r\n";
|
||||||
|
|
||||||
|
var date = now.ToString("MMMM dd, yyyy");
|
||||||
|
var time = now.ToString("hh:mm tt");
|
||||||
|
if (_config.Use24HourTimeFormat)
|
||||||
|
{
|
||||||
|
time = now.ToString("HH:mm");
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestString = $"HR00: {breakString} Assistance has been requested from room {Room.Name}{breakString}on {date} at {time}";
|
||||||
|
|
||||||
|
FusionRoom.Help.InputSig.StringValue = requestString;
|
||||||
|
|
||||||
|
this.LogInformation("Help request sent to Fusion from room '{0}'", Room.Name);
|
||||||
|
this.LogDebug("Help request content: {0}", FusionRoom.Help.InputSig.StringValue);
|
||||||
|
|
||||||
|
_helpRequestSent = true;
|
||||||
|
HelpRequestSentFeedback.FireUpdate();
|
||||||
|
|
||||||
|
_helpRequestStatus = eFusionHelpResponse.HelpRequested;
|
||||||
|
HelpRequestStatusFeedback.FireUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void CancelHelpRequest()
|
||||||
|
{
|
||||||
|
if (_helpRequestSent)
|
||||||
|
{
|
||||||
|
FusionRoom.Help.InputSig.StringValue = "";
|
||||||
|
_helpRequestSent = false;
|
||||||
|
HelpRequestSentFeedback.FireUpdate();
|
||||||
|
_helpRequestStatus = eFusionHelpResponse.None;
|
||||||
|
HelpRequestStatusFeedback.FireUpdate();
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, this, "Help request cancelled in Fusion for room '{0}'", Room.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ToggleHelpRequest()
|
||||||
|
{
|
||||||
|
if (_helpRequestSent)
|
||||||
|
{
|
||||||
|
CancelHelpRequest();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SendHelpRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extensions to enhance Fusion room, asset and signal creation.
|
||||||
|
/// </summary>
|
||||||
public static class FusionRoomExtensions
|
public static class FusionRoomExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1648,6 +1959,8 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask)
|
public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask)
|
||||||
{
|
{
|
||||||
|
Debug.LogDebug("Creating Offset Bool Sig: {0} at Join {1}", name, number);
|
||||||
|
|
||||||
if (number < 50)
|
if (number < 50)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("number", "Cannot be less than 50");
|
throw new ArgumentOutOfRangeException("number", "Cannot be less than 50");
|
||||||
@@ -1668,6 +1981,8 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask)
|
public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask)
|
||||||
{
|
{
|
||||||
|
Debug.LogDebug("Creating Offset UShort Sig: {0} at Join {1}", name, number);
|
||||||
|
|
||||||
if (number < 50)
|
if (number < 50)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("number", "Cannot be less than 50");
|
throw new ArgumentOutOfRangeException("number", "Cannot be less than 50");
|
||||||
@@ -1688,6 +2003,8 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask)
|
public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask)
|
||||||
{
|
{
|
||||||
|
Debug.LogDebug("Creating Offset String Sig: {0} at Join {1}", name, number);
|
||||||
|
|
||||||
if (number < 50)
|
if (number < 50)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("number", "Cannot be less than 50");
|
throw new ArgumentOutOfRangeException("number", "Cannot be less than 50");
|
||||||
@@ -1803,6 +2120,9 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RoomInformation
|
public class RoomInformation
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
public RoomInformation()
|
public RoomInformation()
|
||||||
{
|
{
|
||||||
FusionCustomProperties = new List<FusionCustomProperty>();
|
FusionCustomProperties = new List<FusionCustomProperty>();
|
||||||
@@ -1855,10 +2175,17 @@ namespace PepperDash.Essentials.Core.Fusion
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class FusionCustomProperty
|
public class FusionCustomProperty
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
public FusionCustomProperty()
|
public FusionCustomProperty()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor with id
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
public FusionCustomProperty(string id)
|
public FusionCustomProperty(string id)
|
||||||
{
|
{
|
||||||
ID = id;
|
ID = id;
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Essentials.Core;
|
||||||
|
using PepperDash.Essentials.Core.Fusion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Factory for creating IEssentialsRoomFusionController devices
|
||||||
|
/// </summary>
|
||||||
|
public class IEssentialsRoomFusionControllerFactory : EssentialsDeviceFactory<IEssentialsRoomFusionController>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
public IEssentialsRoomFusionControllerFactory()
|
||||||
|
{
|
||||||
|
TypeNames = new List<string>() { "fusionRoom" };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the device
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dc"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc)
|
||||||
|
{
|
||||||
|
Debug.LogDebug("Factory Attempting to create new IEssentialsRoomFusionController Device");
|
||||||
|
|
||||||
|
|
||||||
|
var properties = dc.Properties.ToObject<IEssentialsRoomFusionControllerPropertiesConfig>();
|
||||||
|
|
||||||
|
return new IEssentialsRoomFusionController(dc.Key, dc.Name, properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using PepperDash.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Config properties for an IEssentialsRoomFusionController device
|
||||||
|
/// </summary>
|
||||||
|
public class IEssentialsRoomFusionControllerPropertiesConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the IP ID of the Fusion Room Controller
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("ipId")]
|
||||||
|
public string IpId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the IP ID as a UInt16
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public uint IpIdInt
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// Try to parse the IpId string to UInt16 as hex
|
||||||
|
if (ushort.TryParse(IpId, System.Globalization.NumberStyles.HexNumber, null, out ushort result))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogWarning( "Failed to parse IpId '{0}' as UInt16", IpId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the join map key
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("joinMapKey")]
|
||||||
|
public string JoinMapKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the room key associated with this Fusion Room Controller
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("roomKey")]
|
||||||
|
public string RoomKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether to use HTML format for help requests
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("useHtmlFormatForHelpRequests")]
|
||||||
|
public bool UseHtmlFormatForHelpRequests { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether to use 24-hour time format
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("use24HourTimeFormat")]
|
||||||
|
public bool Use24HourTimeFormat { get; set; } = false;
|
||||||
|
}
|
||||||
44
src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs
Normal file
44
src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core.Fusion
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents Fusion Help Request functionality
|
||||||
|
/// </summary>
|
||||||
|
public interface IFusionHelpRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Feedback containing the response to a help request
|
||||||
|
/// </summary>
|
||||||
|
StringFeedback HelpRequestResponseFeedback { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether a help request has been sent
|
||||||
|
/// </summary>
|
||||||
|
BoolFeedback HelpRequestSentFeedback { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Feedback containing the current status of the help request
|
||||||
|
/// </summary>
|
||||||
|
StringFeedback HelpRequestStatusFeedback { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a help request
|
||||||
|
/// </summary>
|
||||||
|
void SendHelpRequest();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the current help request status
|
||||||
|
/// </summary>
|
||||||
|
void CancelHelpRequest();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggles between sending and cancelling a help request
|
||||||
|
/// </summary>
|
||||||
|
void ToggleHelpRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/PepperDash.Essentials.Core/Fusion/eFusionHelpResponse.cs
Normal file
37
src/PepperDash.Essentials.Core/Fusion/eFusionHelpResponse.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core.Fusion
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeration of possible Fusion Help Responses based on the standard responses from Fusion
|
||||||
|
/// </summary>
|
||||||
|
public enum eFusionHelpResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No help response
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
/// <summary>
|
||||||
|
/// Help has been requested
|
||||||
|
/// </summary>
|
||||||
|
HelpRequested,
|
||||||
|
/// <summary>
|
||||||
|
/// Help is on the way
|
||||||
|
/// </summary>
|
||||||
|
HelpOnTheWay,
|
||||||
|
/// <summary>
|
||||||
|
/// Please call the helpdesk.
|
||||||
|
/// </summary>
|
||||||
|
CallHelpDesk,
|
||||||
|
/// <summary>
|
||||||
|
/// Rescheduling meeting.
|
||||||
|
/// </summary>
|
||||||
|
ReschedulingMeeting,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Technician taking control.
|
||||||
|
/// </summary>
|
||||||
|
TakingControl,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -49,7 +49,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IRoomOccupancy Room { get; private set; }
|
public IRoomOccupancy Room { get; private set; }
|
||||||
|
|
||||||
private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom;
|
private Fusion.IEssentialsRoomFusionController FusionRoom;
|
||||||
|
|
||||||
public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) :
|
public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) :
|
||||||
base (config)
|
base (config)
|
||||||
@@ -74,7 +74,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
|
|
||||||
var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion";
|
var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion";
|
||||||
|
|
||||||
FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase;
|
FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Core.Fusion.IEssentialsRoomFusionController;
|
||||||
|
|
||||||
if (FusionRoom == null)
|
if (FusionRoom == null)
|
||||||
Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey);
|
Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey);
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ namespace PepperDash.Essentials.Core
|
|||||||
Debug.LogMessage(LogEventLevel.Information, this, "Timeout Minutes from Config is: {0}", timeoutMinutes);
|
Debug.LogMessage(LogEventLevel.Information, this, "Timeout Minutes from Config is: {0}", timeoutMinutes);
|
||||||
|
|
||||||
// If status provider is fusion, set flag to remote
|
// If status provider is fusion, set flag to remote
|
||||||
if (statusProvider is Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase)
|
if (statusProvider is Core.Fusion.IEssentialsRoomFusionController)
|
||||||
OccupancyStatusProviderIsRemote = true;
|
OccupancyStatusProviderIsRemote = true;
|
||||||
|
|
||||||
if(timeoutMinutes > 0)
|
if(timeoutMinutes > 0)
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace PepperDash.Essentials.Core.Routing
|
|||||||
/// <param name="inputPort">The currently selected input port on the destination device.</param>
|
/// <param name="inputPort">The currently selected input port on the destination device.</param>
|
||||||
private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort)
|
private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort)
|
||||||
{
|
{
|
||||||
// Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this,destination?.Key, inputPort?.Key);
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Updating destination {destination} with inputPort {inputPort}", this, destination?.Key, inputPort?.Key);
|
||||||
|
|
||||||
if(inputPort == null)
|
if(inputPort == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using PepperDash.Essentials.Core;
|
|
||||||
using Crestron.SimplSharpPro.DeviceSupport;
|
|
||||||
using PepperDash.Core;
|
|
||||||
using Crestron.SimplSharpPro.UI;
|
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using Crestron.SimplSharpPro;
|
using Crestron.SimplSharpPro;
|
||||||
|
using Crestron.SimplSharpPro.DeviceSupport;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Core.Logging;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core.UI
|
namespace PepperDash.Essentials.Core.UI
|
||||||
{
|
{
|
||||||
public abstract class TouchpanelBase: EssentialsDevice, IHasBasicTriListWithSmartObject
|
/// <summary>
|
||||||
|
/// Base class for Touchpanel devices
|
||||||
|
/// </summary>
|
||||||
|
public abstract class TouchpanelBase : EssentialsDevice, IHasBasicTriListWithSmartObject
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the configuration for the Crestron touchpanel.
|
||||||
|
/// </summary>
|
||||||
protected CrestronTouchpanelPropertiesConfig _config;
|
protected CrestronTouchpanelPropertiesConfig _config;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Panel
|
/// Gets or sets the Panel
|
||||||
@@ -28,11 +30,10 @@ namespace PepperDash.Essentials.Core.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">Essentials Device Key</param>
|
/// <param name="key">Essentials Device Key</param>
|
||||||
/// <param name="name">Essentials Device Name</param>
|
/// <param name="name">Essentials Device Name</param>
|
||||||
/// <param name="type">Touchpanel Type to build</param>
|
/// <param name="panel">Crestron Touchpanel Device</param>
|
||||||
/// <param name="config">Touchpanel Configuration</param>
|
/// <param name="config">Touchpanel Configuration</param>
|
||||||
/// <param name="id">IP-ID to use for touch panel</param>
|
|
||||||
protected TouchpanelBase(string key, string name, BasicTriListWithSmartObject panel, CrestronTouchpanelPropertiesConfig config)
|
protected TouchpanelBase(string key, string name, BasicTriListWithSmartObject panel, CrestronTouchpanelPropertiesConfig config)
|
||||||
:base(key, name)
|
: base(key, name)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (panel == null)
|
if (panel == null)
|
||||||
@@ -57,21 +58,19 @@ namespace PepperDash.Essentials.Core.UI
|
|||||||
|
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
||||||
AddPreActivationAction(() => {
|
AddPreActivationAction(() =>
|
||||||
if (Panel.Register() != eDeviceRegistrationUnRegistrationResponse.Success)
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason);
|
|
||||||
|
|
||||||
// Give up cleanly if SGD is not present.
|
// Give up cleanly if SGD is not present.
|
||||||
var sgdName = Global.FilePathPrefix + "sgd" + Global.DirectorySeparator + _config.SgdFile;
|
var sgdName = Global.FilePathPrefix + "sgd" + Global.DirectorySeparator + _config.SgdFile;
|
||||||
if (!File.Exists(sgdName))
|
if (!File.Exists(sgdName))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Smart object file '{0}' not present in User folder. Looking for embedded file", sgdName);
|
this.LogInformation("Smart object file '{0}' not present in User folder. Looking for embedded file", sgdName);
|
||||||
|
|
||||||
sgdName = Global.ApplicationDirectoryPathPrefix + Global.DirectorySeparator + "SGD" + Global.DirectorySeparator + _config.SgdFile;
|
sgdName = Global.ApplicationDirectoryPathPrefix + Global.DirectorySeparator + "SGD" + Global.DirectorySeparator + _config.SgdFile;
|
||||||
|
|
||||||
if (!File.Exists(sgdName))
|
if (!File.Exists(sgdName))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Unable to find SGD file '{0}' in User sgd or application SGD folder. Exiting touchpanel load.", sgdName);
|
this.LogWarning("Unable to find SGD file '{0}' in User sgd or application SGD folder. Exiting touchpanel load.", sgdName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,12 +81,11 @@ namespace PepperDash.Essentials.Core.UI
|
|||||||
AddPostActivationAction(() =>
|
AddPostActivationAction(() =>
|
||||||
{
|
{
|
||||||
// Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event
|
// Check for IEssentialsRoomCombiner in DeviceManager and if found, subscribe to its event
|
||||||
var roomCombiner = DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) as IEssentialsRoomCombiner;
|
|
||||||
|
|
||||||
if (roomCombiner != null)
|
if (DeviceManager.AllDevices.FirstOrDefault((d) => d is IEssentialsRoomCombiner) is IEssentialsRoomCombiner roomCombiner)
|
||||||
{
|
{
|
||||||
// Subscribe to the even
|
// Subscribe to the even
|
||||||
roomCombiner.RoomCombinationScenarioChanged += new EventHandler<EventArgs>(roomCombiner_RoomCombinationScenarioChanged);
|
roomCombiner.RoomCombinationScenarioChanged += new EventHandler<EventArgs>(RoomCombiner_RoomCombinationScenarioChanged);
|
||||||
|
|
||||||
// Connect to the initial roomKey
|
// Connect to the initial roomKey
|
||||||
if (roomCombiner.CurrentScenario != null)
|
if (roomCombiner.CurrentScenario != null)
|
||||||
@@ -106,6 +104,11 @@ namespace PepperDash.Essentials.Core.UI
|
|||||||
// No room combiner, use the default key
|
// No room combiner, use the default key
|
||||||
SetupPanelDrivers(_config.DefaultRoomKey);
|
SetupPanelDrivers(_config.DefaultRoomKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var panelRegistrationResponse = Panel.Register();
|
||||||
|
|
||||||
|
if (panelRegistrationResponse != eDeviceRegistrationUnRegistrationResponse.Success)
|
||||||
|
this.LogInformation("WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +118,6 @@ namespace PepperDash.Essentials.Core.UI
|
|||||||
/// <param name="roomKey">Room Key for this panel</param>
|
/// <param name="roomKey">Room Key for this panel</param>
|
||||||
protected abstract void SetupPanelDrivers(string roomKey);
|
protected abstract void SetupPanelDrivers(string roomKey);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event handler for System Extender Events
|
/// Event handler for System Extender Events
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -129,7 +131,7 @@ namespace PepperDash.Essentials.Core.UI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="sender"></param>
|
||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
protected virtual void roomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e)
|
protected virtual void RoomCombiner_RoomCombinationScenarioChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var roomCombiner = sender as IEssentialsRoomCombiner;
|
var roomCombiner = sender as IEssentialsRoomCombiner;
|
||||||
|
|
||||||
@@ -156,23 +158,23 @@ namespace PepperDash.Essentials.Core.UI
|
|||||||
SetupPanelDrivers(newRoomKey);
|
SetupPanelDrivers(newRoomKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Panel_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args)
|
private void Panel_SigChange(object currentDevice, SigEventArgs args)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Sig change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue);
|
this.LogVerbose("Sig change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue);
|
||||||
var uo = args.Sig.UserObject;
|
var uo = args.Sig.UserObject;
|
||||||
if (uo is Action<bool>)
|
if (uo is Action<bool>)
|
||||||
(uo as Action<bool>)(args.Sig.BoolValue);
|
(uo as Action<bool>)(args.Sig.BoolValue);
|
||||||
else if (uo is Action<ushort>)
|
else if (uo is Action<ushort>)
|
||||||
(uo as Action<ushort>)(args.Sig.UShortValue);
|
(uo as Action<ushort>)(args.Sig.UShortValue);
|
||||||
else if (uo is Action<string>)
|
else if (uo is Action<string>)
|
||||||
(uo as Action<string>)(args.Sig.StringValue);
|
(uo as Action<string>)(args.Sig.StringValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Tsw_ButtonStateChange(GenericBase device, ButtonEventArgs args)
|
private void Tsw_ButtonStateChange(GenericBase device, ButtonEventArgs args)
|
||||||
{
|
{
|
||||||
var uo = args.Button.UserObject;
|
var uo = args.Button.UserObject;
|
||||||
if(uo is Action<bool>)
|
if (uo is Action<bool>)
|
||||||
(uo as Action<bool>)(args.Button.State == eButtonState.Pressed);
|
(uo as Action<bool>)(args.Button.State == eButtonState.Pressed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,9 +6,9 @@ using PepperDash.Core.Web.RequestHandlers;
|
|||||||
|
|
||||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a SetDeviceStreamDebugRequestHandler
|
/// Represents a SetDeviceStreamDebugRequestHandler
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler
|
public class SetDeviceStreamDebugRequestHandler : WebApiBaseRequestHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -122,23 +122,23 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(DeviceManager.GetDeviceForKey(body.DeviceKey) is IStreamDebugging device))
|
if (!(DeviceManager.GetDeviceForKey(body.DeviceKey) is IStreamDebugging device))
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = 404;
|
context.Response.StatusCode = 404;
|
||||||
context.Response.StatusDescription = "Not Found";
|
context.Response.StatusDescription = "Not Found";
|
||||||
context.Response.End();
|
context.Response.End();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
eStreamDebuggingSetting debugSetting;
|
eStreamDebuggingSetting debugSetting;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
debugSetting = (eStreamDebuggingSetting) Enum.Parse(typeof (eStreamDebuggingSetting), body.Setting, true);
|
debugSetting = (eStreamDebuggingSetting)Enum.Parse(typeof(eStreamDebuggingSetting), body.Setting, true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(ex, "Exception handling set debug request");
|
Debug.LogMessage(ex, "Exception handling set debug request");
|
||||||
context.Response.StatusCode = 500;
|
context.Response.StatusCode = 500;
|
||||||
context.Response.StatusDescription = "Internal Server Error";
|
context.Response.StatusDescription = "Internal Server Error";
|
||||||
context.Response.End();
|
context.Response.End();
|
||||||
@@ -164,7 +164,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(ex, "Exception handling set debug request");
|
Debug.LogMessage(ex, "Exception handling set debug request");
|
||||||
context.Response.StatusCode = 500;
|
context.Response.StatusCode = 500;
|
||||||
context.Response.StatusDescription = "Internal Server Error";
|
context.Response.StatusDescription = "Internal Server Error";
|
||||||
context.Response.End();
|
context.Response.End();
|
||||||
@@ -198,21 +198,21 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
|||||||
public class SetDeviceStreamDebugConfig
|
public class SetDeviceStreamDebugConfig
|
||||||
{
|
{
|
||||||
[JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Include)]
|
[JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Include)]
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the DeviceKey
|
/// Gets or sets the DeviceKey
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DeviceKey { get; set; }
|
public string DeviceKey { get; set; }
|
||||||
|
|
||||||
[JsonProperty("setting", NullValueHandling = NullValueHandling.Include)]
|
[JsonProperty("setting", NullValueHandling = NullValueHandling.Include)]
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Setting
|
/// Gets or sets the Setting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Setting { get; set; }
|
public string Setting { get; set; }
|
||||||
|
|
||||||
[JsonProperty("timeout")]
|
[JsonProperty("timeout")]
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Timeout
|
/// Gets or sets the Timeout
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Timeout { get; set; }
|
public int Timeout { get; set; }
|
||||||
|
|
||||||
public SetDeviceStreamDebugConfig()
|
public SetDeviceStreamDebugConfig()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Core.Logging;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
using PepperDash.Essentials.Core.Config;
|
using PepperDash.Essentials.Core.Config;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
@@ -9,7 +10,7 @@ namespace PepperDash.Essentials.Devices.Common.Generic
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a GenericSink
|
/// Represents a GenericSink
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericSink : EssentialsDevice, IRoutingSinkWithInputPort
|
public class GenericSink : EssentialsDevice, IRoutingSinkWithSwitchingWithInputPort
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the GenericSink class
|
/// Initializes a new instance of the GenericSink class
|
||||||
@@ -20,7 +21,7 @@ namespace PepperDash.Essentials.Devices.Common.Generic
|
|||||||
{
|
{
|
||||||
InputPorts = new RoutingPortCollection<RoutingInputPort>();
|
InputPorts = new RoutingPortCollection<RoutingInputPort>();
|
||||||
|
|
||||||
var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo, eRoutingPortConnectionType.Hdmi, null, this);
|
var inputPort = new RoutingInputPort(RoutingPortNames.AnyVideoIn, eRoutingSignalType.AudioVideo | eRoutingSignalType.SecondaryAudio, eRoutingPortConnectionType.Hdmi, null, this);
|
||||||
|
|
||||||
InputPorts.Add(inputPort);
|
InputPorts.Add(inputPort);
|
||||||
}
|
}
|
||||||
@@ -66,6 +67,15 @@ namespace PepperDash.Essentials.Devices.Common.Generic
|
|||||||
/// Event fired when the current source changes
|
/// Event fired when the current source changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
public event SourceInfoChangeHandler CurrentSourceChange;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event InputChangedEventHandler InputChanged;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ExecuteSwitch(object inputSelector)
|
||||||
|
{
|
||||||
|
this.LogDebug("GenericSink Executing Switch to: {inputSelector}", inputSelector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -31,7 +31,12 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Unsoliciited feedback from a device in a messenger will ONLY be sent to devices in this subscription list. When a client disconnects, it's ID will be removed from the collection.
|
/// Unsoliciited feedback from a device in a messenger will ONLY be sent to devices in this subscription list. When a client disconnects, it's ID will be removed from the collection.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
protected HashSet<string> SubscriberIds = new HashSet<string>();
|
private readonly HashSet<string> subscriberIds = new HashSet<string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lock object for thread-safe access to SubscriberIds
|
||||||
|
/// </summary>
|
||||||
|
private readonly object _subscriberLock = new object();
|
||||||
|
|
||||||
private readonly List<string> _deviceInterfaces;
|
private readonly List<string> _deviceInterfaces;
|
||||||
|
|
||||||
@@ -189,18 +194,18 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
|||||||
{
|
{
|
||||||
if (!enableMessengerSubscriptions)
|
if (!enableMessengerSubscriptions)
|
||||||
{
|
{
|
||||||
this.LogWarning("Messenger subscriptions not enabled");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SubscriberIds.Any(id => id == clientId))
|
lock (_subscriberLock)
|
||||||
{
|
{
|
||||||
this.LogVerbose("Client {clientId} already subscribed", clientId);
|
if (!subscriberIds.Add(clientId))
|
||||||
return;
|
{
|
||||||
|
this.LogVerbose("Client {clientId} already subscribed", clientId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SubscriberIds.Add(clientId);
|
|
||||||
|
|
||||||
this.LogDebug("Client {clientId} subscribed", clientId);
|
this.LogDebug("Client {clientId} subscribed", clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,19 +217,26 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
|||||||
{
|
{
|
||||||
if (!enableMessengerSubscriptions)
|
if (!enableMessengerSubscriptions)
|
||||||
{
|
{
|
||||||
this.LogWarning("Messenger subscriptions not enabled");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SubscriberIds.Any(i => i == clientId))
|
bool wasSubscribed;
|
||||||
|
lock (_subscriberLock)
|
||||||
|
{
|
||||||
|
wasSubscribed = subscriberIds.Contains(clientId);
|
||||||
|
if (wasSubscribed)
|
||||||
|
{
|
||||||
|
subscriberIds.Remove(clientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wasSubscribed)
|
||||||
{
|
{
|
||||||
this.LogVerbose("Client with ID {clientId} is not subscribed", clientId);
|
this.LogVerbose("Client with ID {clientId} is not subscribed", clientId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SubscriberIds.RemoveWhere((i) => i == clientId);
|
this.LogDebug("Client with ID {clientId} unsubscribed", clientId);
|
||||||
|
|
||||||
this.LogInformation("Client with ID {clientId} unsubscribed", clientId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -258,7 +270,8 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
this.LogError(ex, "Exception posting status message for {messagePath} to {clientId}", MessagePath, clientId ?? "all clients");
|
this.LogError("Exception posting status message for {messagePath} to {clientId}: {message}", MessagePath, clientId ?? "all clients", ex.Message);
|
||||||
|
this.LogDebug(ex, "Stack trace: ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +300,8 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
this.LogError(ex, "Exception posting status message for {type} to {clientId}", type, clientId ?? "all clients");
|
this.LogError("Exception posting status message for {type} to {clientId}: {message}", type, clientId ?? "all clients", ex.Message);
|
||||||
|
this.LogDebug(ex, "Stack trace: ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,7 +326,14 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
|||||||
// If client is null or empty, this message is unsolicited feedback. Iterate through the subscriber list and send to all interested parties
|
// If client is null or empty, this message is unsolicited feedback. Iterate through the subscriber list and send to all interested parties
|
||||||
if (string.IsNullOrEmpty(clientId))
|
if (string.IsNullOrEmpty(clientId))
|
||||||
{
|
{
|
||||||
foreach (var client in SubscriberIds)
|
// Create a snapshot of subscribers to avoid collection modification during iteration
|
||||||
|
List<string> subscriberSnapshot;
|
||||||
|
lock (_subscriberLock)
|
||||||
|
{
|
||||||
|
subscriberSnapshot = new List<string>(subscriberIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var client in subscriberSnapshot)
|
||||||
{
|
{
|
||||||
AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = client, Content = content });
|
AppServerController?.SendMessageObject(new MobileControlMessage { Type = !string.IsNullOrEmpty(type) ? type : MessagePath, ClientId = client, Content = content });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,15 @@ using System;
|
|||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a ClientSpecificUpdateRequest
|
/// Send an update request for a specific client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete]
|
||||||
public class ClientSpecificUpdateRequest
|
public class ClientSpecificUpdateRequest
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize an instance of the <see cref="ClientSpecificUpdateRequest"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action"></param>
|
||||||
public ClientSpecificUpdateRequest(Action<string> action)
|
public ClientSpecificUpdateRequest(Action<string> action)
|
||||||
{
|
{
|
||||||
ResponseMethod = action;
|
ResponseMethod = action;
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDelayedConfiguration
|
public interface IDelayedConfiguration
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event triggered when the configuration is ready. Used when Mobile Control is interacting with a SIMPL program.
|
||||||
|
/// </summary>
|
||||||
event EventHandler<EventArgs> ConfigurationIsReady;
|
event EventHandler<EventArgs> ConfigurationIsReady;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
90
src/PepperDash.Essentials.MobileControl/MessageToClients.cs
Normal file
90
src/PepperDash.Essentials.MobileControl/MessageToClients.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Core.Logging;
|
||||||
|
using PepperDash.Essentials.AppServer.Messengers;
|
||||||
|
using PepperDash.Essentials.Core.Queues;
|
||||||
|
using PepperDash.Essentials.WebSocketServer;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a MessageToClients
|
||||||
|
/// </summary>
|
||||||
|
public class MessageToClients : IQueueMessage
|
||||||
|
{
|
||||||
|
private readonly MobileControlWebsocketServer _server;
|
||||||
|
private readonly object msgToSend;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message to send to Direct Server Clients
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msg">message object to send</param>
|
||||||
|
/// <param name="server">WebSocket server instance</param>
|
||||||
|
public MessageToClients(object msg, MobileControlWebsocketServer server)
|
||||||
|
{
|
||||||
|
_server = server;
|
||||||
|
msgToSend = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message to send to Direct Server Clients
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msg">message object to send</param>
|
||||||
|
/// <param name="server">WebSocket server instance</param>
|
||||||
|
public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server)
|
||||||
|
{
|
||||||
|
_server = server;
|
||||||
|
msgToSend = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Implementation of IQueueMessage
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispatch method
|
||||||
|
/// </summary>
|
||||||
|
public void Dispatch()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_server == null)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
|
||||||
|
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
|
||||||
|
|
||||||
|
var clientSpecificMessage = msgToSend as MobileControlMessage;
|
||||||
|
if (clientSpecificMessage.ClientId != null)
|
||||||
|
{
|
||||||
|
var clientId = clientSpecificMessage.ClientId;
|
||||||
|
|
||||||
|
_server.LogVerbose("Message TX To client {clientId}: {message}", clientId, message);
|
||||||
|
|
||||||
|
_server.SendMessageToClient(clientId, message);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_server.SendMessageToAllClients(message);
|
||||||
|
|
||||||
|
_server.LogVerbose("Message TX To all clients: {message}", message);
|
||||||
|
}
|
||||||
|
catch (ThreadAbortException)
|
||||||
|
{
|
||||||
|
//Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(ex, "Caught an exception in the Transmit Processor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
using System;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
@@ -10,12 +10,20 @@ namespace PepperDash.Essentials
|
|||||||
public class MobileControlAction : IMobileControlAction
|
public class MobileControlAction : IMobileControlAction
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Messenger
|
/// Gets the Messenger
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IMobileControlMessenger Messenger { get; private set; }
|
public IMobileControlMessenger Messenger { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Action to execute when this path is matched
|
||||||
|
/// </summary>
|
||||||
public Action<string, string, JToken> Action { get; private set; }
|
public Action<string, string, JToken> Action { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize an instance of the <see cref="MobileControlAction"/> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="messenger">Messenger associated with this action</param>
|
||||||
|
/// <param name="handler">Action to take when this path is matched</param>
|
||||||
public MobileControlAction(IMobileControlMessenger messenger, Action<string, string, JToken> handler)
|
public MobileControlAction(IMobileControlMessenger messenger, Action<string, string, JToken> handler)
|
||||||
{
|
{
|
||||||
Messenger = messenger;
|
Messenger = messenger;
|
||||||
|
|||||||
@@ -1,28 +1,25 @@
|
|||||||
using PepperDash.Core;
|
using System;
|
||||||
using PepperDash.Core.Logging;
|
using System.Collections.Generic;
|
||||||
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
using PepperDash.Essentials.Core.Config;
|
using PepperDash.Essentials.Core.Config;
|
||||||
using Serilog.Events;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a MobileControlDeviceFactory
|
/// Factory to create a Mobile Control System Controller
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MobileControlDeviceFactory : EssentialsDeviceFactory<MobileControlSystemController>
|
public class MobileControlDeviceFactory : EssentialsDeviceFactory<MobileControlSystemController>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create the factory for a Mobile Control System Controller
|
||||||
|
/// </summary>
|
||||||
public MobileControlDeviceFactory()
|
public MobileControlDeviceFactory()
|
||||||
{
|
{
|
||||||
TypeNames = new List<string> { "appserver", "mobilecontrol", "webserver" };
|
TypeNames = new List<string> { "appserver", "mobilecontrol", "webserver" };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// BuildDevice method
|
|
||||||
/// </summary>
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,29 +6,35 @@ using PepperDash.Essentials.Core.Config;
|
|||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a MobileControlEssentialsConfig
|
/// Configuration class for sending data to Mobile Control Edge or a client using the Direct Server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MobileControlEssentialsConfig : EssentialsConfig
|
public class MobileControlEssentialsConfig : EssentialsConfig
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Current versions for the system
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("runtimeInfo")]
|
[JsonProperty("runtimeInfo")]
|
||||||
public MobileControlRuntimeInfo RuntimeInfo { get; set; }
|
public MobileControlRuntimeInfo RuntimeInfo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create Configuration for Mobile Control. Used as part of the data sent to a client
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config">The base configuration</param>
|
||||||
public MobileControlEssentialsConfig(EssentialsConfig config)
|
public MobileControlEssentialsConfig(EssentialsConfig config)
|
||||||
: base()
|
: base()
|
||||||
{
|
{
|
||||||
// TODO: Consider using Reflection to iterate properties
|
Devices = config.Devices;
|
||||||
this.Devices = config.Devices;
|
Info = config.Info;
|
||||||
this.Info = config.Info;
|
JoinMaps = config.JoinMaps;
|
||||||
this.JoinMaps = config.JoinMaps;
|
Rooms = config.Rooms;
|
||||||
this.Rooms = config.Rooms;
|
SourceLists = config.SourceLists;
|
||||||
this.SourceLists = config.SourceLists;
|
DestinationLists = config.DestinationLists;
|
||||||
this.DestinationLists = config.DestinationLists;
|
SystemUrl = config.SystemUrl;
|
||||||
this.SystemUrl = config.SystemUrl;
|
TemplateUrl = config.TemplateUrl;
|
||||||
this.TemplateUrl = config.TemplateUrl;
|
TieLines = config.TieLines;
|
||||||
this.TieLines = config.TieLines;
|
|
||||||
|
|
||||||
if (this.Info == null)
|
if (Info == null)
|
||||||
this.Info = new InfoConfig();
|
Info = new InfoConfig();
|
||||||
|
|
||||||
RuntimeInfo = new MobileControlRuntimeInfo();
|
RuntimeInfo = new MobileControlRuntimeInfo();
|
||||||
}
|
}
|
||||||
@@ -46,15 +52,21 @@ namespace PepperDash.Essentials
|
|||||||
[JsonProperty("pluginVersion")]
|
[JsonProperty("pluginVersion")]
|
||||||
public string PluginVersion { get; set; }
|
public string PluginVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Essentials Version
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("essentialsVersion")]
|
[JsonProperty("essentialsVersion")]
|
||||||
public string EssentialsVersion { get; set; }
|
public string EssentialsVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// PepperDash Core Version
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("pepperDashCoreVersion")]
|
[JsonProperty("pepperDashCoreVersion")]
|
||||||
public string PepperDashCoreVersion { get; set; }
|
public string PepperDashCoreVersion { get; set; }
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the EssentialsPlugins
|
/// List of Plugins loaded on this system
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("essentialsPlugins")]
|
[JsonProperty("essentialsPlugins")]
|
||||||
public List<LoadedAssembly> EssentialsPlugins { get; set; }
|
public List<LoadedAssembly> EssentialsPlugins { get; set; }
|
||||||
|
|||||||
@@ -7,10 +7,13 @@ using PepperDash.Essentials.Core;
|
|||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a MobileControlFactory
|
/// Factory class for the Mobile Control App Controller
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MobileControlFactory
|
public class MobileControlFactory
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileControlFactory"/> class.
|
||||||
|
/// </summary>
|
||||||
public MobileControlFactory()
|
public MobileControlFactory()
|
||||||
{
|
{
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
|||||||
@@ -91,10 +91,16 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public MobileControlApiService ApiService { get; private set; }
|
public MobileControlApiService ApiService { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Room Bridges associated with this controller
|
||||||
|
/// </summary>
|
||||||
public List<MobileControlBridgeBase> RoomBridges => _roomBridges;
|
public List<MobileControlBridgeBase> RoomBridges => _roomBridges;
|
||||||
|
|
||||||
private readonly MobileControlWebsocketServer _directServer;
|
private readonly MobileControlWebsocketServer _directServer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the Direct Server instance associated with this controller
|
||||||
|
/// </summary>
|
||||||
public MobileControlWebsocketServer DirectServer => _directServer;
|
public MobileControlWebsocketServer DirectServer => _directServer;
|
||||||
|
|
||||||
private readonly CCriticalSection _wsCriticalSection = new CCriticalSection();
|
private readonly CCriticalSection _wsCriticalSection = new CCriticalSection();
|
||||||
@@ -104,10 +110,16 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string SystemUrl; //set only from SIMPL Bridge!
|
public string SystemUrl; //set only from SIMPL Bridge!
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if the Mobile Control Edge Server Websocket is connected
|
||||||
|
/// </summary>
|
||||||
public bool Connected => _wsClient2 != null && _wsClient2.IsAlive;
|
public bool Connected => _wsClient2 != null && _wsClient2.IsAlive;
|
||||||
|
|
||||||
private IEssentialsRoomCombiner _roomCombiner;
|
private IEssentialsRoomCombiner _roomCombiner;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the SystemUuid from configuration or SIMPL Bridge
|
||||||
|
/// </summary>
|
||||||
public string SystemUuid
|
public string SystemUuid
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -169,6 +181,9 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
private DateTime _lastAckMessage;
|
private DateTime _lastAckMessage;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the LastAckMessage timestamp
|
||||||
|
/// </summary>
|
||||||
public DateTime LastAckMessage => _lastAckMessage;
|
public DateTime LastAckMessage => _lastAckMessage;
|
||||||
|
|
||||||
private CTimer _pingTimer;
|
private CTimer _pingTimer;
|
||||||
@@ -177,11 +192,11 @@ namespace PepperDash.Essentials
|
|||||||
private LogLevel _wsLogLevel = LogLevel.Error;
|
private LogLevel _wsLogLevel = LogLevel.Error;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Initializes a new instance of the <see cref="MobileControlSystemController"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key"></param>
|
/// <param name="key">The unique key for this controller.</param>
|
||||||
/// <param name="name"></param>
|
/// <param name="name">The name of the controller.</param>
|
||||||
/// <param name="config"></param>
|
/// <param name="config">The configuration settings for the controller.</param>
|
||||||
public MobileControlSystemController(string key, string name, MobileControlConfig config)
|
public MobileControlSystemController(string key, string name, MobileControlConfig config)
|
||||||
: base(key, name)
|
: base(key, name)
|
||||||
{
|
{
|
||||||
@@ -1192,6 +1207,9 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Host { get; private set; }
|
public string Host { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the configured Client App URL
|
||||||
|
/// </summary>
|
||||||
public string ClientAppUrl => Config.ClientAppUrl;
|
public string ClientAppUrl => Config.ClientAppUrl;
|
||||||
|
|
||||||
private void OnRoomCombinationScenarioChanged(
|
private void OnRoomCombinationScenarioChanged(
|
||||||
@@ -1203,7 +1221,7 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CheckForDeviceMessenger method
|
/// Checks if a device messenger exists for the given key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CheckForDeviceMessenger(string key)
|
public bool CheckForDeviceMessenger(string key)
|
||||||
{
|
{
|
||||||
@@ -1211,13 +1229,13 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AddDeviceMessenger method
|
/// Add the provided messenger to the messengers collection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void AddDeviceMessenger(IMobileControlMessenger messenger)
|
public void AddDeviceMessenger(IMobileControlMessenger messenger)
|
||||||
{
|
{
|
||||||
if (_messengers.ContainsKey(messenger.Key))
|
if (_messengers.ContainsKey(messenger.Key))
|
||||||
{
|
{
|
||||||
this.LogWarning("Messenger with key {messengerKey) already added", messenger.Key);
|
this.LogWarning("Messenger with key {messengerKey} already added", messenger.Key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1291,12 +1309,14 @@ namespace PepperDash.Essentials
|
|||||||
messenger.RegisterWithAppServer(this);
|
messenger.RegisterWithAppServer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize method
|
|
||||||
/// </summary>
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
if (!Config.EnableMessengerSubscriptions)
|
||||||
|
{
|
||||||
|
this.LogWarning("Messenger subscriptions disabled. add \"enableMessengerSubscriptions\": true to config for {key} to enable.", Key);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var messenger in _messengers)
|
foreach (var messenger in _messengers)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -1338,7 +1358,7 @@ namespace PepperDash.Essentials
|
|||||||
#region IMobileControl Members
|
#region IMobileControl Members
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GetAppServer method
|
/// Gets the App Server instance
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IMobileControl GetAppServer()
|
public static IMobileControl GetAppServer()
|
||||||
{
|
{
|
||||||
@@ -1356,16 +1376,10 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates the url and creates the websocket client
|
|
||||||
/// </summary>
|
|
||||||
private bool CreateWebsocket()
|
private bool CreateWebsocket()
|
||||||
{
|
{
|
||||||
if (_wsClient2 != null)
|
_wsClient2?.Close();
|
||||||
{
|
_wsClient2 = null;
|
||||||
_wsClient2.Close();
|
|
||||||
_wsClient2 = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(SystemUuid))
|
if (string.IsNullOrEmpty(SystemUuid))
|
||||||
{
|
{
|
||||||
@@ -1382,33 +1396,13 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
Log =
|
Log =
|
||||||
{
|
{
|
||||||
Output = (data, message) =>
|
Output = (data, message) => Utilities.ConvertWebsocketLog(data, message, this)
|
||||||
{
|
|
||||||
switch (data.Level)
|
|
||||||
{
|
|
||||||
case LogLevel.Trace:
|
|
||||||
this.LogVerbose(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Debug:
|
|
||||||
this.LogDebug(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Info:
|
|
||||||
this.LogInformation(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Warn:
|
|
||||||
this.LogWarning(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Error:
|
|
||||||
this.LogError(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Fatal:
|
|
||||||
this.LogFatal(data.Message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// setting to trace to let level be controlled by appdebug
|
||||||
|
_wsClient2.Log.Level = LogLevel.Trace;
|
||||||
|
|
||||||
_wsClient2.SslConfiguration.EnabledSslProtocols =
|
_wsClient2.SslConfiguration.EnabledSslProtocols =
|
||||||
System.Security.Authentication.SslProtocols.Tls11
|
System.Security.Authentication.SslProtocols.Tls11
|
||||||
| System.Security.Authentication.SslProtocols.Tls12;
|
| System.Security.Authentication.SslProtocols.Tls12;
|
||||||
@@ -1422,7 +1416,7 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// LinkSystemMonitorToAppServer method
|
/// Link the System Monitor to this App server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void LinkSystemMonitorToAppServer()
|
public void LinkSystemMonitorToAppServer()
|
||||||
{
|
{
|
||||||
@@ -1449,14 +1443,6 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
private void SetWebsocketDebugLevel(string cmdparameters)
|
private void SetWebsocketDebugLevel(string cmdparameters)
|
||||||
{
|
{
|
||||||
// if (CrestronEnvironment.ProgramCompatibility == eCrestronSeries.Series4)
|
|
||||||
// {
|
|
||||||
// this.LogInformation(
|
|
||||||
// "Setting websocket log level not currently allowed on 4 series."
|
|
||||||
// );
|
|
||||||
// return; // Web socket log level not currently allowed in series4
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(cmdparameters))
|
if (string.IsNullOrEmpty(cmdparameters))
|
||||||
{
|
{
|
||||||
this.LogInformation("Current Websocket debug level: {webSocketDebugLevel}", _wsLogLevel);
|
this.LogInformation("Current Websocket debug level: {webSocketDebugLevel}", _wsLogLevel);
|
||||||
@@ -1494,10 +1480,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sends message to server to indicate the system is shutting down
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="programEventType"></param>
|
|
||||||
private void CrestronEnvironment_ProgramStatusEventHandler(
|
private void CrestronEnvironment_ProgramStatusEventHandler(
|
||||||
eProgramStatusEventType programEventType
|
eProgramStatusEventType programEventType
|
||||||
)
|
)
|
||||||
@@ -1530,6 +1512,9 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get action paths for the current actions
|
||||||
|
/// </summary>
|
||||||
public List<(string, string)> GetActionDictionaryPaths()
|
public List<(string, string)> GetActionDictionaryPaths()
|
||||||
{
|
{
|
||||||
var paths = new List<(string, string)>();
|
var paths = new List<(string, string)>();
|
||||||
@@ -1602,24 +1587,24 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the room bridge with the provided key
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key of the room bridge</param>
|
||||||
public MobileControlBridgeBase GetRoomBridge(string key)
|
public MobileControlBridgeBase GetRoomBridge(string key)
|
||||||
{
|
{
|
||||||
return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key));
|
return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GetRoomMessenger method
|
/// Get the room messenger with the provided key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="key">The Key of the rooom messenger</param>
|
||||||
public IMobileControlRoomMessenger GetRoomMessenger(string key)
|
public IMobileControlRoomMessenger GetRoomMessenger(string key)
|
||||||
{
|
{
|
||||||
return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key));
|
return _roomBridges.FirstOrDefault((r) => r.RoomKey.Equals(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
private void Bridge_ConfigurationIsReady(object sender, EventArgs e)
|
private void Bridge_ConfigurationIsReady(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
this.LogDebug("Bridge ready. Registering");
|
this.LogDebug("Bridge ready. Registering");
|
||||||
@@ -1640,10 +1625,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="o"></param>
|
|
||||||
private void ReconnectToServerTimerCallback(object o)
|
private void ReconnectToServerTimerCallback(object o)
|
||||||
{
|
{
|
||||||
this.LogDebug("Attempting to reconnect to server...");
|
this.LogDebug("Attempting to reconnect to server...");
|
||||||
@@ -1651,9 +1632,6 @@ namespace PepperDash.Essentials
|
|||||||
ConnectWebsocketClient();
|
ConnectWebsocketClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Verifies system connection with servers
|
|
||||||
/// </summary>
|
|
||||||
private void AuthorizeSystem(string code)
|
private void AuthorizeSystem(string code)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
@@ -1698,9 +1676,6 @@ namespace PepperDash.Essentials
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dumps info in response to console command.
|
|
||||||
/// </summary>
|
|
||||||
private void ShowInfo()
|
private void ShowInfo()
|
||||||
{
|
{
|
||||||
var url = Config != null ? Host : "No config";
|
var url = Config != null ? Host : "No config";
|
||||||
@@ -1766,38 +1741,37 @@ namespace PepperDash.Essentials
|
|||||||
"\r\n UI Client Info:\r\n" +
|
"\r\n UI Client Info:\r\n" +
|
||||||
" Tokens Defined: {0}\r\n" +
|
" Tokens Defined: {0}\r\n" +
|
||||||
" Clients Connected: {1}\r\n",
|
" Clients Connected: {1}\r\n",
|
||||||
_directServer.UiClients.Count,
|
_directServer.UiClientContexts.Count,
|
||||||
_directServer.ConnectedUiClientsCount
|
_directServer.ConnectedUiClientsCount
|
||||||
);
|
);
|
||||||
|
|
||||||
var clientNo = 1;
|
var clientNo = 1;
|
||||||
foreach (var clientContext in _directServer.UiClients)
|
foreach (var clientContext in _directServer.UiClientContexts)
|
||||||
{
|
{
|
||||||
var isAlive = false;
|
var clients = _directServer.UiClients.Values.Where(c => c.Token == clientContext.Value.Token.Token);
|
||||||
var duration = "Not Connected";
|
|
||||||
|
|
||||||
if (clientContext.Value.Client != null)
|
|
||||||
{
|
|
||||||
isAlive = clientContext.Value.Client.Context.WebSocket.IsAlive;
|
|
||||||
duration = clientContext.Value.Client.ConnectedDuration.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
CrestronConsole.ConsoleCommandResponse(
|
CrestronConsole.ConsoleCommandResponse(
|
||||||
"\r\nClient {0}:\r\n" +
|
$"\r\nClient {clientNo}:\r\n" +
|
||||||
"Room Key: {1}\r\n" +
|
$" Room Key: {clientContext.Value.Token.RoomKey}\r\n" +
|
||||||
"Touchpanel Key: {6}\r\n" +
|
$" Touchpanel Key: {clientContext.Value.Token.TouchpanelKey}\r\n" +
|
||||||
"Token: {2}\r\n" +
|
$" Token: {clientContext.Key}\r\n" +
|
||||||
"Client URL: {3}\r\n" +
|
$" Client URL: {_directServer.UserAppUrlPrefix}{clientContext.Key}\r\n" +
|
||||||
"Connected: {4}\r\n" +
|
$" Clients:\r\n"
|
||||||
"Duration: {5}\r\n",
|
|
||||||
clientNo,
|
|
||||||
clientContext.Value.Token.RoomKey,
|
|
||||||
clientContext.Key,
|
|
||||||
string.Format("{0}{1}", _directServer.UserAppUrlPrefix, clientContext.Key),
|
|
||||||
isAlive,
|
|
||||||
duration,
|
|
||||||
clientContext.Value.Token.TouchpanelKey
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!clients.Any())
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse(" No clients connected");
|
||||||
|
}
|
||||||
|
foreach (var client in clients)
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse(
|
||||||
|
$" ID: {client.Id}\r\n" +
|
||||||
|
$" Connected: {client.Context.WebSocket.IsAlive}\r\n" +
|
||||||
|
$" Duration: {(client.Context.WebSocket.IsAlive ? client.ConnectedDuration.TotalSeconds.ToString() : "Not Connected")}\r\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
clientNo++;
|
clientNo++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1811,7 +1785,7 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// RegisterSystemToServer method
|
/// Register this system to the Mobile Control Edge Server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void RegisterSystemToServer()
|
public void RegisterSystemToServer()
|
||||||
{
|
{
|
||||||
@@ -1835,9 +1809,6 @@ namespace PepperDash.Essentials
|
|||||||
ConnectWebsocketClient();
|
ConnectWebsocketClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Connects the Websocket Client
|
|
||||||
/// </summary>
|
|
||||||
private void ConnectWebsocketClient()
|
private void ConnectWebsocketClient()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -1878,9 +1849,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attempts to connect the websocket
|
|
||||||
/// </summary>
|
|
||||||
private void TryConnect()
|
private void TryConnect()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -1910,9 +1878,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gracefully handles conect failures by reconstructing the ws client and starting the reconnect timer
|
|
||||||
/// </summary>
|
|
||||||
private void HandleConnectFailure()
|
private void HandleConnectFailure()
|
||||||
{
|
{
|
||||||
_wsClient2 = null;
|
_wsClient2 = null;
|
||||||
@@ -1944,11 +1909,6 @@ namespace PepperDash.Essentials
|
|||||||
StartServerReconnectTimer();
|
StartServerReconnectTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
private void HandleOpen(object sender, EventArgs e)
|
private void HandleOpen(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
StopServerReconnectTimer();
|
StopServerReconnectTimer();
|
||||||
@@ -1957,11 +1917,6 @@ namespace PepperDash.Essentials
|
|||||||
SendMessageObject(new MobileControlMessage { Type = "hello" });
|
SendMessageObject(new MobileControlMessage { Type = "hello" });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
private void HandleMessage(object sender, MessageEventArgs e)
|
private void HandleMessage(object sender, MessageEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.IsPing)
|
if (e.IsPing)
|
||||||
@@ -1978,11 +1933,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
private void HandleError(object sender, ErrorEventArgs e)
|
private void HandleError(object sender, ErrorEventArgs e)
|
||||||
{
|
{
|
||||||
this.LogError("Websocket error {0}", e.Message);
|
this.LogError("Websocket error {0}", e.Message);
|
||||||
@@ -1991,11 +1941,6 @@ namespace PepperDash.Essentials
|
|||||||
StartServerReconnectTimer();
|
StartServerReconnectTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="e"></param>
|
|
||||||
private void HandleClose(object sender, CloseEventArgs e)
|
private void HandleClose(object sender, CloseEventArgs e)
|
||||||
{
|
{
|
||||||
this.LogDebug(
|
this.LogDebug(
|
||||||
@@ -2016,9 +1961,6 @@ namespace PepperDash.Essentials
|
|||||||
StartServerReconnectTimer();
|
StartServerReconnectTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// After a "hello" from the server, sends config and stuff
|
|
||||||
/// </summary>
|
|
||||||
private void SendInitialMessage()
|
private void SendInitialMessage()
|
||||||
{
|
{
|
||||||
this.LogInformation("Sending initial join message");
|
this.LogInformation("Sending initial join message");
|
||||||
@@ -2045,7 +1987,7 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GetConfigWithPluginVersion method
|
/// Get the Essentials configuration with version data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MobileControlEssentialsConfig GetConfigWithPluginVersion()
|
public MobileControlEssentialsConfig GetConfigWithPluginVersion()
|
||||||
{
|
{
|
||||||
@@ -2080,8 +2022,13 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SetClientUrl method
|
/// Set the Client URL for a given room
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="path">new App URL</param>
|
||||||
|
/// <param name="roomKey">room key. Default is null</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// If roomKey is null, the URL will be set for the entire system.
|
||||||
|
/// </remarks>
|
||||||
public void SetClientUrl(string path, string roomKey = null)
|
public void SetClientUrl(string path, string roomKey = null)
|
||||||
{
|
{
|
||||||
var message = new MobileControlMessage
|
var message = new MobileControlMessage
|
||||||
@@ -2097,9 +2044,6 @@ namespace PepperDash.Essentials
|
|||||||
/// Sends any object type to server
|
/// Sends any object type to server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="o"></param>
|
/// <param name="o"></param>
|
||||||
/// <summary>
|
|
||||||
/// SendMessageObject method
|
|
||||||
/// </summary>
|
|
||||||
public void SendMessageObject(IMobileControlMessage o)
|
public void SendMessageObject(IMobileControlMessage o)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -2123,8 +2067,9 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// SendMessageObjectToDirectClient method
|
/// Send a message to a client using the Direct Server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="o">object to send</param>
|
||||||
public void SendMessageObjectToDirectClient(object o)
|
public void SendMessageObjectToDirectClient(object o)
|
||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
@@ -2137,10 +2082,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disconnects the Websocket Client and stops the heartbeat timer
|
|
||||||
/// </summary>
|
|
||||||
private void CleanUpWebsocketClient()
|
private void CleanUpWebsocketClient()
|
||||||
{
|
{
|
||||||
if (_wsClient2 == null)
|
if (_wsClient2 == null)
|
||||||
@@ -2198,9 +2139,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
private void StartServerReconnectTimer()
|
private void StartServerReconnectTimer()
|
||||||
{
|
{
|
||||||
StopServerReconnectTimer();
|
StopServerReconnectTimer();
|
||||||
@@ -2211,9 +2149,6 @@ namespace PepperDash.Essentials
|
|||||||
this.LogDebug("Reconnect Timer Started.");
|
this.LogDebug("Reconnect Timer Started.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does what it says
|
|
||||||
/// </summary>
|
|
||||||
private void StopServerReconnectTimer()
|
private void StopServerReconnectTimer()
|
||||||
{
|
{
|
||||||
if (_serverReconnectTimer == null)
|
if (_serverReconnectTimer == null)
|
||||||
@@ -2224,10 +2159,6 @@ namespace PepperDash.Essentials
|
|||||||
_serverReconnectTimer = null;
|
_serverReconnectTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resets reconnect timer and updates usercode
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="content"></param>
|
|
||||||
private void HandleHeartBeat(JToken content)
|
private void HandleHeartBeat(JToken content)
|
||||||
{
|
{
|
||||||
SendMessageObject(new MobileControlMessage { Type = "/system/heartbeatAck" });
|
SendMessageObject(new MobileControlMessage { Type = "/system/heartbeatAck" });
|
||||||
@@ -2248,6 +2179,7 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
var clientId = content["clientId"].Value<string>();
|
var clientId = content["clientId"].Value<string>();
|
||||||
var roomKey = content["roomKey"].Value<string>();
|
var roomKey = content["roomKey"].Value<string>();
|
||||||
|
var touchpanelKey = content.SelectToken("touchpanelKey");
|
||||||
|
|
||||||
if (_roomCombiner == null)
|
if (_roomCombiner == null)
|
||||||
{
|
{
|
||||||
@@ -2259,6 +2191,10 @@ namespace PepperDash.Essentials
|
|||||||
};
|
};
|
||||||
|
|
||||||
SendMessageObject(message);
|
SendMessageObject(message);
|
||||||
|
|
||||||
|
SendDeviceInterfaces(clientId);
|
||||||
|
|
||||||
|
SendTouchpanelKey(clientId, touchpanelKey);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2270,7 +2206,12 @@ namespace PepperDash.Essentials
|
|||||||
ClientId = clientId,
|
ClientId = clientId,
|
||||||
Content = roomKey
|
Content = roomKey
|
||||||
};
|
};
|
||||||
|
|
||||||
SendMessageObject(message);
|
SendMessageObject(message);
|
||||||
|
|
||||||
|
SendDeviceInterfaces(clientId);
|
||||||
|
|
||||||
|
SendTouchpanelKey(clientId, touchpanelKey);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2288,6 +2229,10 @@ namespace PepperDash.Essentials
|
|||||||
};
|
};
|
||||||
|
|
||||||
SendMessageObject(message);
|
SendMessageObject(message);
|
||||||
|
|
||||||
|
SendDeviceInterfaces(clientId);
|
||||||
|
|
||||||
|
SendTouchpanelKey(clientId, touchpanelKey);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2301,6 +2246,54 @@ namespace PepperDash.Essentials
|
|||||||
};
|
};
|
||||||
|
|
||||||
SendMessageObject(newMessage);
|
SendMessageObject(newMessage);
|
||||||
|
|
||||||
|
SendDeviceInterfaces(clientId);
|
||||||
|
|
||||||
|
SendTouchpanelKey(clientId, touchpanelKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendTouchpanelKey(string clientId, JToken touchpanelKeyToken)
|
||||||
|
{
|
||||||
|
if (touchpanelKeyToken == null)
|
||||||
|
{
|
||||||
|
this.LogWarning("Touchpanel key not found for client {clientId}", clientId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendMessageObject(new MobileControlMessage
|
||||||
|
{
|
||||||
|
Type = "/system/touchpanelKey",
|
||||||
|
ClientId = clientId,
|
||||||
|
Content = touchpanelKeyToken.Value<string>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendDeviceInterfaces(string clientId)
|
||||||
|
{
|
||||||
|
this.LogDebug("Sending Device interfaces");
|
||||||
|
var devices = DeviceManager.GetDevices();
|
||||||
|
Dictionary<string, DeviceInterfaceInfo> deviceInterfaces = new Dictionary<string, DeviceInterfaceInfo>();
|
||||||
|
|
||||||
|
foreach (var device in devices)
|
||||||
|
{
|
||||||
|
var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List<string>();
|
||||||
|
|
||||||
|
deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo
|
||||||
|
{
|
||||||
|
Key = device.Key,
|
||||||
|
Name = (device as IKeyName)?.Name ?? "",
|
||||||
|
Interfaces = interfaces
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = new MobileControlMessage
|
||||||
|
{
|
||||||
|
Type = "/system/deviceInterfaces",
|
||||||
|
ClientId = clientId,
|
||||||
|
Content = JToken.FromObject(new { deviceInterfaces })
|
||||||
|
};
|
||||||
|
|
||||||
|
SendMessageObject(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleUserCode(JToken content, Action<string, string> action = null)
|
private void HandleUserCode(JToken content, Action<string, string> action = null)
|
||||||
@@ -2337,16 +2330,13 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// HandleClientMessage method
|
/// Enqueue an incoming message for processing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void HandleClientMessage(string message)
|
public void HandleClientMessage(string message)
|
||||||
{
|
{
|
||||||
_receiveQueue.Enqueue(new ProcessStringMessage(message, ParseStreamRx));
|
_receiveQueue.Enqueue(new ProcessStringMessage(message, ParseStreamRx));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
private void ParseStreamRx(string messageText)
|
private void ParseStreamRx(string messageText)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(messageText))
|
if (string.IsNullOrEmpty(messageText))
|
||||||
@@ -2414,10 +2404,33 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
foreach (var handler in handlers)
|
foreach (var handler in handlers)
|
||||||
{
|
{
|
||||||
Task.Run(
|
Task.Run(() =>
|
||||||
() =>
|
{
|
||||||
handler.Action(message.Type, message.ClientId, message.Content)
|
try
|
||||||
);
|
{
|
||||||
|
handler.Action(message.Type, message.ClientId, message.Content);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.LogError(
|
||||||
|
"Exception in handler for message type {type}, ClientId {clientId}",
|
||||||
|
message.Type,
|
||||||
|
message.ClientId
|
||||||
|
);
|
||||||
|
this.LogDebug(ex, "Stack Trace: ");
|
||||||
|
}
|
||||||
|
}).ContinueWith(task =>
|
||||||
|
{
|
||||||
|
if (task.IsFaulted && task.Exception != null)
|
||||||
|
{
|
||||||
|
this.LogError(
|
||||||
|
"Unhandled exception in Task for message type {type}, ClientId {clientId}",
|
||||||
|
message.Type,
|
||||||
|
message.ClientId
|
||||||
|
);
|
||||||
|
this.LogDebug(task.Exception.GetBaseException(), "Stack Trace: ");
|
||||||
|
}
|
||||||
|
}, TaskContinuationOptions.OnlyOnFaulted);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -2433,10 +2446,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s"></param>
|
|
||||||
private void TestHttpRequest(string s)
|
private void TestHttpRequest(string s)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,23 +1,35 @@
|
|||||||
using PepperDash.Core;
|
using System;
|
||||||
|
using PepperDash.Core;
|
||||||
using PepperDash.Core.Logging;
|
using PepperDash.Core.Logging;
|
||||||
using PepperDash.Essentials.AppServer.Messengers;
|
using PepperDash.Essentials.AppServer.Messengers;
|
||||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||||
using System;
|
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.RoomBridges
|
namespace PepperDash.Essentials.RoomBridges
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Base class for a Mobile Control Bridge that's used to control a room
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomMessenger
|
public abstract class MobileControlBridgeBase : MessengerBase, IMobileControlRoomMessenger
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when the user Code changes
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<EventArgs> UserCodeChanged;
|
public event EventHandler<EventArgs> UserCodeChanged;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when a user should be prompted for the new code
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<EventArgs> UserPromptedForCode;
|
public event EventHandler<EventArgs> UserPromptedForCode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when a client joins to control this room
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<EventArgs> ClientJoined;
|
public event EventHandler<EventArgs> ClientJoined;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when the App URL for this room changes
|
||||||
|
/// </summary>
|
||||||
public event EventHandler<EventArgs> AppUrlChanged;
|
public event EventHandler<EventArgs> AppUrlChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -49,15 +61,32 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string McServerUrl { get; private set; }
|
public string McServerUrl { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Room Name
|
||||||
|
/// </summary>
|
||||||
public abstract string RoomName { get; }
|
public abstract string RoomName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Room key
|
||||||
|
/// </summary>
|
||||||
public abstract string RoomKey { get; }
|
public abstract string RoomKey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileControlBridgeBase"/> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The unique key for this bridge</param>
|
||||||
|
/// <param name="messagePath">The message path for this bridge</param>
|
||||||
protected MobileControlBridgeBase(string key, string messagePath)
|
protected MobileControlBridgeBase(string key, string messagePath)
|
||||||
: base(key, messagePath)
|
: base(key, messagePath)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileControlBridgeBase"/> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The unique key for this bridge</param>
|
||||||
|
/// <param name="messagePath">The message path for this bridge</param>
|
||||||
|
/// <param name="device">The device associated with this bridge</param>
|
||||||
protected MobileControlBridgeBase(string key, string messagePath, IKeyName device)
|
protected MobileControlBridgeBase(string key, string messagePath, IKeyName device)
|
||||||
: base(key, messagePath, device)
|
: base(key, messagePath, device)
|
||||||
{
|
{
|
||||||
@@ -110,6 +139,10 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
SetUserCode(code);
|
SetUserCode(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the App Url with the provided URL
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">The new App URL</param>
|
||||||
public virtual void UpdateAppUrl(string url)
|
public virtual void UpdateAppUrl(string url)
|
||||||
{
|
{
|
||||||
AppUrl = url;
|
AppUrl = url;
|
||||||
@@ -137,16 +170,25 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
OnUserCodeChanged();
|
OnUserCodeChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Trigger the UserCodeChanged event
|
||||||
|
/// </summary>
|
||||||
protected void OnUserCodeChanged()
|
protected void OnUserCodeChanged()
|
||||||
{
|
{
|
||||||
UserCodeChanged?.Invoke(this, new EventArgs());
|
UserCodeChanged?.Invoke(this, new EventArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Trigger the UserPromptedForCode event
|
||||||
|
/// </summary>
|
||||||
protected void OnUserPromptedForCode()
|
protected void OnUserPromptedForCode()
|
||||||
{
|
{
|
||||||
UserPromptedForCode?.Invoke(this, new EventArgs());
|
UserPromptedForCode?.Invoke(this, new EventArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Trigger the ClientJoined event
|
||||||
|
/// </summary>
|
||||||
protected void OnClientJoined()
|
protected void OnClientJoined()
|
||||||
{
|
{
|
||||||
ClientJoined?.Invoke(this, new EventArgs());
|
ClientJoined?.Invoke(this, new EventArgs());
|
||||||
|
|||||||
@@ -41,24 +41,37 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string DefaultRoomKey { get; private set; }
|
public string DefaultRoomKey { get; private set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Gets the name of the room
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override string RoomName
|
public override string RoomName
|
||||||
{
|
{
|
||||||
get { return Room.Name; }
|
get { return Room.Name; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the key of the room
|
||||||
|
/// </summary>
|
||||||
public override string RoomKey
|
public override string RoomKey
|
||||||
{
|
{
|
||||||
get { return Room.Key; }
|
get { return Room.Key; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MobileControlEssentialsRoomBridge"/> class with the specified room
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="room">The essentials room to bridge</param>
|
||||||
public MobileControlEssentialsRoomBridge(IEssentialsRoom room) :
|
public MobileControlEssentialsRoomBridge(IEssentialsRoom room) :
|
||||||
this($"mobileControlBridge-{room.Key}", room.Key, room)
|
this($"mobileControlBridge-{room.Key}", room.Key, room)
|
||||||
{
|
{
|
||||||
Room = room;
|
Room = room;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MobileControlEssentialsRoomBridge"/> class with the specified parameters
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The unique key for this bridge</param>
|
||||||
|
/// <param name="roomKey">The key of the room to bridge</param>
|
||||||
|
/// <param name="room">The essentials room to bridge</param>
|
||||||
public MobileControlEssentialsRoomBridge(string key, string roomKey, IEssentialsRoom room) : base(key, $"/room/{room.Key}", room as Device)
|
public MobileControlEssentialsRoomBridge(string key, string roomKey, IEssentialsRoom room) : base(key, $"/room/{room.Key}", room as Device)
|
||||||
{
|
{
|
||||||
DefaultRoomKey = roomKey;
|
DefaultRoomKey = roomKey;
|
||||||
@@ -66,7 +79,9 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
AddPreActivationAction(GetRoom);
|
AddPreActivationAction(GetRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers all message handling actions with the AppServer for this room bridge
|
||||||
|
/// </summary>
|
||||||
protected override void RegisterActions()
|
protected override void RegisterActions()
|
||||||
{
|
{
|
||||||
// we add actions to the messaging system with a path, and a related action. Custom action
|
// we add actions to the messaging system with a path, and a related action. Custom action
|
||||||
@@ -284,6 +299,9 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
Room = tempRoom;
|
Room = tempRoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles user code changes and generates QR code URL
|
||||||
|
/// </summary>
|
||||||
protected override void UserCodeChange()
|
protected override void UserCodeChange()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Server user code changed: {userCode}", this, UserCode);
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Server user code changed: {userCode}", this, UserCode);
|
||||||
@@ -807,18 +825,33 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public RoomConfiguration Configuration { get; set; }
|
public RoomConfiguration Configuration { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the activity mode of the room
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("activityMode", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("activityMode", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public int? ActivityMode { get; set; }
|
public int? ActivityMode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether advanced sharing is active
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("advancedSharingActive", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("advancedSharingActive", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? AdvancedSharingActive { get; set; }
|
public bool? AdvancedSharingActive { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room is powered on
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("isOn", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("isOn", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? IsOn { get; set; }
|
public bool? IsOn { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room is warming up
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("isWarmingUp", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("isWarmingUp", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? IsWarmingUp { get; set; }
|
public bool? IsWarmingUp { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room is cooling down
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("isCoolingDown", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("isCoolingDown", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? IsCoolingDown { get; set; }
|
public bool? IsCoolingDown { get; set; }
|
||||||
|
|
||||||
@@ -834,9 +867,15 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public ShareState Share { get; set; }
|
public ShareState Share { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the volume controls collection
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public Dictionary<string, Volume> Volumes { get; set; }
|
public Dictionary<string, Volume> Volumes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room is in a call
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? IsInCall { get; set; }
|
public bool? IsInCall { get; set; }
|
||||||
}
|
}
|
||||||
@@ -853,9 +892,15 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("currentShareText", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("currentShareText", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public string CurrentShareText { get; set; }
|
public string CurrentShareText { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether sharing is enabled
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? Enabled { get; set; }
|
public bool? Enabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether content is currently being shared
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("isSharing", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("isSharing", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? IsSharing { get; set; }
|
public bool? IsSharing { get; set; }
|
||||||
}
|
}
|
||||||
@@ -865,24 +910,45 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class RoomConfiguration
|
public class RoomConfiguration
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room has video conferencing capabilities
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("hasVideoConferencing", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("hasVideoConferencing", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? HasVideoConferencing { get; set; }
|
public bool? HasVideoConferencing { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the video codec is a Zoom Room
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("videoCodecIsZoomRoom", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("videoCodecIsZoomRoom", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? VideoCodecIsZoomRoom { get; set; }
|
public bool? VideoCodecIsZoomRoom { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room has audio conferencing capabilities
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("hasAudioConferencing", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("hasAudioConferencing", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? HasAudioConferencing { get; set; }
|
public bool? HasAudioConferencing { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room has environmental controls (lighting, shades, etc.)
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("hasEnvironmentalControls", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("hasEnvironmentalControls", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? HasEnvironmentalControls { get; set; }
|
public bool? HasEnvironmentalControls { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room has camera controls
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("hasCameraControls", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("hasCameraControls", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? HasCameraControls { get; set; }
|
public bool? HasCameraControls { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room has set-top box controls
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("hasSetTopBoxControls", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("hasSetTopBoxControls", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? HasSetTopBoxControls { get; set; }
|
public bool? HasSetTopBoxControls { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room has routing controls
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("hasRoutingControls", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("hasRoutingControls", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? HasRoutingControls { get; set; }
|
public bool? HasRoutingControls { get; set; }
|
||||||
|
|
||||||
@@ -949,6 +1015,9 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public string DefaultDisplayKey { get; set; }
|
public string DefaultDisplayKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the destinations dictionary keyed by destination type
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("destinations", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("destinations", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public Dictionary<eSourceListItemDestinationTypes, string> Destinations { get; set; }
|
public Dictionary<eSourceListItemDestinationTypes, string> Destinations { get; set; }
|
||||||
|
|
||||||
@@ -959,9 +1028,15 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public List<EnvironmentalDeviceConfiguration> EnvironmentalDevices { get; set; }
|
public List<EnvironmentalDeviceConfiguration> EnvironmentalDevices { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the source list for the room
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("sourceList", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("sourceList", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public Dictionary<string, SourceListItem> SourceList { get; set; }
|
public Dictionary<string, SourceListItem> SourceList { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the destination list for the room
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("destinationList", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("destinationList", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public Dictionary<string, DestinationListItem> DestinationList { get; set; }
|
public Dictionary<string, DestinationListItem> DestinationList { get; set; }
|
||||||
|
|
||||||
@@ -972,6 +1047,9 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("audioControlPointList", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("audioControlPointList", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public AudioControlPointListItem AudioControlPointList { get; set; }
|
public AudioControlPointListItem AudioControlPointList { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the camera list for the room
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public Dictionary<string, CameraListItem> CameraList { get; set; }
|
public Dictionary<string, CameraListItem> CameraList { get; set; }
|
||||||
|
|
||||||
@@ -1004,9 +1082,15 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; }
|
public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the room supports advanced sharing features
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? SupportsAdvancedSharing { get; set; }
|
public bool? SupportsAdvancedSharing { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether the user can change the share mode
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? UserCanChangeShareMode { get; set; }
|
public bool? UserCanChangeShareMode { get; set; }
|
||||||
|
|
||||||
@@ -1017,6 +1101,9 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("roomCombinerKey", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("roomCombinerKey", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public string RoomCombinerKey { get; set; }
|
public string RoomCombinerKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="RoomConfiguration"/> class
|
||||||
|
/// </summary>
|
||||||
public RoomConfiguration()
|
public RoomConfiguration()
|
||||||
{
|
{
|
||||||
Destinations = new Dictionary<eSourceListItemDestinationTypes, string>();
|
Destinations = new Dictionary<eSourceListItemDestinationTypes, string>();
|
||||||
@@ -1046,6 +1133,11 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
[JsonProperty("deviceType", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("deviceType", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public eEnvironmentalDeviceTypes DeviceType { get; private set; }
|
public eEnvironmentalDeviceTypes DeviceType { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EnvironmentalDeviceConfiguration"/> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The device key</param>
|
||||||
|
/// <param name="type">The environmental device type</param>
|
||||||
public EnvironmentalDeviceConfiguration(string key, eEnvironmentalDeviceTypes type)
|
public EnvironmentalDeviceConfiguration(string key, eEnvironmentalDeviceTypes type)
|
||||||
{
|
{
|
||||||
DeviceKey = key;
|
DeviceKey = key;
|
||||||
@@ -1054,14 +1146,29 @@ namespace PepperDash.Essentials.RoomBridges
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enumeration of eEnvironmentalDeviceTypes values
|
/// Enumeration of environmental device types
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum eEnvironmentalDeviceTypes
|
public enum eEnvironmentalDeviceTypes
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// No environmental device type specified
|
||||||
|
/// </summary>
|
||||||
None,
|
None,
|
||||||
|
/// <summary>
|
||||||
|
/// Lighting device type
|
||||||
|
/// </summary>
|
||||||
Lighting,
|
Lighting,
|
||||||
|
/// <summary>
|
||||||
|
/// Shade device type
|
||||||
|
/// </summary>
|
||||||
Shade,
|
Shade,
|
||||||
|
/// <summary>
|
||||||
|
/// Shade controller device type
|
||||||
|
/// </summary>
|
||||||
ShadeController,
|
ShadeController,
|
||||||
|
/// <summary>
|
||||||
|
/// Relay device type
|
||||||
|
/// </summary>
|
||||||
Relay,
|
Relay,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
using PepperDash.Core;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using PepperDash.Core;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Services
|
namespace PepperDash.Essentials.Services
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a MobileControlApiService
|
/// Service for interacting with a Mobile Control Edge server instance
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MobileControlApiService
|
public class MobileControlApiService
|
||||||
{
|
{
|
||||||
private readonly HttpClient _client;
|
private readonly HttpClient _client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileControlApiService"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apiUrl">Mobile Control Edge API URL</param>
|
||||||
public MobileControlApiService(string apiUrl)
|
public MobileControlApiService(string apiUrl)
|
||||||
{
|
{
|
||||||
var handler = new HttpClientHandler
|
var handler = new HttpClientHandler
|
||||||
@@ -24,6 +28,13 @@ namespace PepperDash.Essentials.Services
|
|||||||
_client = new HttpClient(handler);
|
_client = new HttpClient(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send authorization request to Mobile Control Edge Server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="apiUrl">Mobile Control Edge API URL</param>
|
||||||
|
/// <param name="grantCode">Grant code for authorization</param>
|
||||||
|
/// <param name="systemUuid">System UUID for authorization</param>
|
||||||
|
/// <returns>Authorization response</returns>
|
||||||
public async Task<AuthorizationResponse> SendAuthorizationRequest(string apiUrl, string grantCode, string systemUuid)
|
public async Task<AuthorizationResponse> SendAuthorizationRequest(string apiUrl, string grantCode, string systemUuid)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -7,8 +7,15 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITheme : IKeyed
|
public interface ITheme : IKeyed
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Current theme
|
||||||
|
/// </summary>
|
||||||
string Theme { get; }
|
string Theme { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the theme with the given value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="theme">The theme to set</param>
|
||||||
void UpdateTheme(string theme);
|
void UpdateTheme(string theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,24 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITswAppControl : IKeyed
|
public interface ITswAppControl : IKeyed
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Updates when the Zoom Room Control Application opens or closes
|
||||||
|
/// </summary>
|
||||||
BoolFeedback AppOpenFeedback { get; }
|
BoolFeedback AppOpenFeedback { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide the Zoom App and show the User Control Application
|
||||||
|
/// </summary>
|
||||||
void HideOpenApp();
|
void HideOpenApp();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Close the Zoom App and show the User Control Application
|
||||||
|
/// </summary>
|
||||||
void CloseOpenApp();
|
void CloseOpenApp();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open the Zoom App
|
||||||
|
/// </summary>
|
||||||
void OpenApp();
|
void OpenApp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,10 +34,19 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ITswZoomControl : IKeyed
|
public interface ITswZoomControl : IKeyed
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Updates when Zoom has an incoming call
|
||||||
|
/// </summary>
|
||||||
BoolFeedback ZoomIncomingCallFeedback { get; }
|
BoolFeedback ZoomIncomingCallFeedback { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates when Zoom is in a call
|
||||||
|
/// </summary>
|
||||||
BoolFeedback ZoomInCallFeedback { get; }
|
BoolFeedback ZoomInCallFeedback { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// End a Zoom Call
|
||||||
|
/// </summary>
|
||||||
void EndZoomCall();
|
void EndZoomCall();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,24 @@ using PepperDash.Essentials.AppServer.Messengers;
|
|||||||
namespace PepperDash.Essentials.Touchpanel
|
namespace PepperDash.Essentials.Touchpanel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a ITswAppControlMessenger
|
/// Messenger for controlling the Zoom App on a TSW Panel that supports the Zoom Room Control Application
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ITswAppControlMessenger : MessengerBase
|
public class ITswAppControlMessenger : MessengerBase
|
||||||
{
|
{
|
||||||
private readonly ITswAppControl _appControl;
|
private readonly ITswAppControl _appControl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="ITswAppControlMessenger"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key for this messenger</param>
|
||||||
|
/// <param name="messagePath">The message path for this messenger</param>
|
||||||
|
/// <param name="device">The device for this messenger</param>
|
||||||
public ITswAppControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device)
|
public ITswAppControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device)
|
||||||
{
|
{
|
||||||
_appControl = device as ITswAppControl;
|
_appControl = device as ITswAppControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void RegisterActions()
|
protected override void RegisterActions()
|
||||||
{
|
{
|
||||||
if (_appControl == null)
|
if (_appControl == null)
|
||||||
@@ -26,7 +33,7 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddAction($"/fullStatus", (id, context) => SendFullStatus());
|
AddAction($"/fullStatus", (id, context) => SendFullStatus(id));
|
||||||
|
|
||||||
AddAction($"/openApp", (id, context) => _appControl.OpenApp());
|
AddAction($"/openApp", (id, context) => _appControl.OpenApp());
|
||||||
|
|
||||||
@@ -43,14 +50,14 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendFullStatus()
|
private void SendFullStatus(string id = null)
|
||||||
{
|
{
|
||||||
var message = new TswAppStateMessage
|
var message = new TswAppStateMessage
|
||||||
{
|
{
|
||||||
AppOpen = _appControl.AppOpenFeedback.BoolValue,
|
AppOpen = _appControl.AppOpenFeedback.BoolValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
PostStatusMessage(message);
|
PostStatusMessage(message, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +66,9 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class TswAppStateMessage : DeviceStateMessageBase
|
public class TswAppStateMessage : DeviceStateMessageBase
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// True if the Zoom app is open on a TSW panel
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("appOpen", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("appOpen", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? AppOpen { get; set; }
|
public bool? AppOpen { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,17 +8,24 @@ using PepperDash.Essentials.AppServer.Messengers;
|
|||||||
namespace PepperDash.Essentials.Touchpanel
|
namespace PepperDash.Essentials.Touchpanel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a ITswZoomControlMessenger
|
/// Messenger to handle Zoom status and control for a TSW panel that supports the Zoom Application
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ITswZoomControlMessenger : MessengerBase
|
public class ITswZoomControlMessenger : MessengerBase
|
||||||
{
|
{
|
||||||
private readonly ITswZoomControl _zoomControl;
|
private readonly ITswZoomControl _zoomControl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="ITswZoomControlMessenger"/> class for the given device
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key for this messenger</param>
|
||||||
|
/// <param name="messagePath">The message path for this messenger</param>
|
||||||
|
/// <param name="device">The device for this messenger</param>
|
||||||
public ITswZoomControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device)
|
public ITswZoomControlMessenger(string key, string messagePath, Device device) : base(key, messagePath, device)
|
||||||
{
|
{
|
||||||
_zoomControl = device as ITswZoomControl;
|
_zoomControl = device as ITswZoomControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void RegisterActions()
|
protected override void RegisterActions()
|
||||||
{
|
{
|
||||||
if (_zoomControl == null)
|
if (_zoomControl == null)
|
||||||
@@ -27,7 +34,9 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddAction($"/fullStatus", (id, context) => SendFullStatus());
|
AddAction($"/fullStatus", (id, context) => SendFullStatus(id));
|
||||||
|
|
||||||
|
AddAction($"/zoomStatus", (id, content) => SendFullStatus(id));
|
||||||
|
|
||||||
|
|
||||||
AddAction($"/endCall", (id, context) => _zoomControl.EndZoomCall());
|
AddAction($"/endCall", (id, context) => _zoomControl.EndZoomCall());
|
||||||
@@ -53,7 +62,7 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendFullStatus()
|
private void SendFullStatus(string id = null)
|
||||||
{
|
{
|
||||||
var message = new TswZoomStateMessage
|
var message = new TswZoomStateMessage
|
||||||
{
|
{
|
||||||
@@ -61,7 +70,7 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
IncomingCall = _zoomControl?.ZoomIncomingCallFeedback.BoolValue
|
IncomingCall = _zoomControl?.ZoomIncomingCallFeedback.BoolValue
|
||||||
};
|
};
|
||||||
|
|
||||||
PostStatusMessage(message);
|
PostStatusMessage(message, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,9 +79,16 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class TswZoomStateMessage : DeviceStateMessageBase
|
public class TswZoomStateMessage : DeviceStateMessageBase
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// True if the panel is in a Zoom call
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("inCall", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("inCall", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? InCall { get; set; }
|
public bool? InCall { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if there is an incoming Zoom call
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
[JsonProperty("incomingCall", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("incomingCall", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? IncomingCall { get; set; }
|
public bool? IncomingCall { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
if (!x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue)
|
if (!x70Panel.ExtenderApplicationControlReservedSigs.HideOpenedApplicationFeedback.BoolValue)
|
||||||
{
|
{
|
||||||
x70Panel.ExtenderButtonToolbarReservedSigs.ShowButtonToolbar();
|
x70Panel.ExtenderButtonToolbarReservedSigs.ShowButtonToolbar();
|
||||||
|
|
||||||
x70Panel.ExtenderButtonToolbarReservedSigs.Button2On();
|
x70Panel.ExtenderButtonToolbarReservedSigs.Button2On();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -294,17 +295,16 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
handler(this, new DeviceInfoEventArgs(DeviceInfo));
|
handler(this, new DeviceInfoEventArgs(DeviceInfo));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
x70Panel.ExtenderButtonToolbarReservedSigs.DeviceExtenderSigChange += (o, a) =>
|
||||||
|
{
|
||||||
|
this.LogVerbose("X70 Button Toolbar Device Extender args: {event}:{sig}:{name}:{type}:{boolValue}:{ushortValue}:{stringValue}", a.Event, a.Sig, a.Sig.Name, a.Sig.Type, a.Sig.BoolValue, a.Sig.UShortValue, a.Sig.StringValue);
|
||||||
|
};
|
||||||
|
|
||||||
x70Panel.ExtenderApplicationControlReservedSigs.Use();
|
x70Panel.ExtenderApplicationControlReservedSigs.Use();
|
||||||
x70Panel.ExtenderZoomRoomAppReservedSigs.Use();
|
x70Panel.ExtenderZoomRoomAppReservedSigs.Use();
|
||||||
x70Panel.ExtenderEthernetReservedSigs.Use();
|
x70Panel.ExtenderEthernetReservedSigs.Use();
|
||||||
x70Panel.ExtenderButtonToolbarReservedSigs.Use();
|
x70Panel.ExtenderButtonToolbarReservedSigs.Use();
|
||||||
|
|
||||||
x70Panel.ExtenderButtonToolbarReservedSigs.Button1Off();
|
|
||||||
x70Panel.ExtenderButtonToolbarReservedSigs.Button3Off();
|
|
||||||
x70Panel.ExtenderButtonToolbarReservedSigs.Button4Off();
|
|
||||||
x70Panel.ExtenderButtonToolbarReservedSigs.Button5Off();
|
|
||||||
x70Panel.ExtenderButtonToolbarReservedSigs.Button6Off();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,34 +414,79 @@ namespace PepperDash.Essentials.Touchpanel
|
|||||||
McServerUrlFeedback.LinkInputSig(Panel.StringInput[3]);
|
McServerUrlFeedback.LinkInputSig(Panel.StringInput[3]);
|
||||||
UserCodeFeedback.LinkInputSig(Panel.StringInput[4]);
|
UserCodeFeedback.LinkInputSig(Panel.StringInput[4]);
|
||||||
|
|
||||||
Panel.IpInformationChange += (sender, args) =>
|
Panel.IpInformationChange -= Panel_IpInformationChange;
|
||||||
|
Panel.IpInformationChange += Panel_IpInformationChange;
|
||||||
|
|
||||||
|
Panel.OnlineStatusChange -= Panel_OnlineChange;
|
||||||
|
Panel.OnlineStatusChange += Panel_OnlineChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Panel_OnlineChange(GenericBase sender, OnlineOfflineEventArgs args)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (args.Connected)
|
if (!args.DeviceOnLine)
|
||||||
{
|
{
|
||||||
this.LogVerbose("Connection from IP: {ip}", args.DeviceIpAddress);
|
this.LogInformation("panel is offline");
|
||||||
this.LogInformation("Sending {appUrl} on join 1", AppUrlFeedback.StringValue);
|
return;
|
||||||
|
|
||||||
var appUrl = GetUrlWithCorrectIp(_appUrl);
|
|
||||||
Panel.StringInput[1].StringValue = appUrl;
|
|
||||||
|
|
||||||
SetAppUrl(appUrl);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
this.LogVerbose("Disconnection from IP: {ip}", args.DeviceIpAddress);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Panel.OnlineStatusChange += (sender, args) =>
|
this.LogDebug("panel is online");
|
||||||
{
|
|
||||||
this.LogInformation("Sending {appUrl} on join 1", AppUrlFeedback.StringValue);
|
|
||||||
|
|
||||||
UpdateFeedbacks();
|
UpdateFeedbacks();
|
||||||
Panel.StringInput[1].StringValue = _appUrl;
|
Panel.StringInput[1].StringValue = _appUrl;
|
||||||
Panel.StringInput[2].StringValue = QrCodeUrlFeedback.StringValue;
|
Panel.StringInput[2].StringValue = QrCodeUrlFeedback.StringValue;
|
||||||
Panel.StringInput[3].StringValue = McServerUrlFeedback.StringValue;
|
Panel.StringInput[3].StringValue = McServerUrlFeedback.StringValue;
|
||||||
Panel.StringInput[4].StringValue = UserCodeFeedback.StringValue;
|
Panel.StringInput[4].StringValue = UserCodeFeedback.StringValue;
|
||||||
};
|
|
||||||
|
if (Panel is TswXX70Base x70Panel)
|
||||||
|
{
|
||||||
|
this.LogDebug("setting buttons off");
|
||||||
|
|
||||||
|
x70Panel.ExtenderButtonToolbarReservedSigs.Button1Off();
|
||||||
|
x70Panel.ExtenderButtonToolbarReservedSigs.Button3Off();
|
||||||
|
x70Panel.ExtenderButtonToolbarReservedSigs.Button4Off();
|
||||||
|
x70Panel.ExtenderButtonToolbarReservedSigs.Button5Off();
|
||||||
|
x70Panel.ExtenderButtonToolbarReservedSigs.Button6Off();
|
||||||
|
}
|
||||||
|
|
||||||
|
SendUrlToPanel();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
this.LogError("Exception in panel online: {message}", ex.Message);
|
||||||
|
this.LogDebug(ex, "Stack Trace: ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendUrlToPanel()
|
||||||
|
{
|
||||||
|
var appUrl = GetUrlWithCorrectIp(_appUrl);
|
||||||
|
|
||||||
|
this.LogInformation("Sending {appUrl} on join 1", AppUrlFeedback.StringValue);
|
||||||
|
|
||||||
|
if (Panel.StringInput[1].StringValue == appUrl)
|
||||||
|
{
|
||||||
|
this.LogInformation("App URL already set to {appUrl}, no update needed", AppUrlFeedback.StringValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Panel.StringInput[1].StringValue = appUrl;
|
||||||
|
|
||||||
|
SetAppUrl(appUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Panel_IpInformationChange(GenericBase sender, ConnectedIpEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.Connected)
|
||||||
|
{
|
||||||
|
this.LogVerbose("Connection from IP: {ip}", args.DeviceIpAddress);
|
||||||
|
SendUrlToPanel();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.LogVerbose("Disconnection from IP: {ip}", args.DeviceIpAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,38 +1,46 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Core.Logging;
|
||||||
using PepperDash.Essentials.AppServer;
|
using PepperDash.Essentials.AppServer;
|
||||||
using PepperDash.Essentials.AppServer.Messengers;
|
using PepperDash.Essentials.AppServer.Messengers;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Touchpanel
|
namespace PepperDash.Essentials.Touchpanel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a ThemeMessenger
|
/// Messenger to save the current theme (light/dark) and send to a device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ThemeMessenger : MessengerBase
|
public class ThemeMessenger : MessengerBase
|
||||||
{
|
{
|
||||||
private readonly ITheme _tpDevice;
|
private readonly ITheme _tpDevice;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="ThemeMessenger"/> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key for this messenger</param>
|
||||||
|
/// <param name="path">The path for this messenger</param>
|
||||||
|
/// <param name="device">The device for this messenger</param>
|
||||||
public ThemeMessenger(string key, string path, ITheme device) : base(key, path, device as Device)
|
public ThemeMessenger(string key, string path, ITheme device) : base(key, path, device as Device)
|
||||||
{
|
{
|
||||||
_tpDevice = device;
|
_tpDevice = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override void RegisterActions()
|
protected override void RegisterActions()
|
||||||
{
|
{
|
||||||
AddAction("/fullStatus", (id, content) =>
|
AddAction("/fullStatus", (id, content) =>
|
||||||
{
|
{
|
||||||
PostStatusMessage(new ThemeUpdateMessage { Theme = _tpDevice.Theme });
|
PostStatusMessage(new ThemeUpdateMessage { Theme = _tpDevice.Theme }, id);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAction("/saveTheme", (id, content) =>
|
AddAction("/saveTheme", (id, content) =>
|
||||||
{
|
{
|
||||||
var theme = content.ToObject<MobileControlSimpleContent<string>>();
|
var theme = content.ToObject<MobileControlSimpleContent<string>>();
|
||||||
|
|
||||||
Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Setting theme to {theme}", this, theme.Value);
|
this.LogInformation("Setting theme to {theme}", theme.Value);
|
||||||
_tpDevice.UpdateTheme(theme.Value);
|
_tpDevice.UpdateTheme(theme.Value);
|
||||||
|
|
||||||
PostStatusMessage(JToken.FromObject(new { theme = theme.Value }));
|
PostStatusMessage(JToken.FromObject(new { theme = theme.Value }), clientId: id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
using Newtonsoft.Json;
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Core.Logging;
|
|
||||||
using PepperDash.Essentials.AppServer.Messengers;
|
using PepperDash.Essentials.AppServer.Messengers;
|
||||||
using PepperDash.Essentials.Core.Queues;
|
using PepperDash.Essentials.Core.Queues;
|
||||||
using PepperDash.Essentials.WebSocketServer;
|
|
||||||
using Serilog.Events;
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using WebSocketSharp;
|
using WebSocketSharp;
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
@@ -20,12 +16,22 @@ namespace PepperDash.Essentials
|
|||||||
private readonly WebSocket _ws;
|
private readonly WebSocket _ws;
|
||||||
private readonly object msgToSend;
|
private readonly object msgToSend;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize a message to send
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msg">message object to send</param>
|
||||||
|
/// <param name="ws">WebSocket instance</param>
|
||||||
public TransmitMessage(object msg, WebSocket ws)
|
public TransmitMessage(object msg, WebSocket ws)
|
||||||
{
|
{
|
||||||
_ws = ws;
|
_ws = ws;
|
||||||
msgToSend = msg;
|
msgToSend = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize a message to send
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msg">message object to send</param>
|
||||||
|
/// <param name="ws">WebSocket instance</param>
|
||||||
public TransmitMessage(DeviceStateMessageBase msg, WebSocket ws)
|
public TransmitMessage(DeviceStateMessageBase msg, WebSocket ws)
|
||||||
{
|
{
|
||||||
_ws = ws;
|
_ws = ws;
|
||||||
@@ -43,13 +49,13 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
if (_ws == null)
|
if (_ws == null)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Websocket client is null");
|
Debug.LogWarning("Cannot send message. Websocket client is null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_ws.IsAlive)
|
if (!_ws.IsAlive)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Websocket client is not connected");
|
Debug.LogWarning("Cannot send message. Websocket client is not connected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,83 +63,14 @@ namespace PepperDash.Essentials
|
|||||||
var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
|
var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
|
||||||
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
|
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Message TX: {0}", null, message);
|
Debug.LogVerbose("Message TX: {0}", message);
|
||||||
|
|
||||||
_ws.Send(message);
|
_ws.Send(message);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(ex, "Caught an exception in the Transmit Processor");
|
Debug.LogError("Caught an exception in the Transmit Processor: {message}", ex.Message);
|
||||||
}
|
Debug.LogDebug(ex, "Stack Trace: ");
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a MessageToClients
|
|
||||||
/// </summary>
|
|
||||||
public class MessageToClients : IQueueMessage
|
|
||||||
{
|
|
||||||
private readonly MobileControlWebsocketServer _server;
|
|
||||||
private readonly object msgToSend;
|
|
||||||
|
|
||||||
public MessageToClients(object msg, MobileControlWebsocketServer server)
|
|
||||||
{
|
|
||||||
_server = server;
|
|
||||||
msgToSend = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server)
|
|
||||||
{
|
|
||||||
_server = server;
|
|
||||||
msgToSend = msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Implementation of IQueueMessage
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dispatch method
|
|
||||||
/// </summary>
|
|
||||||
public void Dispatch()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_server == null)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
|
|
||||||
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
|
|
||||||
|
|
||||||
var clientSpecificMessage = msgToSend as MobileControlMessage;
|
|
||||||
if (clientSpecificMessage.ClientId != null)
|
|
||||||
{
|
|
||||||
var clientId = clientSpecificMessage.ClientId;
|
|
||||||
|
|
||||||
_server.LogVerbose("Message TX To client {clientId} Message: {message}", clientId, message);
|
|
||||||
|
|
||||||
_server.SendMessageToClient(clientId, message);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_server.SendMessageToAllClients(message);
|
|
||||||
|
|
||||||
_server.LogVerbose("Message TX To all clients: {message}", message);
|
|
||||||
}
|
|
||||||
catch (ThreadAbortException)
|
|
||||||
{
|
|
||||||
//Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(ex, "Caught an exception in the Transmit Processor");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -3,12 +3,19 @@ using System;
|
|||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a UserCodeChanged
|
/// Defines the action to take when the User code changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UserCodeChanged
|
public class UserCodeChanged
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Action to take when the User Code changes
|
||||||
|
/// </summary>
|
||||||
public Action<string, string> UpdateUserCode { get; private set; }
|
public Action<string, string> UpdateUserCode { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// create an instance of the <see cref="UserCodeChanged"/> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="updateMethod">action to take when the User Code changes</param>
|
||||||
public UserCodeChanged(Action<string, string> updateMethod)
|
public UserCodeChanged(Action<string, string> updateMethod)
|
||||||
{
|
{
|
||||||
UpdateUserCode = updateMethod;
|
UpdateUserCode = updateMethod;
|
||||||
|
|||||||
97
src/PepperDash.Essentials.MobileControl/Utilities.cs
Normal file
97
src/PepperDash.Essentials.MobileControl/Utilities.cs
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Core.Logging;
|
||||||
|
using WebSocketSharp;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Utility functions for logging and other common tasks.
|
||||||
|
/// </summary>
|
||||||
|
public static class Utilities
|
||||||
|
{
|
||||||
|
private static int nextClientId = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the next unique client ID
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Client ID</returns>
|
||||||
|
public static int GetNextClientId()
|
||||||
|
{
|
||||||
|
nextClientId++;
|
||||||
|
return nextClientId;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a WebSocketServer LogData object to Essentials logging calls.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The LogData object to convert.</param>
|
||||||
|
/// <param name="message">The log message.</param>
|
||||||
|
/// <param name="device">The device associated with the log message.</param>
|
||||||
|
public static void ConvertWebsocketLog(LogData data, string message, IKeyed device = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (data.Level)
|
||||||
|
{
|
||||||
|
case LogLevel.Trace:
|
||||||
|
if (device == null)
|
||||||
|
{
|
||||||
|
Debug.LogVerbose(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device.LogVerbose(message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LogLevel.Debug:
|
||||||
|
if (device == null)
|
||||||
|
{
|
||||||
|
Debug.LogDebug(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device.LogDebug(message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LogLevel.Info:
|
||||||
|
if (device == null)
|
||||||
|
{
|
||||||
|
Debug.LogInformation(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device.LogInformation(message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LogLevel.Warn:
|
||||||
|
if (device == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device.LogWarning(message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LogLevel.Error:
|
||||||
|
if (device == null)
|
||||||
|
{
|
||||||
|
Debug.LogError(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device.LogError(message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LogLevel.Fatal:
|
||||||
|
if (device == null)
|
||||||
|
{
|
||||||
|
Debug.LogFatal(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
device.LogFatal(message);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,15 +15,17 @@ namespace PepperDash.Essentials
|
|||||||
[JsonProperty("master", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("master", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public Volume Master { get; set; }
|
public Volume Master { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aux Faders as configured in the room
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("auxFaders", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("auxFaders", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public Dictionary<string, Volume> AuxFaders { get; set; }
|
public Dictionary<string, Volume> AuxFaders { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Count of aux faders for this system
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("numberOfAuxFaders", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("numberOfAuxFaders", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public int? NumberOfAuxFaders { get; set; }
|
public int? NumberOfAuxFaders { get; set; }
|
||||||
|
|
||||||
public Volumes()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -31,16 +33,21 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Volume
|
public class Volume
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Key
|
/// Gets or sets the Key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Level for this volume object
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public int? Level { get; set; }
|
public int? Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if this volume control is muted
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? Muted { get; set; }
|
public bool? Muted { get; set; }
|
||||||
|
|
||||||
@@ -51,12 +58,21 @@ namespace PepperDash.Essentials
|
|||||||
[JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public string Label { get; set; }
|
public string Label { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if this volume object has mute control
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? HasMute { get; set; }
|
public bool? HasMute { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if this volume object has Privacy mute control
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("hasPrivacyMute", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("hasPrivacyMute", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? HasPrivacyMute { get; set; }
|
public bool? HasPrivacyMute { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if the privacy mute is muted
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("privacyMuted", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("privacyMuted", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public bool? PrivacyMuted { get; set; }
|
public bool? PrivacyMuted { get; set; }
|
||||||
|
|
||||||
@@ -68,6 +84,15 @@ namespace PepperDash.Essentials
|
|||||||
[JsonProperty("muteIcon", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("muteIcon", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public string MuteIcon { get; set; }
|
public string MuteIcon { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="Volume" /> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key for this volume object</param>
|
||||||
|
/// <param name="level">The level for this volume object</param>
|
||||||
|
/// <param name="muted">True if this volume control is muted</param>
|
||||||
|
/// <param name="label">The label for this volume object</param>
|
||||||
|
/// <param name="hasMute">True if this volume object has mute control</param>
|
||||||
|
/// <param name="muteIcon">The mute icon for this volume object</param>
|
||||||
public Volume(string key, int level, bool muted, string label, bool hasMute, string muteIcon)
|
public Volume(string key, int level, bool muted, string label, bool hasMute, string muteIcon)
|
||||||
: this(key)
|
: this(key)
|
||||||
{
|
{
|
||||||
@@ -78,18 +103,32 @@ namespace PepperDash.Essentials
|
|||||||
MuteIcon = muteIcon;
|
MuteIcon = muteIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="Volume" /> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key for this volume object</param>
|
||||||
|
/// <param name="level">The level for this volume object</param>
|
||||||
public Volume(string key, int level)
|
public Volume(string key, int level)
|
||||||
: this(key)
|
: this(key)
|
||||||
{
|
{
|
||||||
Level = level;
|
Level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="Volume" /> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key for this volume object</param>
|
||||||
|
/// <param name="muted">True if this volume control is muted</param>
|
||||||
public Volume(string key, bool muted)
|
public Volume(string key, bool muted)
|
||||||
: this(key)
|
: this(key)
|
||||||
{
|
{
|
||||||
Muted = muted;
|
Muted = muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="Volume" /> class
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key for this volume object</param>
|
||||||
public Volume(string key)
|
public Volume(string key)
|
||||||
{
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
|
|||||||
@@ -12,11 +12,20 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
public class ActionPathsHandler : WebApiBaseRequestHandler
|
public class ActionPathsHandler : WebApiBaseRequestHandler
|
||||||
{
|
{
|
||||||
private readonly MobileControlSystemController mcController;
|
private readonly MobileControlSystemController mcController;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="ActionPathsHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controller"></param>
|
||||||
public ActionPathsHandler(MobileControlSystemController controller) : base(true)
|
public ActionPathsHandler(MobileControlSystemController controller) : base(true)
|
||||||
{
|
{
|
||||||
mcController = controller;
|
mcController = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle a request to get the action paths
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">Request Context</param>
|
||||||
protected override void HandleGet(HttpCwsContext context)
|
protected override void HandleGet(HttpCwsContext context)
|
||||||
{
|
{
|
||||||
var response = JsonConvert.SerializeObject(new ActionPathsResponse(mcController));
|
var response = JsonConvert.SerializeObject(new ActionPathsResponse(mcController));
|
||||||
@@ -37,9 +46,16 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
private readonly MobileControlSystemController mcController;
|
private readonly MobileControlSystemController mcController;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registered action paths for this system
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("actionPaths")]
|
[JsonProperty("actionPaths")]
|
||||||
public List<ActionPath> ActionPaths => mcController.GetActionDictionaryPaths().Select((path) => new ActionPath { MessengerKey = path.Item1, Path = path.Item2 }).ToList();
|
public List<ActionPath> ActionPaths => mcController.GetActionDictionaryPaths().Select((path) => new ActionPath { MessengerKey = path.Item1, Path = path.Item2 }).ToList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="ActionPathsResponse"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mcController"></param>
|
||||||
public ActionPathsResponse(MobileControlSystemController mcController)
|
public ActionPathsResponse(MobileControlSystemController mcController)
|
||||||
{
|
{
|
||||||
this.mcController = mcController;
|
this.mcController = mcController;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using Crestron.SimplSharp.WebScripting;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Crestron.SimplSharp.WebScripting;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Core.Web.RequestHandlers;
|
using PepperDash.Core.Web.RequestHandlers;
|
||||||
using PepperDash.Essentials.Core.Web;
|
using PepperDash.Essentials.Core.Web;
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.WebApiHandlers
|
namespace PepperDash.Essentials.WebApiHandlers
|
||||||
{
|
{
|
||||||
@@ -15,11 +15,20 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
{
|
{
|
||||||
private readonly MobileControlSystemController mcController;
|
private readonly MobileControlSystemController mcController;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileAuthRequestHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controller"></param>
|
||||||
public MobileAuthRequestHandler(MobileControlSystemController controller) : base(true)
|
public MobileAuthRequestHandler(MobileControlSystemController controller) : base(true)
|
||||||
{
|
{
|
||||||
mcController = controller;
|
mcController = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle authorization request for this processor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">request context</param>
|
||||||
|
/// <returns>Task</returns>
|
||||||
protected override async Task HandlePost(HttpCwsContext context)
|
protected override async Task HandlePost(HttpCwsContext context)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -1,26 +1,35 @@
|
|||||||
using Crestron.SimplSharp.WebScripting;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Crestron.SimplSharp.WebScripting;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Core.Web.RequestHandlers;
|
using PepperDash.Core.Web.RequestHandlers;
|
||||||
using PepperDash.Essentials.Core.Config;
|
using PepperDash.Essentials.Core.Config;
|
||||||
using PepperDash.Essentials.WebSocketServer;
|
using PepperDash.Essentials.WebSocketServer;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.WebApiHandlers
|
namespace PepperDash.Essentials.WebApiHandlers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a MobileInfoHandler
|
/// Represents a MobileInfoHandler. Used with the Essentials CWS API
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MobileInfoHandler : WebApiBaseRequestHandler
|
public class MobileInfoHandler : WebApiBaseRequestHandler
|
||||||
{
|
{
|
||||||
private readonly MobileControlSystemController mcController;
|
private readonly MobileControlSystemController mcController;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileInfoHandler"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controller"></param>
|
||||||
public MobileInfoHandler(MobileControlSystemController controller) : base(true)
|
public MobileInfoHandler(MobileControlSystemController controller) : base(true)
|
||||||
{
|
{
|
||||||
mcController = controller;
|
mcController = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Mobile Control Information
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
protected override void HandleGet(HttpCwsContext context)
|
protected override void HandleGet(HttpCwsContext context)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -50,14 +59,22 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
private readonly MobileControlSystemController mcController;
|
private readonly MobileControlSystemController mcController;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Edge Server. Null if edge server is disabled
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("edgeServer", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("edgeServer", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public MobileControlEdgeServer EdgeServer => mcController.Config.EnableApiServer ? new MobileControlEdgeServer(mcController) : null;
|
public MobileControlEdgeServer EdgeServer => mcController.Config.EnableApiServer ? new MobileControlEdgeServer(mcController) : null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Direct server. Null if the direct server is disabled
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("directServer", NullValueHandling = NullValueHandling.Ignore)]
|
[JsonProperty("directServer", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
public MobileControlDirectServer DirectServer => mcController.Config.DirectServer.EnableDirectServer ? new MobileControlDirectServer(mcController.DirectServer) : null;
|
public MobileControlDirectServer DirectServer => mcController.Config.DirectServer.EnableDirectServer ? new MobileControlDirectServer(mcController.DirectServer) : null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="InformationResponse"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controller"></param>
|
||||||
public InformationResponse(MobileControlSystemController controller)
|
public InformationResponse(MobileControlSystemController controller)
|
||||||
{
|
{
|
||||||
mcController = controller;
|
mcController = controller;
|
||||||
@@ -72,24 +89,46 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
private readonly MobileControlSystemController mcController;
|
private readonly MobileControlSystemController mcController;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mobile Control Edge Server address for this system
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("serverAddress")]
|
[JsonProperty("serverAddress")]
|
||||||
public string ServerAddress => mcController.Config == null ? "No Config" : mcController.Host;
|
public string ServerAddress => mcController.Config == null ? "No Config" : mcController.Host;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System Name for this system
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("systemName")]
|
[JsonProperty("systemName")]
|
||||||
public string SystemName => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].RoomName : "No Config";
|
public string SystemName => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].RoomName : "No Config";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System URL for this system
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("systemUrl")]
|
[JsonProperty("systemUrl")]
|
||||||
public string SystemUrl => ConfigReader.ConfigObject.SystemUrl;
|
public string SystemUrl => ConfigReader.ConfigObject.SystemUrl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// User code to use in MC UI for this system
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("userCode")]
|
[JsonProperty("userCode")]
|
||||||
public string UserCode => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].UserCode : "Not available";
|
public string UserCode => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].UserCode : "Not available";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if connected to edge server
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("connected")]
|
[JsonProperty("connected")]
|
||||||
public bool Connected => mcController.Connected;
|
public bool Connected => mcController.Connected;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Seconds since last comms with edge server
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("secondsSinceLastAck")]
|
[JsonProperty("secondsSinceLastAck")]
|
||||||
public int SecondsSinceLastAck => (DateTime.Now - mcController.LastAckMessage).Seconds;
|
public int SecondsSinceLastAck => (DateTime.Now - mcController.LastAckMessage).Seconds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileControlEdgeServer"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controller">controller to use for this</param>
|
||||||
public MobileControlEdgeServer(MobileControlSystemController controller)
|
public MobileControlEdgeServer(MobileControlSystemController controller)
|
||||||
{
|
{
|
||||||
mcController = controller;
|
mcController = controller;
|
||||||
@@ -104,21 +143,43 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
private readonly MobileControlWebsocketServer directServer;
|
private readonly MobileControlWebsocketServer directServer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL to use to interact with this server
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("userAppUrl")]
|
[JsonProperty("userAppUrl")]
|
||||||
public string UserAppUrl => $"{directServer.UserAppUrlPrefix}/[insert_client_token]";
|
public string UserAppUrl => $"{directServer.UserAppUrlPrefix}/[insert_client_token]";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// TCP/IP Port this server is configured to use
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("serverPort")]
|
[JsonProperty("serverPort")]
|
||||||
public int ServerPort => directServer.Port;
|
public int ServerPort => directServer.Port;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Count of defined tokens for this server
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("tokensDefined")]
|
[JsonProperty("tokensDefined")]
|
||||||
public int TokensDefined => directServer.UiClients.Count;
|
public int TokensDefined => directServer.UiClientContexts.Count;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Count of connected clients
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("clientsConnected")]
|
[JsonProperty("clientsConnected")]
|
||||||
public int ClientsConnected => directServer.ConnectedUiClientsCount;
|
public int ClientsConnected => directServer.ConnectedUiClientsCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of tokens and connected clients for this server
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("clients")]
|
[JsonProperty("clients")]
|
||||||
public List<MobileControlDirectClient> Clients => directServer.UiClients.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList();
|
public List<MobileControlDirectClient> Clients => directServer.UiClientContexts
|
||||||
|
.Select(context => (context, clients: directServer.UiClients.Where(client => client.Value.Token == context.Value.Token.Token).Select(c => c.Value).ToList()))
|
||||||
|
.Select((clientTuple, i) => new MobileControlDirectClient(clientTuple.clients, clientTuple.context, i, directServer.UserAppUrlPrefix))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileControlDirectServer"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="server"></param>
|
||||||
public MobileControlDirectServer(MobileControlWebsocketServer server)
|
public MobileControlDirectServer(MobileControlWebsocketServer server)
|
||||||
{
|
{
|
||||||
directServer = server;
|
directServer = server;
|
||||||
@@ -142,33 +203,85 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
private readonly string urlPrefix;
|
private readonly string urlPrefix;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Client number for this client
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("clientNumber")]
|
[JsonProperty("clientNumber")]
|
||||||
public string ClientNumber => $"{clientNumber}";
|
public string ClientNumber => $"{clientNumber}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Room Key for this client
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("roomKey")]
|
[JsonProperty("roomKey")]
|
||||||
public string RoomKey => context.Token.RoomKey;
|
public string RoomKey => context.Token.RoomKey;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Touchpanel Key, if defined, for this client
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("touchpanelKey")]
|
[JsonProperty("touchpanelKey")]
|
||||||
public string TouchpanelKey => context.Token.TouchpanelKey;
|
public string TouchpanelKey => context.Token.TouchpanelKey;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL for this client
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("url")]
|
[JsonProperty("url")]
|
||||||
public string Url => $"{urlPrefix}{Key}";
|
public string Url => $"{urlPrefix}{Key}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Token for this client
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("token")]
|
[JsonProperty("token")]
|
||||||
public string Token => Key;
|
public string Token => Key;
|
||||||
|
|
||||||
[JsonProperty("connected")]
|
private readonly List<UiClient> clients;
|
||||||
public bool Connected => context.Client != null && context.Client.Context.WebSocket.IsAlive;
|
|
||||||
|
|
||||||
[JsonProperty("duration")]
|
/// <summary>
|
||||||
public double Duration => context.Client == null ? 0 : context.Client.ConnectedDuration.TotalSeconds;
|
/// List of status for all connected UI Clients
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("clientStatus")]
|
||||||
|
public List<ClientStatus> ClientStatus => clients.Select(c => new ClientStatus(c)).ToList();
|
||||||
|
|
||||||
public MobileControlDirectClient(KeyValuePair<string, UiClientContext> clientContext, int index, string urlPrefix)
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="MobileControlDirectClient"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clients">List of Websocket Clients</param>
|
||||||
|
/// <param name="context">Context for the client</param>
|
||||||
|
/// <param name="index">Index of the client</param>
|
||||||
|
/// <param name="urlPrefix">URL prefix for the client</param>
|
||||||
|
public MobileControlDirectClient(List<UiClient> clients, KeyValuePair<string, UiClientContext> context, int index, string urlPrefix)
|
||||||
{
|
{
|
||||||
context = clientContext.Value;
|
this.context = context.Value;
|
||||||
Key = clientContext.Key;
|
Key = context.Key;
|
||||||
clientNumber = index;
|
clientNumber = index;
|
||||||
this.urlPrefix = urlPrefix;
|
this.urlPrefix = urlPrefix;
|
||||||
|
this.clients = clients;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Report the status of a UiClient
|
||||||
|
/// </summary>
|
||||||
|
public class ClientStatus
|
||||||
|
{
|
||||||
|
private readonly UiClient client;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if client is connected
|
||||||
|
/// </summary>
|
||||||
|
public bool Connected => client != null && client.Context.WebSocket.IsAlive;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the time this client has been connected
|
||||||
|
/// </summary>
|
||||||
|
public double Duration => client == null ? 0 : client.ConnectedDuration.TotalSeconds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create an instance of the <see cref="ClientStatus"/> class for the specified client
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">client to report on</param>
|
||||||
|
public ClientStatus(UiClient client)
|
||||||
|
{
|
||||||
|
this.client = client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,20 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
public class UiClientHandler : WebApiBaseRequestHandler
|
public class UiClientHandler : WebApiBaseRequestHandler
|
||||||
{
|
{
|
||||||
private readonly MobileControlWebsocketServer server;
|
private readonly MobileControlWebsocketServer server;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Essentials CWS API handler for the MC Direct Server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="directServer">Direct Server instance</param>
|
||||||
public UiClientHandler(MobileControlWebsocketServer directServer) : base(true)
|
public UiClientHandler(MobileControlWebsocketServer directServer) : base(true)
|
||||||
{
|
{
|
||||||
server = directServer;
|
server = directServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a client for the Direct Server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">HTTP Context for this request</param>
|
||||||
protected override void HandlePost(HttpCwsContext context)
|
protected override void HandlePost(HttpCwsContext context)
|
||||||
{
|
{
|
||||||
var req = context.Request;
|
var req = context.Request;
|
||||||
@@ -65,6 +74,10 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
res.End();
|
res.End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handle DELETE request for a Client
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
protected override void HandleDelete(HttpCwsContext context)
|
protected override void HandleDelete(HttpCwsContext context)
|
||||||
{
|
{
|
||||||
var req = context.Request;
|
var req = context.Request;
|
||||||
@@ -93,7 +106,7 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!server.UiClients.TryGetValue(request.Token, out UiClientContext clientContext))
|
if (!server.UiClientContexts.TryGetValue(request.Token, out UiClientContext clientContext))
|
||||||
{
|
{
|
||||||
var response = new ClientResponse
|
var response = new ClientResponse
|
||||||
{
|
{
|
||||||
@@ -134,7 +147,7 @@ namespace PepperDash.Essentials.WebApiHandlers
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
server.UiClients.Remove(request.Token);
|
server.UiClientContexts.Remove(request.Token);
|
||||||
|
|
||||||
server.UpdateSecret();
|
server.UpdateSecret();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.WebSocketServer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Event Args for <see cref="UiClient"/> ConnectionClosed event
|
||||||
|
/// </summary>
|
||||||
|
public class ConnectionClosedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Client ID that is being closed
|
||||||
|
/// </summary>
|
||||||
|
public string ClientId { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize an instance of the <see cref="ConnectionClosedEventArgs"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clientId">client that's closing</param>
|
||||||
|
public ConnectionClosedEventArgs(string clientId)
|
||||||
|
{
|
||||||
|
ClientId = clientId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,9 +17,15 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
[JsonProperty("clientId")]
|
[JsonProperty("clientId")]
|
||||||
public string ClientId { get; set; }
|
public string ClientId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Room Key for this client
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("roomKey")]
|
[JsonProperty("roomKey")]
|
||||||
public string RoomKey { get; set; }
|
public string RoomKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System UUID for this system
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("systemUUid")]
|
[JsonProperty("systemUUid")]
|
||||||
public string SystemUuid { get; set; }
|
public string SystemUuid { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,28 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class JoinToken
|
public class JoinToken
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Unique client ID for a client that is joining
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Code
|
/// Gets or sets the Code
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Code { get; set; }
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Room Key this token is associated with
|
||||||
|
/// </summary>
|
||||||
public string RoomKey { get; set; }
|
public string RoomKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unique ID for this token
|
||||||
|
/// </summary>
|
||||||
public string Uuid { get; set; }
|
public string Uuid { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Touchpanel Key this token is associated with, if this is a touch panel token
|
||||||
|
/// </summary>
|
||||||
public string TouchpanelKey { get; set; } = "";
|
public string TouchpanelKey { get; set; } = "";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Text;
|
|||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.WebScripting;
|
using Crestron.SimplSharp.WebScripting;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Org.BouncyCastle.Crypto.Prng;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Core.Logging;
|
using PepperDash.Core.Logging;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
@@ -56,7 +57,14 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of UI client contexts
|
/// Gets the collection of UI client contexts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, UiClientContext> UiClients { get; private set; }
|
public Dictionary<string, UiClientContext> UiClientContexts { get; private set; }
|
||||||
|
|
||||||
|
private readonly Dictionary<string, UiClient> uiClients = new Dictionary<string, UiClient>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the collection of UI clients
|
||||||
|
/// </summary>
|
||||||
|
public ReadOnlyDictionary<string, UiClient> UiClients => new ReadOnlyDictionary<string, UiClient>(uiClients);
|
||||||
|
|
||||||
private readonly MobileControlSystemController _parent;
|
private readonly MobileControlSystemController _parent;
|
||||||
|
|
||||||
@@ -127,17 +135,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var count = 0;
|
return uiClients.Values.Where(c => c.Context.WebSocket.IsAlive).Count();
|
||||||
|
|
||||||
foreach (var client in UiClients)
|
|
||||||
{
|
|
||||||
if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +200,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UiClients = new Dictionary<string, UiClientContext>();
|
UiClientContexts = new Dictionary<string, UiClientContext>();
|
||||||
|
|
||||||
//_joinTokens = new Dictionary<string, JoinToken>();
|
//_joinTokens = new Dictionary<string, JoinToken>();
|
||||||
|
|
||||||
@@ -277,30 +275,10 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_server.Log.Output = (data, message) =>
|
_server.Log.Output = (data, message) => Utilities.ConvertWebsocketLog(data, message, this);
|
||||||
{
|
|
||||||
switch (data.Level)
|
// setting to trace to allow logging level to be controlled by appdebug
|
||||||
{
|
_server.Log.Level = LogLevel.Trace;
|
||||||
case LogLevel.Trace:
|
|
||||||
this.LogVerbose(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Debug:
|
|
||||||
this.LogDebug(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Info:
|
|
||||||
this.LogInformation(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Warn:
|
|
||||||
this.LogWarning(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Error:
|
|
||||||
this.LogError(data.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Fatal:
|
|
||||||
this.LogFatal(data.Message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
|
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
|
||||||
|
|
||||||
@@ -326,6 +304,9 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the internal logging level for the Websocket Server
|
||||||
|
/// </summary>
|
||||||
public void SetWebsocketLogLevel(LogLevel level)
|
public void SetWebsocketLogLevel(LogLevel level)
|
||||||
{
|
{
|
||||||
CrestronConsole.ConsoleCommandResponse($"Setting direct server debug level to {level}", level.ToString());
|
CrestronConsole.ConsoleCommandResponse($"Setting direct server debug level to {level}", level.ToString());
|
||||||
@@ -404,9 +385,9 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}";
|
var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}";
|
||||||
|
|
||||||
this.LogVerbose("Sending URL {appUrl}", appUrl);
|
this.LogVerbose("Sending URL {appUrl} to touchpanel {touchpanelKey}", appUrl, touchpanel.Touchpanel.Key);
|
||||||
|
|
||||||
touchpanel.Messenger.UpdateAppUrl($"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}");
|
touchpanel.Touchpanel.SetAppUrl($"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,20 +535,20 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
this.LogInformation("Adding token: {key} for room: {roomKey}", token.Key, token.Value.RoomKey);
|
this.LogInformation("Adding token: {key} for room: {roomKey}", token.Key, token.Value.RoomKey);
|
||||||
|
|
||||||
if (UiClients == null)
|
if (UiClientContexts == null)
|
||||||
{
|
{
|
||||||
UiClients = new Dictionary<string, UiClientContext>();
|
UiClientContexts = new Dictionary<string, UiClientContext>();
|
||||||
}
|
}
|
||||||
|
|
||||||
UiClients.Add(token.Key, new UiClientContext(token.Value));
|
UiClientContexts.Add(token.Key, new UiClientContext(token.Value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UiClients.Count > 0)
|
if (UiClientContexts.Count > 0)
|
||||||
{
|
{
|
||||||
this.LogInformation("Restored {uiClientCount} UiClients from secrets data", UiClients.Count);
|
this.LogInformation("Restored {uiClientCount} UiClients from secrets data", UiClientContexts.Count);
|
||||||
|
|
||||||
foreach (var client in UiClients)
|
foreach (var client in UiClientContexts)
|
||||||
{
|
{
|
||||||
var key = client.Key;
|
var key = client.Key;
|
||||||
var path = _wsPath + key;
|
var path = _wsPath + key;
|
||||||
@@ -575,13 +556,8 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
_server.AddWebSocketService(path, () =>
|
_server.AddWebSocketService(path, () =>
|
||||||
{
|
{
|
||||||
var c = new UiClient($"uiclient-{key}-{roomKey}");
|
this.LogInformation("Building a UiClient with ID {id}", client.Value.Token.Id);
|
||||||
this.LogDebug("Constructing UiClient with id: {key}", key);
|
return BuildUiClient(roomKey, client.Value.Token, key);
|
||||||
|
|
||||||
c.Controller = _parent;
|
|
||||||
c.RoomKey = roomKey;
|
|
||||||
UiClients[key].SetClient(c);
|
|
||||||
return c;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -591,7 +567,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
this.LogWarning("No secret found");
|
this.LogWarning("No secret found");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.LogDebug("{uiClientCount} UiClients restored from secrets data", UiClients.Count);
|
this.LogDebug("{uiClientCount} UiClients restored from secrets data", UiClientContexts.Count);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -616,7 +592,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
_secret.Tokens.Clear();
|
_secret.Tokens.Clear();
|
||||||
|
|
||||||
foreach (var uiClientContext in UiClients)
|
foreach (var uiClientContext in UiClientContexts)
|
||||||
{
|
{
|
||||||
_secret.Tokens.Add(uiClientContext.Key, uiClientContext.Value.Token);
|
_secret.Tokens.Add(uiClientContext.Key, uiClientContext.Value.Token);
|
||||||
}
|
}
|
||||||
@@ -725,21 +701,17 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
var token = new JoinToken { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid, TouchpanelKey = touchPanelKey };
|
var token = new JoinToken { Code = bridge.UserCode, RoomKey = bridge.RoomKey, Uuid = _parent.SystemUuid, TouchpanelKey = touchPanelKey };
|
||||||
|
|
||||||
UiClients.Add(key, new UiClientContext(token));
|
UiClientContexts.Add(key, new UiClientContext(token));
|
||||||
|
|
||||||
var path = _wsPath + key;
|
var path = _wsPath + key;
|
||||||
|
|
||||||
_server.AddWebSocketService(path, () =>
|
_server.AddWebSocketService(path, () =>
|
||||||
{
|
{
|
||||||
var c = new UiClient($"uiclient-{key}-{bridge.RoomKey}");
|
this.LogInformation("Building a UiClient with ID {id}", token.Id);
|
||||||
this.LogVerbose("Constructing UiClient with id: {key}", key);
|
return BuildUiClient(bridge.RoomKey, token, key);
|
||||||
c.Controller = _parent;
|
|
||||||
c.RoomKey = bridge.RoomKey;
|
|
||||||
UiClients[key].SetClient(c);
|
|
||||||
return c;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.LogInformation("Added new WebSocket UiClient service at path: {path}", path);
|
this.LogInformation("Added new WebSocket UiClient for path: {path}", path);
|
||||||
this.LogInformation("Token: {@token}", token);
|
this.LogInformation("Token: {@token}", token);
|
||||||
|
|
||||||
this.LogVerbose("{serviceCount} websocket services present", _server.WebSocketServices.Count);
|
this.LogVerbose("{serviceCount} websocket services present", _server.WebSocketServices.Count);
|
||||||
@@ -749,6 +721,44 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
return (key, path);
|
return (key, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UiClient BuildUiClient(string roomKey, JoinToken token, string key)
|
||||||
|
{
|
||||||
|
var c = new UiClient($"uiclient-{key}-{roomKey}-{token.Id}", token.Id, token.Token, token.TouchpanelKey);
|
||||||
|
this.LogInformation("Constructing UiClient with key {key} and ID {id}", key, token.Id);
|
||||||
|
c.Controller = _parent;
|
||||||
|
c.RoomKey = roomKey;
|
||||||
|
|
||||||
|
if (uiClients.ContainsKey(token.Id))
|
||||||
|
{
|
||||||
|
this.LogWarning("removing client with duplicate id {id}", token.Id);
|
||||||
|
uiClients.Remove(token.Id);
|
||||||
|
}
|
||||||
|
uiClients.Add(token.Id, c);
|
||||||
|
// UiClients[key].SetClient(c);
|
||||||
|
c.ConnectionClosed += (o, a) => uiClients.Remove(a.ClientId);
|
||||||
|
token.Id = null;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prints out the session data for each path
|
||||||
|
/// </summary>
|
||||||
|
public void PrintSessionData()
|
||||||
|
{
|
||||||
|
foreach (var path in _server.WebSocketServices.Paths)
|
||||||
|
{
|
||||||
|
this.LogInformation("Path: {path}", path);
|
||||||
|
this.LogInformation(" Session Count: {sessionCount}", _server.WebSocketServices[path].Sessions.Count);
|
||||||
|
this.LogInformation(" Active Session Count: {activeSessionCount}", _server.WebSocketServices[path].Sessions.ActiveIDs.Count());
|
||||||
|
this.LogInformation(" Inactive Session Count: {inactiveSessionCount}", _server.WebSocketServices[path].Sessions.InactiveIDs.Count());
|
||||||
|
this.LogInformation(" Active Clients:");
|
||||||
|
foreach (var session in _server.WebSocketServices[path].Sessions.IDs)
|
||||||
|
{
|
||||||
|
this.LogInformation(" Client ID: {id}", (_server.WebSocketServices[path].Sessions[session] as UiClient)?.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes all clients from the server
|
/// Removes all clients from the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -766,7 +776,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var client in UiClients)
|
foreach (var client in UiClientContexts)
|
||||||
{
|
{
|
||||||
if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive)
|
if (client.Value.Client != null && client.Value.Client.Context.WebSocket.IsAlive)
|
||||||
{
|
{
|
||||||
@@ -784,7 +794,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UiClients.Clear();
|
UiClientContexts.Clear();
|
||||||
|
|
||||||
UpdateSecret();
|
UpdateSecret();
|
||||||
}
|
}
|
||||||
@@ -803,9 +813,9 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
var key = s;
|
var key = s;
|
||||||
|
|
||||||
if (UiClients.ContainsKey(key))
|
if (UiClientContexts.ContainsKey(key))
|
||||||
{
|
{
|
||||||
var uiClientContext = UiClients[key];
|
var uiClientContext = UiClientContexts[key];
|
||||||
|
|
||||||
if (uiClientContext.Client != null && uiClientContext.Client.Context.WebSocket.IsAlive)
|
if (uiClientContext.Client != null && uiClientContext.Client.Context.WebSocket.IsAlive)
|
||||||
{
|
{
|
||||||
@@ -815,7 +825,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
var path = _wsPath + key;
|
var path = _wsPath + key;
|
||||||
if (_server.RemoveWebSocketService(path))
|
if (_server.RemoveWebSocketService(path))
|
||||||
{
|
{
|
||||||
UiClients.Remove(key);
|
UiClientContexts.Remove(key);
|
||||||
|
|
||||||
UpdateSecret();
|
UpdateSecret();
|
||||||
|
|
||||||
@@ -839,9 +849,9 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
{
|
{
|
||||||
CrestronConsole.ConsoleCommandResponse("Mobile Control UI Client Info:\r");
|
CrestronConsole.ConsoleCommandResponse("Mobile Control UI Client Info:\r");
|
||||||
|
|
||||||
CrestronConsole.ConsoleCommandResponse(string.Format("{0} clients found:\r", UiClients.Count));
|
CrestronConsole.ConsoleCommandResponse(string.Format("{0} clients found:\r", UiClientContexts.Count));
|
||||||
|
|
||||||
foreach (var client in UiClients)
|
foreach (var client in UiClientContexts)
|
||||||
{
|
{
|
||||||
CrestronConsole.ConsoleCommandResponse(string.Format("RoomKey: {0} Token: {1}\r", client.Value.Token.RoomKey, client.Key));
|
CrestronConsole.ConsoleCommandResponse(string.Format("RoomKey: {0} Token: {1}\r", client.Value.Token.RoomKey, client.Key));
|
||||||
}
|
}
|
||||||
@@ -853,9 +863,9 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
{
|
{
|
||||||
foreach (var client in UiClients.Values)
|
foreach (var client in UiClients.Values)
|
||||||
{
|
{
|
||||||
if (client.Client != null && client.Client.Context.WebSocket.IsAlive)
|
if (client != null && client.Context.WebSocket.IsAlive)
|
||||||
{
|
{
|
||||||
client.Client.Context.WebSocket.Close(CloseStatusCode.Normal, "Server Shutting Down");
|
client.Context.WebSocket.Close(CloseStatusCode.Normal, "Server Shutting Down");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -990,77 +1000,81 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
this.LogVerbose("Join Room Request with token: {token}", token);
|
this.LogVerbose("Join Room Request with token: {token}", token);
|
||||||
|
|
||||||
|
byte[] body;
|
||||||
|
|
||||||
if (UiClients.TryGetValue(token, out UiClientContext clientContext))
|
if (!UiClientContexts.TryGetValue(token, out UiClientContext clientContext))
|
||||||
{
|
|
||||||
var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey);
|
|
||||||
|
|
||||||
if (bridge != null)
|
|
||||||
{
|
|
||||||
res.StatusCode = 200;
|
|
||||||
res.ContentType = "application/json";
|
|
||||||
|
|
||||||
var devices = DeviceManager.GetDevices();
|
|
||||||
Dictionary<string, DeviceInterfaceInfo> deviceInterfaces = new Dictionary<string, DeviceInterfaceInfo>();
|
|
||||||
|
|
||||||
foreach (var device in devices)
|
|
||||||
{
|
|
||||||
var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List<string>();
|
|
||||||
deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo
|
|
||||||
{
|
|
||||||
Key = device.Key,
|
|
||||||
Name = device is IKeyName ? (device as IKeyName).Name : "",
|
|
||||||
Interfaces = interfaces
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the response object
|
|
||||||
JoinResponse jRes = new JoinResponse
|
|
||||||
{
|
|
||||||
ClientId = token,
|
|
||||||
RoomKey = bridge.RoomKey,
|
|
||||||
SystemUuid = _parent.SystemUuid,
|
|
||||||
RoomUuid = _parent.SystemUuid,
|
|
||||||
Config = _parent.GetConfigWithPluginVersion(),
|
|
||||||
CodeExpires = new DateTime().AddYears(1),
|
|
||||||
UserCode = bridge.UserCode,
|
|
||||||
UserAppUrl = string.Format("http://{0}:{1}/mc/app",
|
|
||||||
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
|
|
||||||
Port),
|
|
||||||
EnableDebug = false,
|
|
||||||
DeviceInterfaceSupport = deviceInterfaces
|
|
||||||
};
|
|
||||||
|
|
||||||
// Serialize to JSON and convert to Byte[]
|
|
||||||
var json = JsonConvert.SerializeObject(jRes);
|
|
||||||
var body = Encoding.UTF8.GetBytes(json);
|
|
||||||
res.ContentLength64 = body.LongLength;
|
|
||||||
|
|
||||||
// Send the response
|
|
||||||
res.Close(body, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var message = string.Format("Unable to find bridge with key: {0}", clientContext.Token.RoomKey);
|
|
||||||
res.StatusCode = 404;
|
|
||||||
res.ContentType = "application/json";
|
|
||||||
this.LogVerbose("{message}", message);
|
|
||||||
var body = Encoding.UTF8.GetBytes(message);
|
|
||||||
res.ContentLength64 = body.LongLength;
|
|
||||||
res.Close(body, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
var message = "Token invalid or has expired";
|
var message = "Token invalid or has expired";
|
||||||
res.StatusCode = 401;
|
res.StatusCode = 401;
|
||||||
res.ContentType = "application/json";
|
res.ContentType = "application/json";
|
||||||
this.LogVerbose("{message}", message);
|
this.LogVerbose("{message}", message);
|
||||||
var body = Encoding.UTF8.GetBytes(message);
|
body = Encoding.UTF8.GetBytes(message);
|
||||||
res.ContentLength64 = body.LongLength;
|
res.ContentLength64 = body.LongLength;
|
||||||
res.Close(body, true);
|
res.Close(body, true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bridge = _parent.GetRoomBridge(clientContext.Token.RoomKey);
|
||||||
|
|
||||||
|
if (bridge == null)
|
||||||
|
{
|
||||||
|
var message = string.Format("Unable to find bridge with key: {0}", clientContext.Token.RoomKey);
|
||||||
|
res.StatusCode = 404;
|
||||||
|
res.ContentType = "application/json";
|
||||||
|
this.LogVerbose("{message}", message);
|
||||||
|
body = Encoding.UTF8.GetBytes(message);
|
||||||
|
res.ContentLength64 = body.LongLength;
|
||||||
|
res.Close(body, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.StatusCode = 200;
|
||||||
|
res.ContentType = "application/json";
|
||||||
|
|
||||||
|
var devices = DeviceManager.GetDevices();
|
||||||
|
Dictionary<string, DeviceInterfaceInfo> deviceInterfaces = new Dictionary<string, DeviceInterfaceInfo>();
|
||||||
|
|
||||||
|
foreach (var device in devices)
|
||||||
|
{
|
||||||
|
var interfaces = device?.GetType().GetInterfaces().Select((i) => i.Name).ToList() ?? new List<string>();
|
||||||
|
|
||||||
|
deviceInterfaces.Add(device.Key, new DeviceInterfaceInfo
|
||||||
|
{
|
||||||
|
Key = device.Key,
|
||||||
|
Name = (device as IKeyName)?.Name ?? "",
|
||||||
|
Interfaces = interfaces
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var clientId = $"{Utilities.GetNextClientId()}";
|
||||||
|
clientContext.Token.Id = clientId;
|
||||||
|
|
||||||
|
this.LogVerbose("Assigning ClientId: {clientId}", clientId);
|
||||||
|
|
||||||
|
// Construct the response object
|
||||||
|
JoinResponse jRes = new JoinResponse
|
||||||
|
{
|
||||||
|
ClientId = clientId,
|
||||||
|
RoomKey = bridge.RoomKey,
|
||||||
|
SystemUuid = _parent.SystemUuid,
|
||||||
|
RoomUuid = _parent.SystemUuid,
|
||||||
|
Config = _parent.GetConfigWithPluginVersion(),
|
||||||
|
CodeExpires = new DateTime().AddYears(1),
|
||||||
|
UserCode = bridge.UserCode,
|
||||||
|
UserAppUrl = string.Format("http://{0}:{1}/mc/app",
|
||||||
|
CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0),
|
||||||
|
Port),
|
||||||
|
EnableDebug = false,
|
||||||
|
DeviceInterfaceSupport = deviceInterfaces
|
||||||
|
};
|
||||||
|
|
||||||
|
// Serialize to JSON and convert to Byte[]
|
||||||
|
var json = JsonConvert.SerializeObject(jRes);
|
||||||
|
body = Encoding.UTF8.GetBytes(json);
|
||||||
|
res.ContentLength64 = body.LongLength;
|
||||||
|
|
||||||
|
// Send the response
|
||||||
|
res.Close(body, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1242,12 +1256,14 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendMessageToAllClients(string message)
|
public void SendMessageToAllClients(string message)
|
||||||
{
|
{
|
||||||
foreach (var clientContext in UiClients.Values)
|
foreach (var client in uiClients.Values)
|
||||||
{
|
{
|
||||||
if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive)
|
if (!client.Context.WebSocket.IsAlive)
|
||||||
{
|
{
|
||||||
clientContext.Client.Context.WebSocket.Send(message);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client.Context.WebSocket.Send(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1266,17 +1282,16 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UiClients.TryGetValue((string)clientId, out UiClientContext clientContext))
|
if (uiClients.TryGetValue((string)clientId, out var client))
|
||||||
{
|
{
|
||||||
if (clientContext.Client != null)
|
var socket = client.Context.WebSocket;
|
||||||
{
|
|
||||||
var socket = clientContext.Client.Context.WebSocket;
|
|
||||||
|
|
||||||
if (socket.IsAlive)
|
if (!socket.IsAlive)
|
||||||
{
|
{
|
||||||
socket.Send(message);
|
this.LogError("Unable to send message to client {id}. Client is disconnected: {message}", clientId, message);
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
socket.Send(message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,8 +13,15 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string GrantCode { get; set; }
|
public string GrantCode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Tokens for this server
|
||||||
|
/// </summary>
|
||||||
public Dictionary<string, JoinToken> Tokens { get; set; }
|
public Dictionary<string, JoinToken> Tokens { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize a new instance of the <see cref="ServerTokenSecrets"/> class with the provided grant code
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grantCode">The grant code for this server</param>
|
||||||
public ServerTokenSecrets(string grantCode)
|
public ServerTokenSecrets(string grantCode)
|
||||||
{
|
{
|
||||||
GrantCode = grantCode;
|
GrantCode = grantCode;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
@@ -22,6 +21,21 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Key { get; private set; }
|
public string Key { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Client ID used by client for this connection
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Token associated with this client
|
||||||
|
/// </summary>
|
||||||
|
public string Token { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Touchpanel Key associated with this client
|
||||||
|
/// </summary>
|
||||||
|
public string TouchpanelKey { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the mobile control system controller that handles this client's messages
|
/// Gets or sets the mobile control system controller that handles this client's messages
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -32,11 +46,6 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string RoomKey { get; set; }
|
public string RoomKey { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The unique identifier for this client instance
|
|
||||||
/// </summary>
|
|
||||||
private string _clientId;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The timestamp when this client connection was established
|
/// The timestamp when this client connection was established
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -60,13 +69,24 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggered when this client closes it's connection
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<ConnectionClosedEventArgs> ConnectionClosed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the UiClient class with the specified key
|
/// Initializes a new instance of the UiClient class with the specified key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">The unique key to identify this client</param>
|
/// <param name="key">The unique key to identify this client</param>
|
||||||
public UiClient(string key)
|
/// <param name="id">The client ID used by the client for this connection</param>
|
||||||
|
/// <param name="token">The token associated with this client</param>
|
||||||
|
/// <param name="touchpanelKey">The touchpanel key associated with this client</param>
|
||||||
|
public UiClient(string key, string id, string token, string touchpanelKey = "")
|
||||||
{
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
|
Id = id;
|
||||||
|
Token = token;
|
||||||
|
TouchpanelKey = touchpanelKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -74,19 +94,10 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
{
|
{
|
||||||
base.OnOpen();
|
base.OnOpen();
|
||||||
|
|
||||||
var url = Context.WebSocket.Url;
|
_connectionTime = DateTime.Now;
|
||||||
this.LogInformation("New WebSocket Connection from: {url}", url);
|
|
||||||
|
|
||||||
var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)");
|
Log.Output = (data, message) => Utilities.ConvertWebsocketLog(data, message, this);
|
||||||
|
Log.Level = LogLevel.Trace;
|
||||||
if (!match.Success)
|
|
||||||
{
|
|
||||||
_connectionTime = DateTime.Now;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var clientId = match.Groups[1].Value;
|
|
||||||
_clientId = clientId;
|
|
||||||
|
|
||||||
if (Controller == null)
|
if (Controller == null)
|
||||||
{
|
{
|
||||||
@@ -99,8 +110,9 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
Type = "/system/clientJoined",
|
Type = "/system/clientJoined",
|
||||||
Content = JToken.FromObject(new
|
Content = JToken.FromObject(new
|
||||||
{
|
{
|
||||||
clientId,
|
clientId = Id,
|
||||||
roomKey = RoomKey,
|
roomKey = RoomKey,
|
||||||
|
touchpanelKey = TouchpanelKey ?? string.Empty,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,7 +122,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
if (bridge == null) return;
|
if (bridge == null) return;
|
||||||
|
|
||||||
SendUserCodeToClient(bridge, clientId);
|
SendUserCodeToClient(bridge, Id);
|
||||||
|
|
||||||
bridge.UserCodeChanged -= Bridge_UserCodeChanged;
|
bridge.UserCodeChanged -= Bridge_UserCodeChanged;
|
||||||
bridge.UserCodeChanged += Bridge_UserCodeChanged;
|
bridge.UserCodeChanged += Bridge_UserCodeChanged;
|
||||||
@@ -125,7 +137,7 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// <param name="e">Event arguments</param>
|
/// <param name="e">Event arguments</param>
|
||||||
private void Bridge_UserCodeChanged(object sender, EventArgs e)
|
private void Bridge_UserCodeChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, _clientId);
|
SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -172,13 +184,15 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
|
|
||||||
foreach (var messenger in Controller.Messengers)
|
foreach (var messenger in Controller.Messengers)
|
||||||
{
|
{
|
||||||
messenger.Value.UnsubscribeClient(_clientId);
|
messenger.Value.UnsubscribeClient(Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var messenger in Controller.DefaultMessengers)
|
foreach (var messenger in Controller.DefaultMessengers)
|
||||||
{
|
{
|
||||||
messenger.Value.UnsubscribeClient(_clientId);
|
messenger.Value.UnsubscribeClient(Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConnectionClosed?.Invoke(this, new ConnectionClosedEventArgs(Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public JoinToken Token { get; private set; }
|
public JoinToken Token { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize an instance of the <see cref="UiClientContext"/> class with the provided token
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">token for this client</param>
|
||||||
public UiClientContext(JoinToken token)
|
public UiClientContext(JoinToken token)
|
||||||
{
|
{
|
||||||
Token = token;
|
Token = token;
|
||||||
|
|||||||
@@ -8,12 +8,25 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Version
|
public class Version
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Server version this Websocket is connected to
|
||||||
|
/// </summary>
|
||||||
[JsonProperty("serverVersion")]
|
[JsonProperty("serverVersion")]
|
||||||
public string ServerVersion { get; set; }
|
public string ServerVersion { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// True if the server is on a processor
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
[JsonProperty("serverIsRunningOnProcessorHardware")]
|
[JsonProperty("serverIsRunningOnProcessorHardware")]
|
||||||
public bool ServerIsRunningOnProcessorHardware { get; private set; }
|
public bool ServerIsRunningOnProcessorHardware { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize an instance of the <see cref="Version"/> class
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The <see cref="ServerIsRunningOnProcessorHardware"/> property is set to true by default.
|
||||||
|
/// </remarks>
|
||||||
public Version()
|
public Version()
|
||||||
{
|
{
|
||||||
ServerIsRunningOnProcessorHardware = true;
|
ServerIsRunningOnProcessorHardware = true;
|
||||||
|
|||||||
@@ -13,25 +13,28 @@ namespace PepperDash.Essentials.WebSocketServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a WebSocketServerSecret
|
/// Stores a secret value using the provided secret store provider
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WebSocketServerSecret : ISecret
|
public class WebSocketServerSecret : ISecret
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Provider
|
/// Gets the Secret Provider associated with this secret
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ISecretProvider Provider { get; private set; }
|
public ISecretProvider Provider { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Key
|
/// Gets the Key associated with this secret
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Key { get; private set; }
|
public string Key { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the Value
|
/// Gets the Value associated with this secret
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object Value { get; private set; }
|
public object Value { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize and instance of the <see cref="WebSocketServerSecret"/> class
|
||||||
|
/// </summary>
|
||||||
public WebSocketServerSecret(string key, object value, ISecretProvider provider)
|
public WebSocketServerSecret(string key, object value, ISecretProvider provider)
|
||||||
{
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ namespace PepperDash.Essentials
|
|||||||
CrestronConsole.ConsoleCommandResponse
|
CrestronConsole.ConsoleCommandResponse
|
||||||
("Current running configuration. This is the merged system and template configuration" + CrestronEnvironment.NewLine);
|
("Current running configuration. This is the merged system and template configuration" + CrestronEnvironment.NewLine);
|
||||||
CrestronConsole.ConsoleCommandResponse(Newtonsoft.Json.JsonConvert.SerializeObject
|
CrestronConsole.ConsoleCommandResponse(Newtonsoft.Json.JsonConvert.SerializeObject
|
||||||
(ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented));
|
(ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented).Replace(Environment.NewLine, "\r\n"));
|
||||||
}, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator);
|
}, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
CrestronConsole.AddNewConsoleCommand(s =>
|
CrestronConsole.AddNewConsoleCommand(s =>
|
||||||
|
|||||||
Reference in New Issue
Block a user