feat: add RoutingFeedbackManager

RoutingFeedbackManager keeps track of updates from IRoutingSinkWotjFeedbacl devoces & IRoutingWithFeedback devices to allow for walking tieLines and finding a source.
This commit is contained in:
Andrew Welker
2024-05-08 08:37:26 -05:00
parent e3e7add5b9
commit 19bd5723c8
15 changed files with 98 additions and 34 deletions

View File

@@ -5,6 +5,7 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.Reflection; using Crestron.SimplSharp.Reflection;
using Newtonsoft.Json; using Newtonsoft.Json;
@@ -82,7 +83,8 @@ namespace PepperDash.Essentials.Core
var convertedParams = mParams var convertedParams = mParams
.Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) .Select((p, i) => ConvertType(action.Params[i], p.ParameterType))
.ToArray(); .ToArray();
method.Invoke(obj, convertedParams);
Task.Run(() => method.Invoke(obj, convertedParams));
CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name, CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name,
action.DeviceKey); action.DeviceKey);

View File

@@ -70,7 +70,7 @@ namespace PepperDash.Essentials.Core.Devices
{ {
public LaptopFactory() public LaptopFactory()
{ {
TypeNames = new List<string>() { "laptop" }; TypeNames = new List<string>() { "deprecated" };
} }
public override EssentialsDevice BuildDevice(DeviceConfig dc) public override EssentialsDevice BuildDevice(DeviceConfig dc)

View File

@@ -161,8 +161,11 @@ namespace PepperDash.Essentials.Core
Icon = "Blank"; Icon = "Blank";
} }
public override string ToString()
} {
return $"{SourceKey}:{Name}";
}
}
public class SourceRouteListItem public class SourceRouteListItem
{ {

View File

@@ -8,7 +8,7 @@ using PepperDash.Core;
namespace PepperDash.Essentials.Core.Routing namespace PepperDash.Essentials.Core.Routing
{ {
public class DummyRoutingInputsDevice : Device, IRoutingSource public class DummyRoutingInputsDevice : Device, IRoutingSource, IRoutingOutputs
{ {
/// <summary> /// <summary>
/// A single output port, backplane, audioVideo /// A single output port, backplane, audioVideo

View File

@@ -3,7 +3,7 @@
/// <summary> /// <summary>
/// Defines an IRoutingOutputs devices as being a source - the start of the chain /// Defines an IRoutingOutputs devices as being a source - the start of the chain
/// </summary> /// </summary>
public interface IRoutingSource : IRoutingOutputs public interface IRoutingSource
{ {
} }
} }

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
namespace PepperDash.Essentials.Core.Routing namespace PepperDash.Essentials.Core.Routing
{ {
@@ -48,7 +49,14 @@ namespace PepperDash.Essentials.Core.Routing
private void HandleSinkUpdate(IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort) private void HandleSinkUpdate(IRoutingSinkWithSwitching sender, RoutingInputPort currentInputPort)
{ {
UpdateDestination(sender, currentInputPort); try
{
UpdateDestination(sender, currentInputPort);
}
catch (Exception ex)
{
Debug.LogMessage(ex, "Error handling Sink update from {senderKey}:{Exception}", this, sender.Key, ex);
}
} }
private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort) private void UpdateDestination(IRoutingSinkWithSwitching destination, RoutingInputPort inputPort)
@@ -66,7 +74,9 @@ namespace PepperDash.Essentials.Core.Routing
return; return;
} }
var sourceTieLine = GetRootTieLine(firstTieLine); Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Getting source for first TieLine {tieLine}", this, firstTieLine);
var sourceTieLine = GetRootTieLine(firstTieLine);
if (sourceTieLine == null) if (sourceTieLine == null)
{ {
@@ -76,6 +86,7 @@ namespace PepperDash.Essentials.Core.Routing
destination.CurrentSourceInfoKey = string.Empty; destination.CurrentSourceInfoKey = string.Empty;
} }
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root TieLine {tieLine}", this, sourceTieLine);
// Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet. // Does not handle combinable scenarios or other scenarios where a display might be part of multiple rooms yet.
var room = DeviceManager.AllDevices.OfType<IEssentialsRoom>().FirstOrDefault((r) => { var room = DeviceManager.AllDevices.OfType<IEssentialsRoom>().FirstOrDefault((r) => {
@@ -90,7 +101,7 @@ namespace PepperDash.Essentials.Core.Routing
} }
return false; return false;
}) ; });
if(room == null) if(room == null)
{ {
@@ -98,6 +109,8 @@ namespace PepperDash.Essentials.Core.Routing
return; return;
} }
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found room {room} for destination {destination}", this, room.Key, destination.Key);
var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey);
if (sourceList == null) if (sourceList == null)
@@ -106,7 +119,18 @@ namespace PepperDash.Essentials.Core.Routing
return; return;
} }
var sourceListItem = sourceList.FirstOrDefault(sli => sli.Value.SourceKey == sourceTieLine.SourcePort.ParentDevice.Key); Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found sourceList for room {room}", this, room.Key);
var sourceListItem = sourceList.FirstOrDefault(sli => {
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose,
"SourceListItem {sourceListItem}:{sourceKey} tieLine sourceport device key {sourcePortDeviceKey}",
this,
sli.Key,
sli.Value.SourceKey,
sourceTieLine.SourcePort.ParentDevice.Key);
return sli.Value.SourceKey.Equals(sourceTieLine.SourcePort.ParentDevice.Key,StringComparison.InvariantCultureIgnoreCase);
});
var source = sourceListItem.Value; var source = sourceListItem.Value;
@@ -119,6 +143,8 @@ namespace PepperDash.Essentials.Core.Routing
return; return;
} }
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Got Source {source}", this, source);
destination.CurrentSourceInfo = source; destination.CurrentSourceInfo = source;
destination.CurrentSourceInfoKey = source.SourceKey; destination.CurrentSourceInfoKey = source.SourceKey;
} }
@@ -129,6 +155,8 @@ namespace PepperDash.Essentials.Core.Routing
if(tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint) if(tieLine.SourcePort.ParentDevice is IRoutingWithFeedback midpoint)
{ {
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source device is midpoint", this);
var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => route.OutputPort.Key == tieLine.SourcePort.Key); var currentRoute = midpoint.CurrentRoutes.FirstOrDefault(route => route.OutputPort.Key == tieLine.SourcePort.Key);
if(currentRoute == null) if(currentRoute == null)
@@ -147,8 +175,12 @@ namespace PepperDash.Essentials.Core.Routing
return tieLine; return tieLine;
} }
if(tieLine.SourcePort.ParentDevice is IRoutingSource) //end of the chain Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLIne Source Device {sourceDeviceKey} is IRoutingSource: {isIRoutingSource}", this,tieLine.SourcePort.ParentDevice.Key, tieLine.SourcePort.ParentDevice is IRoutingSource);
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "TieLine Source Device interfaces: {typeFullName}:{interfaces}",this, tieLine.SourcePort.ParentDevice.GetType().FullName, tieLine.SourcePort.ParentDevice.GetType().GetInterfaces().Select(i => i.Name));
if(tieLine.SourcePort.ParentDevice is IRoutingSource || tieLine.SourcePort.ParentDevice is IRoutingOutputs) //end of the chain
{ {
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, "Found root: {tieLine}", this, tieLine);
return tieLine; return tieLine;
} }
@@ -159,7 +191,7 @@ namespace PepperDash.Essentials.Core.Routing
return GetRootTieLine(nextTieLine); return GetRootTieLine(nextTieLine);
} }
return nextTieLine; return null;
} }
} }
} }

View File

@@ -28,7 +28,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays
return _currentInputPort; return _currentInputPort;
} }
private set protected set
{ {
_currentInputPort = value; _currentInputPort = value;

View File

@@ -140,18 +140,40 @@ namespace PepperDash.Essentials.Devices.Common.Displays
public override void ExecuteSwitch(object selector) public override void ExecuteSwitch(object selector)
{ {
Debug.LogMessage(LogEventLevel.Verbose, this, "ExecuteSwitch: {0}", selector); try
{
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector);
if (!_PowerIsOn) if (!_PowerIsOn)
{ {
PowerOn(); PowerOn();
} }
if (!Inputs.Items.TryGetValue(selector.ToString(), out var input)) if (!Inputs.Items.TryGetValue(selector.ToString(), out var input))
return; return;
input.Select(); Debug.LogMessage(LogEventLevel.Verbose, "Selected input: {input}", this, input.Key);
} input.Select();
var inputPort = InputPorts.FirstOrDefault(port =>
{
Debug.LogMessage(LogEventLevel.Verbose, "Checking input port {inputPort} with selector {portSelector} against {selector}", this, port, port.Selector, selector);
return port.Selector.ToString() == selector.ToString();
});
if (inputPort == null)
{
Debug.LogMessage(LogEventLevel.Verbose, "Unable to find input port for selector {selector}", this, selector);
return;
}
Debug.LogMessage(LogEventLevel.Verbose, "Setting current input port to {inputPort}", this, inputPort);
CurrentInputPort = inputPort;
} catch (Exception ex)
{
Debug.LogMessage(ex, "Error making switch: {Exception}", this);
}
}
public void SetInput(string selector) public void SetInput(string selector)
{ {

View File

@@ -14,7 +14,7 @@ using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common namespace PepperDash.Essentials.Devices.Common
{ {
public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IRoutingOutputs, IUsageTracking
{ {
public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } } public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } }

View File

@@ -20,7 +20,7 @@ using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common namespace PepperDash.Essentials.Devices.Common
{ {
[Description("Wrapper class for an IR Set Top Box")] [Description("Wrapper class for an IR Set Top Box")]
public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IUsageTracking, IHasPowerControl, ITvPresetsProvider public class IRSetTopBoxBase : EssentialsBridgeableDevice, ISetTopBoxControls, IRoutingSource, IRoutingOutputs, IUsageTracking, IHasPowerControl, ITvPresetsProvider
{ {
public IrOutputPortController IrPort { get; private set; } public IrOutputPortController IrPort { get; private set; }

View File

@@ -9,7 +9,7 @@ using System.Linq;
namespace PepperDash.Essentials.Devices.Common.SoftCodec namespace PepperDash.Essentials.Devices.Common.SoftCodec
{ {
public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingSinkWithSwitching public class GenericSoftCodec : EssentialsDevice, IRoutingSource, IRoutingOutputs, IRoutingSinkWithSwitching
{ {
private RoutingInputPort _currentInputPort; private RoutingInputPort _currentInputPort;
public RoutingInputPort CurrentInputPort { public RoutingInputPort CurrentInputPort {

View File

@@ -8,7 +8,7 @@ using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Sources namespace PepperDash.Essentials.Devices.Common.Sources
{ {
public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking
{ {
public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } }
public string IconName { get; set; } public string IconName { get; set; }

View File

@@ -8,7 +8,7 @@ using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Sources namespace PepperDash.Essentials.Devices.Common.Sources
{ {
public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking public class Laptop : EssentialsDevice, IHasFeedback, IRoutingSource, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking
{ {
public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } } public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } }
public string IconName { get; set; } public string IconName { get; set; }
@@ -29,11 +29,15 @@ namespace PepperDash.Essentials.Devices.Common.Sources
: base(key, name) : base(key, name)
{ {
IconName = "Laptop"; IconName = "Laptop";
HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback", HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback",
() => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus); () => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus);
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
OutputPorts.Add(AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, OutputPorts = new RoutingPortCollection<RoutingOutputPort>
eRoutingPortConnectionType.None, 0, this)); {
(AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.None, 0, this))
};
} }
#region IHasFeedback Members #region IHasFeedback Members

View File

@@ -19,8 +19,9 @@ using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common namespace PepperDash.Essentials.Devices.Common
{ {
[Description("Wrapper class for an IR-Controlled AppleTV")] [Description("Wrapper class for an IR-Controlled AppleTV")]
public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs
{
{
public IrOutputPortController IrPort { get; private set; } public IrOutputPortController IrPort { get; private set; }
public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir"; public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir";
public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } } public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } }

View File

@@ -15,7 +15,7 @@ using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common namespace PepperDash.Essentials.Devices.Common
{ {
[Description("Wrapper class for an IR-Controlled Roku")] [Description("Wrapper class for an IR-Controlled Roku")]
public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource public class Roku2 : EssentialsDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingSource, IRoutingOutputs
{ {
[Api] [Api]
public IrOutputPortController IrPort { get; private set; } public IrOutputPortController IrPort { get; private set; }