mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-04 23:35:02 +00:00
Compare commits
8 Commits
copilot/fi
...
v2.14.0-IB
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6830efe42a | ||
|
|
fe33443b25 | ||
|
|
8cf195b262 | ||
|
|
40406b797d | ||
|
|
65bc408ebf | ||
|
|
fb7797dac7 | ||
|
|
574f5f6dc9 | ||
|
|
e49c69a12f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -395,3 +395,4 @@ essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/Pepp
|
||||
_site/
|
||||
api/
|
||||
*.DS_Store
|
||||
/._PepperDash.Essentials.4Series.sln
|
||||
|
||||
@@ -74,6 +74,10 @@ namespace PepperDash.Core
|
||||
/// <summary>
|
||||
/// Secure TCP/IP
|
||||
/// </summary>
|
||||
SecureTcpIp
|
||||
SecureTcpIp,
|
||||
/// <summary>
|
||||
/// Used when comms needs to be handled in SIMPL and bridged opposite the normal direction
|
||||
/// </summary>
|
||||
ComBridge
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,13 @@ namespace PepperDash.Essentials.Core.Bridges
|
||||
/// </summary>
|
||||
public interface IBridgeAdvanced
|
||||
{
|
||||
/// <summary>
|
||||
/// Links the bridge to the API using the provided trilist, join start, join map key, and bridge.
|
||||
/// </summary>
|
||||
/// <param name="trilist">The trilist to link to.</param>
|
||||
/// <param name="joinStart">The starting join number.</param>
|
||||
/// <param name="joinMapKey">The key for the join map.</param>
|
||||
/// <param name="bridge">The EISC API bridge.</param>
|
||||
void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
|
||||
}
|
||||
}
|
||||
138
src/PepperDash.Essentials.Core/Comm and IR/CommBridge.cs
Normal file
138
src/PepperDash.Essentials.Core/Comm and IR/CommBridge.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Crestron.SimplSharp.CrestronSockets;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
using Newtonsoft.Json;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Logging;
|
||||
using PepperDash.Essentials.Core.Bridges;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using PepperDash.Essentials.Core.Devices;
|
||||
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements IBasicCommunication and sends all communication through an EISC
|
||||
/// </summary>
|
||||
[Description("Generic communication wrapper class for any IBasicCommunication type")]
|
||||
public class CommBridge : EssentialsBridgeableDevice, IBasicCommunication
|
||||
{
|
||||
private EiscApiAdvanced eisc;
|
||||
|
||||
private IBasicCommunicationJoinMap joinMap;
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when text is received through the communication bridge.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when bytes are received through the communication bridge.
|
||||
/// </summary>
|
||||
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the communication bridge is currently connected.
|
||||
/// </summary>
|
||||
public bool IsConnected { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CommBridge"/> class.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key for the communication bridge.</param>
|
||||
/// <param name="name">The display name for the communication bridge.</param>
|
||||
public CommBridge(string key, string name)
|
||||
: base(key, name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a byte array through the communication bridge.
|
||||
/// </summary>
|
||||
/// <param name="bytes">The byte array to send.</param>
|
||||
public void SendBytes(byte[] bytes)
|
||||
{
|
||||
if (eisc == null)
|
||||
{
|
||||
this.LogWarning("EISC is null, cannot send bytes.");
|
||||
return;
|
||||
}
|
||||
eisc.Eisc.SetString(joinMap.SendText.JoinNumber, Encoding.ASCII.GetString(bytes, 0, bytes.Length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends a text string through the communication bridge.
|
||||
/// </summary>
|
||||
/// <param name="text">The text string to send.</param>
|
||||
public void SendText(string text)
|
||||
{
|
||||
if (eisc == null)
|
||||
{
|
||||
this.LogWarning("EISC is null, cannot send text.");
|
||||
return;
|
||||
}
|
||||
eisc.Eisc.SetString(joinMap.SendText.JoinNumber, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initiates a connection through the communication bridge.
|
||||
/// </summary>
|
||||
public void Connect()
|
||||
{
|
||||
if (eisc == null)
|
||||
{
|
||||
this.LogWarning("EISC is null, cannot connect.");
|
||||
return;
|
||||
}
|
||||
eisc.Eisc.SetBool(joinMap.Connect.JoinNumber, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Terminates the connection through the communication bridge.
|
||||
/// </summary>
|
||||
public void Disconnect()
|
||||
{
|
||||
if (eisc == null)
|
||||
{
|
||||
this.LogWarning("EISC is null, cannot disconnect.");
|
||||
return;
|
||||
}
|
||||
eisc.Eisc.SetBool(joinMap.Connect.JoinNumber, false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
||||
{
|
||||
joinMap = new IBasicCommunicationJoinMap(joinStart);
|
||||
|
||||
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
|
||||
|
||||
if (!string.IsNullOrEmpty(joinMapSerialized))
|
||||
joinMap = JsonConvert.DeserializeObject<IBasicCommunicationJoinMap>(joinMapSerialized);
|
||||
|
||||
if (bridge != null)
|
||||
{
|
||||
bridge.AddJoinMap(Key, joinMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LogWarning("Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
|
||||
}
|
||||
|
||||
this.LogDebug("Linking to Trilist '{0}'", trilist.ID.ToString("X"));
|
||||
|
||||
eisc = bridge;
|
||||
|
||||
trilist.SetBoolSigAction(joinMap.Connected.JoinNumber, (b) => IsConnected = b);
|
||||
|
||||
trilist.SetStringSigAction(joinMap.TextReceived.JoinNumber, (s) =>
|
||||
{
|
||||
TextReceived?.Invoke(this, new GenericCommMethodReceiveTextArgs(s));
|
||||
BytesReceived?.Invoke(this, new GenericCommMethodReceiveBytesArgs(Encoding.ASCII.GetBytes(s)));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,9 @@
|
||||
|
||||
|
||||
using System;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.DM;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core.Config;
|
||||
using Serilog.Events;
|
||||
@@ -38,9 +36,9 @@ namespace PepperDash.Essentials.Core
|
||||
/// Returns a comm method of either com port, TCP, SSH, and puts this into the DeviceManager
|
||||
/// </summary>
|
||||
/// <param name="deviceConfig">The Device config object</param>
|
||||
/// <summary>
|
||||
/// CreateCommForDevice method
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// CreateCommForDevice method
|
||||
/// </summary>
|
||||
public static IBasicCommunication CreateCommForDevice(DeviceConfig deviceConfig)
|
||||
{
|
||||
EssentialsControlPropertiesConfig controlConfig = GetControlPropertiesConfig(deviceConfig);
|
||||
@@ -56,35 +54,38 @@ namespace PepperDash.Essentials.Core
|
||||
case eControlMethod.Com:
|
||||
comm = new ComPortController(deviceConfig.Key + "-com", GetComPort, controlConfig.ComParams.Value, controlConfig);
|
||||
break;
|
||||
case eControlMethod.Cec:
|
||||
comm = new CecPortController(deviceConfig.Key + "-cec", GetCecPort, controlConfig);
|
||||
break;
|
||||
case eControlMethod.ComBridge:
|
||||
comm = new CommBridge(deviceConfig.Key + "-simpl", deviceConfig.Name + " Simpl");
|
||||
break;
|
||||
case eControlMethod.Cec:
|
||||
comm = new CecPortController(deviceConfig.Key + "-cec", GetCecPort, controlConfig);
|
||||
break;
|
||||
case eControlMethod.IR:
|
||||
break;
|
||||
case eControlMethod.Ssh:
|
||||
{
|
||||
var ssh = new GenericSshClient(deviceConfig.Key + "-ssh", c.Address, c.Port, c.Username, c.Password);
|
||||
ssh.AutoReconnect = c.AutoReconnect;
|
||||
if(ssh.AutoReconnect)
|
||||
ssh.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
||||
comm = ssh;
|
||||
break;
|
||||
}
|
||||
case eControlMethod.Tcpip:
|
||||
{
|
||||
var tcp = new GenericTcpIpClient(deviceConfig.Key + "-tcp", c.Address, c.Port, c.BufferSize);
|
||||
tcp.AutoReconnect = c.AutoReconnect;
|
||||
if (tcp.AutoReconnect)
|
||||
tcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
||||
comm = tcp;
|
||||
break;
|
||||
}
|
||||
case eControlMethod.Udp:
|
||||
{
|
||||
var udp = new GenericUdpServer(deviceConfig.Key + "-udp", c.Address, c.Port, c.BufferSize);
|
||||
comm = udp;
|
||||
break;
|
||||
}
|
||||
case eControlMethod.Ssh:
|
||||
{
|
||||
var ssh = new GenericSshClient(deviceConfig.Key + "-ssh", c.Address, c.Port, c.Username, c.Password);
|
||||
ssh.AutoReconnect = c.AutoReconnect;
|
||||
if (ssh.AutoReconnect)
|
||||
ssh.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
||||
comm = ssh;
|
||||
break;
|
||||
}
|
||||
case eControlMethod.Tcpip:
|
||||
{
|
||||
var tcp = new GenericTcpIpClient(deviceConfig.Key + "-tcp", c.Address, c.Port, c.BufferSize);
|
||||
tcp.AutoReconnect = c.AutoReconnect;
|
||||
if (tcp.AutoReconnect)
|
||||
tcp.AutoReconnectIntervalMs = c.AutoReconnectIntervalMs;
|
||||
comm = tcp;
|
||||
break;
|
||||
}
|
||||
case eControlMethod.Udp:
|
||||
{
|
||||
var udp = new GenericUdpServer(deviceConfig.Key + "-udp", c.Address, c.Port, c.BufferSize);
|
||||
comm = udp;
|
||||
break;
|
||||
}
|
||||
case eControlMethod.Telnet:
|
||||
break;
|
||||
case eControlMethod.SecureTcpIp:
|
||||
@@ -98,7 +99,7 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -107,15 +108,14 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
|
||||
// put it in the device manager if it's the right flavor
|
||||
var comDev = comm as Device;
|
||||
if (comDev != null)
|
||||
if (comm is Device comDev)
|
||||
DeviceManager.AddDevice(comDev);
|
||||
return comm;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetComPort method
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// GetComPort method
|
||||
/// </summary>
|
||||
public static ComPort GetComPort(EssentialsControlPropertiesConfig config)
|
||||
{
|
||||
var comPar = config.ComParams;
|
||||
@@ -126,74 +126,74 @@ namespace PepperDash.Essentials.Core
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an ICec port from a RoutingInput or RoutingOutput on a device
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// GetCecPort method
|
||||
/// </summary>
|
||||
public static ICec GetCecPort(ControlPropertiesConfig config)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dev = DeviceManager.GetDeviceForKey(config.ControlPortDevKey);
|
||||
/// <summary>
|
||||
/// Gets an ICec port from a RoutingInput or RoutingOutput on a device
|
||||
/// </summary>
|
||||
/// <param name="config"></param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// GetCecPort method
|
||||
/// </summary>
|
||||
public static ICec GetCecPort(ControlPropertiesConfig config)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dev = DeviceManager.GetDeviceForKey(config.ControlPortDevKey);
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort: device '{0}' {1}", config.ControlPortDevKey, dev == null
|
||||
? "is not valid, failed to get cec port"
|
||||
: "found in device manager, attempting to get cec port");
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort: device '{0}' {1}", config.ControlPortDevKey, dev == null
|
||||
? "is not valid, failed to get cec port"
|
||||
: "found in device manager, attempting to get cec port");
|
||||
|
||||
if (dev == null)
|
||||
return null;
|
||||
if (dev == null)
|
||||
return null;
|
||||
|
||||
if (String.IsNullOrEmpty(config.ControlPortName))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort: '{0}' - Configuration missing 'ControlPortName'", config.ControlPortDevKey);
|
||||
return null;
|
||||
}
|
||||
if (String.IsNullOrEmpty(config.ControlPortName))
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort: '{0}' - Configuration missing 'ControlPortName'", config.ControlPortDevKey);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var inputsOutputs = dev as IRoutingInputsOutputs;
|
||||
if (inputsOutputs == null)
|
||||
{
|
||||
var inputsOutputs = dev as IRoutingInputsOutputs;
|
||||
if (inputsOutputs == null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort: Device '{0}' does not support IRoutingInputsOutputs, failed to get CEC port called '{1}'",
|
||||
config.ControlPortDevKey, config.ControlPortName);
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var inputPort = inputsOutputs.InputPorts[config.ControlPortName];
|
||||
if (inputPort != null && inputPort.Port is ICec)
|
||||
if (inputPort != null && inputPort.Port is ICec)
|
||||
return inputPort.Port as ICec;
|
||||
|
||||
|
||||
var outputPort = inputsOutputs.OutputPorts[config.ControlPortName];
|
||||
if (outputPort != null && outputPort.Port is ICec)
|
||||
return outputPort.Port as ICec;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "GetCecPort Exception Message: {0}", ex.Message);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "GetCecPort Exception StackTrace: {0}", ex.StackTrace);
|
||||
if (ex.InnerException != null)
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort Exception InnerException: {0}", ex.InnerException);
|
||||
}
|
||||
|
||||
var outputPort = inputsOutputs.OutputPorts[config.ControlPortName];
|
||||
if (outputPort != null && outputPort.Port is ICec)
|
||||
return outputPort.Port as ICec;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "GetCecPort Exception Message: {0}", ex.Message);
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "GetCecPort Exception StackTrace: {0}", ex.StackTrace);
|
||||
if (ex.InnerException != null)
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort Exception InnerException: {0}", ex.InnerException);
|
||||
}
|
||||
|
||||
Debug.LogMessage(LogEventLevel.Information, "GetCecPort: Device '{0}' does not have a CEC port called '{1}'",
|
||||
config.ControlPortDevKey, config.ControlPortName);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to grab the IComPorts device for this PortDeviceKey. Key "controlSystem" will
|
||||
/// return the ControlSystem object from the Global class.
|
||||
/// </summary>
|
||||
/// <returns>IComPorts device or null if the device is not found or does not implement IComPorts</returns>
|
||||
/// <summary>
|
||||
/// GetIComPortsDeviceFromManagedDevice method
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// GetIComPortsDeviceFromManagedDevice method
|
||||
/// </summary>
|
||||
public static IComPorts GetIComPortsDeviceFromManagedDevice(string ComPortDevKey)
|
||||
{
|
||||
if ((ComPortDevKey.Equals("controlSystem", System.StringComparison.OrdinalIgnoreCase)
|
||||
@@ -210,81 +210,81 @@ namespace PepperDash.Essentials.Core
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a EssentialsControlPropertiesConfig
|
||||
/// </summary>
|
||||
public class EssentialsControlPropertiesConfig :
|
||||
ControlPropertiesConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a EssentialsControlPropertiesConfig
|
||||
/// </summary>
|
||||
public class EssentialsControlPropertiesConfig :
|
||||
ControlPropertiesConfig
|
||||
{
|
||||
|
||||
[JsonProperty("comParams", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonConverter(typeof(ComSpecJsonConverter))]
|
||||
public ComPort.ComPortSpec? ComParams { get; set; }
|
||||
[JsonProperty("comParams", NullValueHandling = NullValueHandling.Ignore)]
|
||||
[JsonConverter(typeof(ComSpecJsonConverter))]
|
||||
public ComPort.ComPortSpec? ComParams { get; set; }
|
||||
|
||||
[JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string CresnetId { get; set; }
|
||||
[JsonProperty("cresnetId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string CresnetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to provide uint conversion of string CresnetId
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint CresnetIdInt
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToUInt32(CresnetId, 16);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new FormatException(string.Format("ERROR:Unable to convert Cresnet ID: {0} to hex. Error:\n{1}", CresnetId));
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Attempts to provide uint conversion of string CresnetId
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint CresnetIdInt
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToUInt32(CresnetId, 16);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new FormatException(string.Format("ERROR:Unable to convert Cresnet ID: {0} to hex. Error:\n{1}", CresnetId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
/// <summary>
|
||||
/// Gets or sets the InfinetId
|
||||
/// </summary>
|
||||
public string InfinetId { get; set; }
|
||||
[JsonProperty("infinetId", NullValueHandling = NullValueHandling.Ignore)]
|
||||
/// <summary>
|
||||
/// Gets or sets the InfinetId
|
||||
/// </summary>
|
||||
public string InfinetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Attepmts to provide uiont conversion of string InifinetId
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint InfinetIdInt
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToUInt32(InfinetId, 16);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new FormatException(string.Format("ERROR:Unable to conver Infinet ID: {0} to hex. Error:\n{1}", InfinetId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Attepmts to provide uiont conversion of string InifinetId
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public uint InfinetIdInt
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToUInt32(InfinetId, 16);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new FormatException(string.Format("ERROR:Unable to conver Infinet ID: {0} to hex. Error:\n{1}", InfinetId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a IrControlSpec
|
||||
/// </summary>
|
||||
public class IrControlSpec
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the PortDeviceKey
|
||||
/// </summary>
|
||||
public string PortDeviceKey { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the PortNumber
|
||||
/// </summary>
|
||||
public uint PortNumber { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the File
|
||||
/// </summary>
|
||||
public string File { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Represents a IrControlSpec
|
||||
/// </summary>
|
||||
public class IrControlSpec
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the PortDeviceKey
|
||||
/// </summary>
|
||||
public string PortDeviceKey { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the PortNumber
|
||||
/// </summary>
|
||||
public uint PortNumber { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the File
|
||||
/// </summary>
|
||||
public string File { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -19,5 +19,11 @@ namespace PepperDash.Essentials.Core.Config
|
||||
/// </summary>
|
||||
[JsonProperty("multicastAudioAddress", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string MulticastAudioAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The URL for the streaming device's media stream.
|
||||
/// </summary>
|
||||
[JsonProperty("streamUrl", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public string StreamUrl { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,29 @@ using PepperDash.Essentials.Core.Bridges;
|
||||
|
||||
namespace PepperDash.Essentials.Core
|
||||
{
|
||||
public abstract class EssentialsBridgeableDevice:EssentialsDevice, IBridgeAdvanced
|
||||
/// <summary>
|
||||
/// Base class for devices that can be bridged to an EISC API.
|
||||
/// </summary>
|
||||
public abstract class EssentialsBridgeableDevice : EssentialsDevice, IBridgeAdvanced
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EssentialsBridgeableDevice"/> class with the specified key.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key for the device.</param>
|
||||
protected EssentialsBridgeableDevice(string key) : base(key)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EssentialsBridgeableDevice"/> class with the specified key and name.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key for the device.</param>
|
||||
/// <param name="name">The display name for the device.</param>
|
||||
protected EssentialsBridgeableDevice(string key, string name) : base(key, name)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge);
|
||||
}
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Core.Logging;
|
||||
using PepperDash.Essentials.Core;
|
||||
using PepperDash.Essentials.Devices.Common.Codec;
|
||||
|
||||
namespace PepperDash.Essentials.AppServer.Messengers
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a messaging bridge for devices that implement call status interfaces
|
||||
/// without requiring VideoCodecBase inheritance
|
||||
/// </summary>
|
||||
public class CallStatusMessenger : MessengerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Device with dialer capabilities
|
||||
/// </summary>
|
||||
protected IHasDialer Dialer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Device with content sharing capabilities (optional)
|
||||
/// </summary>
|
||||
protected IHasContentSharing ContentSharing { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="dialer"></param>
|
||||
/// <param name="messagePath"></param>
|
||||
public CallStatusMessenger(string key, IHasDialer dialer, string messagePath)
|
||||
: base(key, messagePath, dialer as IKeyName)
|
||||
{
|
||||
Dialer = dialer ?? throw new ArgumentNullException(nameof(dialer));
|
||||
dialer.CallStatusChange += Dialer_CallStatusChange;
|
||||
|
||||
// Check for optional content sharing interface
|
||||
if (dialer is IHasContentSharing contentSharing)
|
||||
{
|
||||
ContentSharing = contentSharing;
|
||||
contentSharing.SharingContentIsOnFeedback.OutputChange += SharingContentIsOnFeedback_OutputChange;
|
||||
contentSharing.SharingSourceFeedback.OutputChange += SharingSourceFeedback_OutputChange;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles call status changes
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void Dialer_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
SendFullStatus();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.LogError(ex, "Error handling call status change: {error}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles content sharing status changes
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void SharingContentIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||
{
|
||||
PostStatusMessage(JToken.FromObject(new
|
||||
{
|
||||
sharingContentIsOn = e.BoolValue
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles sharing source changes
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private void SharingSourceFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||
{
|
||||
PostStatusMessage(JToken.FromObject(new
|
||||
{
|
||||
sharingSource = e.StringValue
|
||||
}));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets active calls from the dialer
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private object GetActiveCalls()
|
||||
{
|
||||
// Try to get active calls if the dialer has an ActiveCalls property
|
||||
var dialerType = Dialer.GetType();
|
||||
var activeCallsProperty = dialerType.GetProperty("ActiveCalls");
|
||||
|
||||
if (activeCallsProperty != null && activeCallsProperty.PropertyType == typeof(System.Collections.Generic.List<CodecActiveCallItem>))
|
||||
{
|
||||
var activeCalls = activeCallsProperty.GetValue(Dialer) as System.Collections.Generic.List<CodecActiveCallItem>;
|
||||
return activeCalls ?? new System.Collections.Generic.List<CodecActiveCallItem>();
|
||||
}
|
||||
|
||||
// Return basic call status if no ActiveCalls property
|
||||
return new { isInCall = Dialer.IsInCall };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends full status message
|
||||
/// </summary>
|
||||
public void SendFullStatus()
|
||||
{
|
||||
var status = new
|
||||
{
|
||||
isInCall = Dialer.IsInCall,
|
||||
calls = GetActiveCalls()
|
||||
};
|
||||
|
||||
// Add content sharing status if available
|
||||
if (ContentSharing != null)
|
||||
{
|
||||
var statusWithSharing = new
|
||||
{
|
||||
isInCall = Dialer.IsInCall,
|
||||
calls = GetActiveCalls(),
|
||||
sharingContentIsOn = ContentSharing.SharingContentIsOnFeedback.BoolValue,
|
||||
sharingSource = ContentSharing.SharingSourceFeedback.StringValue
|
||||
};
|
||||
PostStatusMessage(JToken.FromObject(statusWithSharing));
|
||||
}
|
||||
else
|
||||
{
|
||||
PostStatusMessage(JToken.FromObject(status));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers actions for call control
|
||||
/// </summary>
|
||||
protected override void RegisterActions()
|
||||
{
|
||||
base.RegisterActions();
|
||||
|
||||
AddAction("/fullStatus", (id, content) => SendFullStatus());
|
||||
|
||||
// Basic call control actions
|
||||
AddAction("/dial", (id, content) =>
|
||||
{
|
||||
var msg = content.ToObject<MobileControlSimpleContent<string>>();
|
||||
Dialer.Dial(msg.Value);
|
||||
});
|
||||
|
||||
AddAction("/endAllCalls", (id, content) => Dialer.EndAllCalls());
|
||||
|
||||
AddAction("/dtmf", (id, content) =>
|
||||
{
|
||||
var msg = content.ToObject<MobileControlSimpleContent<string>>();
|
||||
Dialer.SendDtmf(msg.Value);
|
||||
});
|
||||
|
||||
// Call-specific actions (if active calls are available)
|
||||
AddAction("/endCallById", (id, content) =>
|
||||
{
|
||||
var msg = content.ToObject<MobileControlSimpleContent<string>>();
|
||||
var call = GetCallWithId(msg.Value);
|
||||
if (call != null)
|
||||
Dialer.EndCall(call);
|
||||
});
|
||||
|
||||
AddAction("/acceptById", (id, content) =>
|
||||
{
|
||||
var msg = content.ToObject<MobileControlSimpleContent<string>>();
|
||||
var call = GetCallWithId(msg.Value);
|
||||
if (call != null)
|
||||
Dialer.AcceptCall(call);
|
||||
});
|
||||
|
||||
AddAction("/rejectById", (id, content) =>
|
||||
{
|
||||
var msg = content.ToObject<MobileControlSimpleContent<string>>();
|
||||
var call = GetCallWithId(msg.Value);
|
||||
if (call != null)
|
||||
Dialer.RejectCall(call);
|
||||
});
|
||||
|
||||
// Content sharing actions if available
|
||||
if (ContentSharing != null)
|
||||
{
|
||||
AddAction("/startSharing", (id, content) => ContentSharing.StartSharing());
|
||||
AddAction("/stopSharing", (id, content) => ContentSharing.StopSharing());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a call by ID
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
private CodecActiveCallItem GetCallWithId(string id)
|
||||
{
|
||||
// Try to get call using reflection for ActiveCalls property
|
||||
var dialerType = Dialer.GetType();
|
||||
var activeCallsProperty = dialerType.GetProperty("ActiveCalls");
|
||||
|
||||
if (activeCallsProperty != null && activeCallsProperty.PropertyType == typeof(System.Collections.Generic.List<CodecActiveCallItem>))
|
||||
{
|
||||
var activeCalls = activeCallsProperty.GetValue(Dialer) as System.Collections.Generic.List<CodecActiveCallItem>;
|
||||
if (activeCalls != null)
|
||||
{
|
||||
return activeCalls.FirstOrDefault(c => c.Id.Equals(id));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,17 +140,19 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
|
||||
if (Camera is IHasCameraPresets presetsCamera)
|
||||
{
|
||||
for (int i = 1; i <= 6; i++)
|
||||
AddAction("/recallPreset", (id, content) =>
|
||||
{
|
||||
var preset = i;
|
||||
AddAction("/cameraPreset" + i, (id, content) =>
|
||||
{
|
||||
var msg = content.ToObject<MobileControlSimpleContent<int>>();
|
||||
var msg = content.ToObject<MobileControlSimpleContent<int>>();
|
||||
|
||||
presetsCamera.PresetSelect(msg.Value);
|
||||
});
|
||||
presetsCamera.PresetSelect(msg.Value);
|
||||
});
|
||||
|
||||
}
|
||||
AddAction("/storePreset", (id, content) =>
|
||||
{
|
||||
var msg = content.ToObject<MobileControlSimpleContent<int>>();
|
||||
|
||||
presetsCamera.PresetStore(msg.Value, string.Empty);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,9 +166,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
|
||||
return;
|
||||
}
|
||||
|
||||
timerHandler(state.Value, cameraAction);
|
||||
timerHandler(Camera.Key, cameraAction);
|
||||
|
||||
cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase));
|
||||
//cameraAction(state.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using PepperDash.Core;
|
||||
using PepperDash.Essentials.Core;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PepperDash.Essentials.AppServer.Messengers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a IBasicVideoMuteWithFeedbackMessenger
|
||||
/// </summary>
|
||||
public class IBasicVideoMuteWithFeedbackMessenger : MessengerBase
|
||||
{
|
||||
private readonly IBasicVideoMuteWithFeedback device;
|
||||
|
||||
public IBasicVideoMuteWithFeedbackMessenger(string key, string messagePath, IBasicVideoMuteWithFeedback device)
|
||||
: base(key, messagePath, device as IKeyName)
|
||||
{
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SendFullStatus method
|
||||
/// </summary>
|
||||
public void SendFullStatus()
|
||||
{
|
||||
var messageObj = new IBasicVideoMuteWithFeedbackMessage
|
||||
{
|
||||
VideoMuteState = device.VideoMuteIsOn.BoolValue
|
||||
};
|
||||
|
||||
PostStatusMessage(messageObj);
|
||||
}
|
||||
|
||||
protected override void RegisterActions()
|
||||
{
|
||||
base.RegisterActions();
|
||||
|
||||
AddAction("/fullStatus", (id, content) => SendFullStatus());
|
||||
|
||||
AddAction("/videoMuteToggle", (id, content) =>
|
||||
{
|
||||
device.VideoMuteToggle();
|
||||
});
|
||||
|
||||
AddAction("/videoMuteOn", (id, content) =>
|
||||
{
|
||||
device.VideoMuteOn();
|
||||
});
|
||||
|
||||
AddAction("/videoMuteOff", (id, content) =>
|
||||
{
|
||||
device.VideoMuteOff();
|
||||
});
|
||||
|
||||
device.VideoMuteIsOn.OutputChange += VideoMuteIsOnFeedback_OutputChange;
|
||||
}
|
||||
|
||||
private void VideoMuteIsOnFeedback_OutputChange(object sender, FeedbackEventArgs args)
|
||||
{
|
||||
PostStatusMessage(JToken.FromObject(new
|
||||
{
|
||||
videoMuteState = args.BoolValue
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a IBasicVideoMuteWithFeedbackMessage
|
||||
/// </summary>
|
||||
public class IBasicVideoMuteWithFeedbackMessage : DeviceStateMessageBase
|
||||
{
|
||||
[JsonProperty("videoMuteState")]
|
||||
public bool VideoMuteState { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ using PepperDash.Essentials.Core.Shades;
|
||||
using PepperDash.Essentials.Core.Web;
|
||||
using PepperDash.Essentials.Devices.Common.AudioCodec;
|
||||
using PepperDash.Essentials.Devices.Common.Cameras;
|
||||
using PepperDash.Essentials.Devices.Common.Codec;
|
||||
using PepperDash.Essentials.Devices.Common.Displays;
|
||||
using PepperDash.Essentials.Devices.Common.Lighting;
|
||||
using PepperDash.Essentials.Devices.Common.SoftCodec;
|
||||
@@ -506,6 +505,25 @@ namespace PepperDash.Essentials
|
||||
messengerAdded = true;
|
||||
}
|
||||
|
||||
if (device is IBasicVideoMuteWithFeedback)
|
||||
{
|
||||
var deviceKey = device.Key;
|
||||
this.LogVerbose(
|
||||
"Adding IBasicVideoMuteWithFeedback for {deviceKey}",
|
||||
deviceKey
|
||||
);
|
||||
|
||||
var videoMuteControlDevice = device as IBasicVideoMuteWithFeedback;
|
||||
var messenger = new IBasicVideoMuteWithFeedbackMessenger(
|
||||
$"{device.Key}-videoMute-{Key}",
|
||||
string.Format("/device/{0}", deviceKey),
|
||||
videoMuteControlDevice
|
||||
);
|
||||
AddDefaultDeviceMessenger(messenger);
|
||||
|
||||
messengerAdded = true;
|
||||
}
|
||||
|
||||
if (device is ILightingScenes || device is LightingBase)
|
||||
{
|
||||
var deviceKey = device.Key;
|
||||
@@ -561,21 +579,6 @@ namespace PepperDash.Essentials
|
||||
|
||||
messengerAdded = true;
|
||||
}
|
||||
else if (device is IHasDialer dialer && !messengerAdded)
|
||||
{
|
||||
this.LogVerbose(
|
||||
"Adding CallStatusMessenger for {deviceKey}", device.Key);
|
||||
|
||||
var messenger = new CallStatusMessenger(
|
||||
$"{device.Key}-callStatus-{Key}",
|
||||
dialer,
|
||||
$"/device/{device.Key}"
|
||||
);
|
||||
|
||||
AddDefaultDeviceMessenger(messenger);
|
||||
|
||||
messengerAdded = true;
|
||||
}
|
||||
|
||||
if (device is AudioCodecBase audioCodec)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Crestron.SimplSharp;
|
||||
using Crestron.SimplSharpPro;
|
||||
using Crestron.SimplSharpPro.DeviceSupport;
|
||||
using Crestron.SimplSharpPro.UI;
|
||||
@@ -106,6 +108,11 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
|
||||
public ReadOnlyCollection<ConnectedIpInformation> ConnectedIps => Panel.ConnectedIpList;
|
||||
|
||||
private System.Net.IPAddress csIpAddress;
|
||||
|
||||
private System.Net.IPAddress csSubnetMask;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MobileControlTouchpanelController class.
|
||||
/// </summary>
|
||||
@@ -182,6 +189,13 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
};
|
||||
|
||||
RegisterForExtenders();
|
||||
|
||||
var csAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
|
||||
var csSubnetMask = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, csAdapterId);
|
||||
var csIpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, csAdapterId);
|
||||
|
||||
this.csSubnetMask = System.Net.IPAddress.Parse(csSubnetMask);
|
||||
this.csIpAddress = System.Net.IPAddress.Parse(csIpAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -381,19 +395,81 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
McServerUrlFeedback.LinkInputSig(Panel.StringInput[3]);
|
||||
UserCodeFeedback.LinkInputSig(Panel.StringInput[4]);
|
||||
|
||||
Panel.IpInformationChange += (sender, args) =>
|
||||
{
|
||||
if (args.Connected)
|
||||
{
|
||||
this.LogVerbose("Connection from IP: {ip}", args.DeviceIpAddress);
|
||||
this.LogInformation("Sending {appUrl} on join 1", AppUrlFeedback.StringValue);
|
||||
|
||||
var appUrl = GetUrlWithCorrectIp(_appUrl);
|
||||
Panel.StringInput[1].StringValue = appUrl;
|
||||
|
||||
SetAppUrl(appUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LogVerbose("Disconnection from IP: {ip}", args.DeviceIpAddress);
|
||||
}
|
||||
};
|
||||
|
||||
Panel.OnlineStatusChange += (sender, args) =>
|
||||
{
|
||||
UpdateFeedbacks();
|
||||
|
||||
this.LogInformation("Sending {appUrl} on join 1", AppUrlFeedback.StringValue);
|
||||
|
||||
Panel.StringInput[1].StringValue = AppUrlFeedback.StringValue;
|
||||
UpdateFeedbacks();
|
||||
Panel.StringInput[1].StringValue = _appUrl;
|
||||
Panel.StringInput[2].StringValue = QrCodeUrlFeedback.StringValue;
|
||||
Panel.StringInput[3].StringValue = McServerUrlFeedback.StringValue;
|
||||
Panel.StringInput[4].StringValue = UserCodeFeedback.StringValue;
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the URL with the correct IP address based on the connected devices and the Crestron processor's IP address.
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
private string GetUrlWithCorrectIp(string url)
|
||||
{
|
||||
var lanAdapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter);
|
||||
|
||||
var processorIp = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, lanAdapterId);
|
||||
|
||||
if(csIpAddress == null || csSubnetMask == null || url == null)
|
||||
{
|
||||
this.LogWarning("CS IP Address Subnet Mask or url is null, cannot determine correct IP for URL");
|
||||
return url;
|
||||
}
|
||||
|
||||
this.LogVerbose("Processor IP: {processorIp}, CS IP: {csIpAddress}, CS Subnet Mask: {csSubnetMask}", processorIp, csIpAddress, csSubnetMask);
|
||||
this.LogVerbose("Connected IP Count: {connectedIps}", ConnectedIps.Count);
|
||||
|
||||
var ip = ConnectedIps.Any(ipInfo =>
|
||||
{
|
||||
if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp))
|
||||
{
|
||||
return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask);
|
||||
}
|
||||
this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress);
|
||||
return false;
|
||||
}) ? csIpAddress.ToString() : processorIp;
|
||||
|
||||
var match = Regex.Match(url, @"^http://([^:/]+):\d+/mc/app\?token=.+$");
|
||||
if (match.Success)
|
||||
{
|
||||
string ipa = match.Groups[1].Value;
|
||||
// ip will be "192.168.1.100"
|
||||
}
|
||||
|
||||
// replace ipa with ip but leave the rest of the string intact
|
||||
var updatedUrl = Regex.Replace(url, @"^http://[^:/]+", $"http://{ip}");
|
||||
|
||||
this.LogVerbose("Updated URL: {updatedUrl}", updatedUrl);
|
||||
|
||||
return updatedUrl;
|
||||
}
|
||||
|
||||
private void SubscribeForMobileControlUpdates()
|
||||
{
|
||||
foreach (var dev in DeviceManager.AllDevices)
|
||||
@@ -443,7 +519,8 @@ namespace PepperDash.Essentials.Touchpanel
|
||||
/// </summary>
|
||||
public void SetAppUrl(string url)
|
||||
{
|
||||
_appUrl = url;
|
||||
_appUrl = GetUrlWithCorrectIp(url);
|
||||
|
||||
AppUrlFeedback.FireUpdate();
|
||||
}
|
||||
|
||||
|
||||
@@ -327,18 +327,22 @@ namespace PepperDash.Essentials.WebSocketServer
|
||||
}
|
||||
|
||||
string ip = processorIp;
|
||||
if (touchpanel.Touchpanel is IMobileControlCrestronTouchpanelController crestronTouchpanel && csIpAddress != null)
|
||||
{
|
||||
ip = crestronTouchpanel.ConnectedIps.Any(ipInfo =>
|
||||
{
|
||||
if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp))
|
||||
{
|
||||
return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask);
|
||||
}
|
||||
this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress);
|
||||
return false;
|
||||
}) ? csIpAddress.ToString() : processorIp;
|
||||
}
|
||||
|
||||
// Moved to the MobileControlTouchpanelController class in the GetUrlWithCorrectIp method
|
||||
// triggered by the Panel.IpInformationChange event so that we know we have the necessary info
|
||||
// to make the determination of which IP to use.
|
||||
//if (touchpanel.Touchpanel is IMobileControlCrestronTouchpanelController crestronTouchpanel && csIpAddress != null)
|
||||
//{
|
||||
// ip = crestronTouchpanel.ConnectedIps.Any(ipInfo =>
|
||||
// {
|
||||
// if (System.Net.IPAddress.TryParse(ipInfo.DeviceIpAddress, out var parsedIp))
|
||||
// {
|
||||
// return csIpAddress.IsInSameSubnet(parsedIp, csSubnetMask);
|
||||
// }
|
||||
// this.LogWarning("Invalid IP address: {deviceIpAddress}", ipInfo.DeviceIpAddress);
|
||||
// return false;
|
||||
// }) ? csIpAddress.ToString() : processorIp;
|
||||
//}
|
||||
|
||||
var appUrl = $"http://{ip}:{_parent.Config.DirectServer.Port}/mc/app?token={touchpanel.Key}";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user