mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-04-15 05:27:16 +00:00
chore: move all files to file-scoped namespace
This commit is contained in:
parent
aaa5b0532b
commit
3ece4f0b7b
522 changed files with 39628 additions and 45678 deletions
|
|
@ -9,65 +9,66 @@ using PepperDash.Essentials.Core.Bridges;
|
|||
using PepperDash.Essentials.Core.Config;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Common.Displays
|
||||
namespace PepperDash.Essentials.Devices.Common.Displays;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a basic IR controlled display device. This class is intended to be used for simple displays that are controlled via IR and do not have a more robust API. It provides basic power and volume controls, as well as input switching via IR commands.
|
||||
/// </summary>
|
||||
public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a BasicIrDisplay
|
||||
/// Gets or sets the IrPort
|
||||
/// </summary>
|
||||
public class BasicIrDisplay : DisplayBase, IBasicVolumeControls, IBridgeAdvanced
|
||||
public IrOutputPortController IrPort { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the IrPulseTime
|
||||
/// </summary>
|
||||
public ushort IrPulseTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the power is on feedback function
|
||||
/// </summary>
|
||||
protected Func<bool> PowerIsOnFeedbackFunc
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the IrPort
|
||||
/// </summary>
|
||||
public IrOutputPortController IrPort { get; private set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the IrPulseTime
|
||||
/// </summary>
|
||||
public ushort IrPulseTime { get; set; }
|
||||
get { return () => _PowerIsOn; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the power is on feedback function
|
||||
/// </summary>
|
||||
protected Func<bool> PowerIsOnFeedbackFunc
|
||||
{
|
||||
get { return () => _PowerIsOn; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the is cooling down feedback function
|
||||
/// </summary>
|
||||
protected override Func<bool> IsCoolingDownFeedbackFunc
|
||||
{
|
||||
get { return () => _IsCoolingDown; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the is warming up feedback function
|
||||
/// </summary>
|
||||
protected override Func<bool> IsWarmingUpFeedbackFunc
|
||||
{
|
||||
get { return () => _IsWarmingUp; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the is cooling down feedback function
|
||||
/// </summary>
|
||||
protected override Func<bool> IsCoolingDownFeedbackFunc
|
||||
{
|
||||
get { return () => _IsCoolingDown; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the is warming up feedback function
|
||||
/// </summary>
|
||||
protected override Func<bool> IsWarmingUpFeedbackFunc
|
||||
{
|
||||
get { return () => _IsWarmingUp; }
|
||||
}
|
||||
|
||||
bool _PowerIsOn;
|
||||
bool _IsWarmingUp;
|
||||
bool _IsCoolingDown;
|
||||
bool _PowerIsOn;
|
||||
bool _IsWarmingUp;
|
||||
bool _IsCoolingDown;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BasicIrDisplay class
|
||||
/// </summary>
|
||||
/// <param name="key">The device key</param>
|
||||
/// <param name="name">The device name</param>
|
||||
/// <param name="port">The IR output port</param>
|
||||
/// <param name="irDriverFilepath">The path to the IR driver file</param>
|
||||
public BasicIrDisplay(string key, string name, IROutputPort port, string irDriverFilepath)
|
||||
: base(key, name)
|
||||
{
|
||||
IrPort = new IrOutputPortController(key + "-ir", port, irDriverFilepath);
|
||||
DeviceManager.AddDevice(IrPort);
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BasicIrDisplay class
|
||||
/// </summary>
|
||||
/// <param name="key">The device key</param>
|
||||
/// <param name="name">The device name</param>
|
||||
/// <param name="port">The IR output port</param>
|
||||
/// <param name="irDriverFilepath">The path to the IR driver file</param>
|
||||
public BasicIrDisplay(string key, string name, IROutputPort port, string irDriverFilepath)
|
||||
: base(key, name)
|
||||
{
|
||||
IrPort = new IrOutputPortController(key + "-ir", port, irDriverFilepath);
|
||||
DeviceManager.AddDevice(IrPort);
|
||||
|
||||
IsWarmingUpFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Warming up={0}", _IsWarmingUp);
|
||||
IsCoolingDownFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Cooling down={0}", _IsCoolingDown);
|
||||
IsWarmingUpFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Warming up={0}", _IsWarmingUp);
|
||||
IsCoolingDownFeedback.OutputChange += (o, a) => Debug.LogMessage(LogEventLevel.Verbose, this, "Cooling down={0}", _IsCoolingDown);
|
||||
|
||||
InputPorts.AddRange(new RoutingPortCollection<RoutingInputPort>
|
||||
InputPorts.AddRange(new RoutingPortCollection<RoutingInputPort>
|
||||
{
|
||||
new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
||||
eRoutingPortConnectionType.Hdmi, new Action(Hdmi1), this, false),
|
||||
|
|
@ -84,224 +85,223 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
|||
new RoutingInputPort(RoutingPortNames.AntennaIn, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
||||
eRoutingPortConnectionType.Hdmi, new Action(Antenna), this, false),
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hdmi1 method
|
||||
/// </summary>
|
||||
public void Hdmi1()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_1, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hdmi2 method
|
||||
/// </summary>
|
||||
public void Hdmi2()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_2, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hdmi3 method
|
||||
/// </summary>
|
||||
public void Hdmi3()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_3, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hdmi4 method
|
||||
/// </summary>
|
||||
public void Hdmi4()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_4, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Component1 method
|
||||
/// </summary>
|
||||
public void Component1()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_COMPONENT_1, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Video1 method
|
||||
/// </summary>
|
||||
public void Video1()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_VIDEO_1, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Antenna method
|
||||
/// </summary>
|
||||
public void Antenna()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_ANTENNA, IrPulseTime);
|
||||
}
|
||||
|
||||
#region IPower Members
|
||||
|
||||
/// <summary>
|
||||
/// PowerOn method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override void PowerOn()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime);
|
||||
_PowerIsOn = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PowerOff method
|
||||
/// </summary>
|
||||
public override void PowerOff()
|
||||
{
|
||||
_PowerIsOn = false;
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PowerToggle method
|
||||
/// </summary>
|
||||
public override void PowerToggle()
|
||||
{
|
||||
_PowerIsOn = false;
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBasicVolumeControls Members
|
||||
|
||||
/// <summary>
|
||||
/// VolumeUp method
|
||||
/// </summary>
|
||||
public void VolumeUp(bool pressRelease)
|
||||
{
|
||||
IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_PLUS, pressRelease);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// VolumeDown method
|
||||
/// </summary>
|
||||
public void VolumeDown(bool pressRelease)
|
||||
{
|
||||
IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_MINUS, pressRelease);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MuteToggle method
|
||||
/// </summary>
|
||||
public void MuteToggle()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_MUTE, 200);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
void StartWarmingTimer()
|
||||
{
|
||||
_IsWarmingUp = true;
|
||||
IsWarmingUpFeedback.FireUpdate();
|
||||
new CTimer(o =>
|
||||
{
|
||||
_IsWarmingUp = false;
|
||||
IsWarmingUpFeedback.FireUpdate();
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
void StartCoolingTimer()
|
||||
{
|
||||
_IsCoolingDown = true;
|
||||
IsCoolingDownFeedback.FireUpdate();
|
||||
new CTimer(o =>
|
||||
{
|
||||
_IsCoolingDown = false;
|
||||
IsCoolingDownFeedback.FireUpdate();
|
||||
}, 7000);
|
||||
}
|
||||
|
||||
#region IRoutingSink Members
|
||||
|
||||
/// <summary>
|
||||
/// Typically called by the discovery routing algorithm.
|
||||
/// </summary>
|
||||
/// <param name="inputSelector">A delegate containing the input selector method to call</param>
|
||||
/// <summary>
|
||||
/// ExecuteSwitch method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override void ExecuteSwitch(object inputSelector)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString());
|
||||
|
||||
Action finishSwitch = () =>
|
||||
{
|
||||
var action = inputSelector as Action;
|
||||
if (action != null)
|
||||
action();
|
||||
};
|
||||
|
||||
if (!_PowerIsOn)
|
||||
{
|
||||
PowerOn();
|
||||
EventHandler<FeedbackEventArgs> oneTimer = null;
|
||||
oneTimer = (o, a) =>
|
||||
{
|
||||
if (IsWarmingUpFeedback.BoolValue) return; // Only catch done warming
|
||||
IsWarmingUpFeedback.OutputChange -= oneTimer;
|
||||
finishSwitch();
|
||||
};
|
||||
IsWarmingUpFeedback.OutputChange += oneTimer;
|
||||
}
|
||||
else // Do it!
|
||||
finishSwitch();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// LinkToApi method
|
||||
/// </summary>
|
||||
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
||||
{
|
||||
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a BasicIrDisplayFactory
|
||||
/// Hdmi1 method
|
||||
/// </summary>
|
||||
public class BasicIrDisplayFactory : EssentialsDeviceFactory<BasicIrDisplay>
|
||||
public void Hdmi1()
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BasicIrDisplayFactory class
|
||||
/// </summary>
|
||||
public BasicIrDisplayFactory()
|
||||
{
|
||||
TypeNames = new List<string>() { "basicirdisplay" };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BuildDevice method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BasicIrDisplay Device");
|
||||
var ir = IRPortHelper.GetIrPort(dc.Properties);
|
||||
if (ir != null)
|
||||
{
|
||||
var display = new BasicIrDisplay(dc.Key, dc.Name, ir.Port, ir.FileName);
|
||||
display.IrPulseTime = 200; // Set default pulse time for IR commands.
|
||||
return display;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_1, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hdmi2 method
|
||||
/// </summary>
|
||||
public void Hdmi2()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_2, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hdmi3 method
|
||||
/// </summary>
|
||||
public void Hdmi3()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_3, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hdmi4 method
|
||||
/// </summary>
|
||||
public void Hdmi4()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_HDMI_4, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Component1 method
|
||||
/// </summary>
|
||||
public void Component1()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_COMPONENT_1, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Video1 method
|
||||
/// </summary>
|
||||
public void Video1()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_VIDEO_1, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Antenna method
|
||||
/// </summary>
|
||||
public void Antenna()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_ANTENNA, IrPulseTime);
|
||||
}
|
||||
|
||||
#region IPower Members
|
||||
|
||||
/// <summary>
|
||||
/// PowerOn method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override void PowerOn()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_ON, IrPulseTime);
|
||||
_PowerIsOn = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PowerOff method
|
||||
/// </summary>
|
||||
public override void PowerOff()
|
||||
{
|
||||
_PowerIsOn = false;
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_POWER_OFF, IrPulseTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PowerToggle method
|
||||
/// </summary>
|
||||
public override void PowerToggle()
|
||||
{
|
||||
_PowerIsOn = false;
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_POWER, IrPulseTime);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBasicVolumeControls Members
|
||||
|
||||
/// <summary>
|
||||
/// VolumeUp method
|
||||
/// </summary>
|
||||
public void VolumeUp(bool pressRelease)
|
||||
{
|
||||
IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_PLUS, pressRelease);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// VolumeDown method
|
||||
/// </summary>
|
||||
public void VolumeDown(bool pressRelease)
|
||||
{
|
||||
IrPort.PressRelease(IROutputStandardCommands.IROut_VOL_MINUS, pressRelease);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MuteToggle method
|
||||
/// </summary>
|
||||
public void MuteToggle()
|
||||
{
|
||||
IrPort.Pulse(IROutputStandardCommands.IROut_MUTE, 200);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
void StartWarmingTimer()
|
||||
{
|
||||
_IsWarmingUp = true;
|
||||
IsWarmingUpFeedback.FireUpdate();
|
||||
new CTimer(o =>
|
||||
{
|
||||
_IsWarmingUp = false;
|
||||
IsWarmingUpFeedback.FireUpdate();
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
void StartCoolingTimer()
|
||||
{
|
||||
_IsCoolingDown = true;
|
||||
IsCoolingDownFeedback.FireUpdate();
|
||||
new CTimer(o =>
|
||||
{
|
||||
_IsCoolingDown = false;
|
||||
IsCoolingDownFeedback.FireUpdate();
|
||||
}, 7000);
|
||||
}
|
||||
|
||||
#region IRoutingSink Members
|
||||
|
||||
/// <summary>
|
||||
/// Typically called by the discovery routing algorithm.
|
||||
/// </summary>
|
||||
/// <param name="inputSelector">A delegate containing the input selector method to call</param>
|
||||
/// <summary>
|
||||
/// ExecuteSwitch method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override void ExecuteSwitch(object inputSelector)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Switching to input '{0}'", (inputSelector as Action).ToString());
|
||||
|
||||
Action finishSwitch = () =>
|
||||
{
|
||||
var action = inputSelector as Action;
|
||||
if (action != null)
|
||||
action();
|
||||
};
|
||||
|
||||
if (!_PowerIsOn)
|
||||
{
|
||||
PowerOn();
|
||||
EventHandler<FeedbackEventArgs> oneTimer = null;
|
||||
oneTimer = (o, a) =>
|
||||
{
|
||||
if (IsWarmingUpFeedback.BoolValue) return; // Only catch done warming
|
||||
IsWarmingUpFeedback.OutputChange -= oneTimer;
|
||||
finishSwitch();
|
||||
};
|
||||
IsWarmingUpFeedback.OutputChange += oneTimer;
|
||||
}
|
||||
else // Do it!
|
||||
finishSwitch();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// LinkToApi method
|
||||
/// </summary>
|
||||
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
||||
{
|
||||
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating BasicIrDisplay devices
|
||||
/// </summary>
|
||||
public class BasicIrDisplayFactory : EssentialsDeviceFactory<BasicIrDisplay>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the BasicIrDisplayFactory class
|
||||
/// </summary>
|
||||
public BasicIrDisplayFactory()
|
||||
{
|
||||
TypeNames = new List<string>() { "basicirdisplay" };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BuildDevice method
|
||||
/// </summary>
|
||||
/// <param name="dc"></param>
|
||||
/// <returns></returns>
|
||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new BasicIrDisplay Device");
|
||||
var ir = IRPortHelper.GetIrPort(dc.Properties);
|
||||
if (ir != null)
|
||||
{
|
||||
var display = new BasicIrDisplay(dc.Key, dc.Name, ir.Port, ir.FileName);
|
||||
display.IrPulseTime = 200; // Set default pulse time for IR commands.
|
||||
return display;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,426 +13,425 @@ using PepperDash.Essentials.Core.Routing;
|
|||
using Serilog.Events;
|
||||
using Feedback = PepperDash.Essentials.Core.Feedback;
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Common.Displays
|
||||
namespace PepperDash.Essentials.Devices.Common.Displays;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract base class for display devices that provides common display functionality
|
||||
/// including power control, input switching, and routing capabilities.
|
||||
/// </summary>
|
||||
public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources, IHasFeedback
|
||||
{
|
||||
private RoutingInputPort _currentInputPort;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract base class for display devices that provides common display functionality
|
||||
/// including power control, input switching, and routing capabilities.
|
||||
/// Gets or sets the current input port that is selected on the display.
|
||||
/// </summary>
|
||||
public abstract class DisplayBase : EssentialsDevice, IDisplay, ICurrentSources, IHasFeedback
|
||||
public RoutingInputPort CurrentInputPort
|
||||
{
|
||||
private RoutingInputPort _currentInputPort;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current input port that is selected on the display.
|
||||
/// </summary>
|
||||
public RoutingInputPort CurrentInputPort
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentInputPort;
|
||||
}
|
||||
|
||||
protected set
|
||||
{
|
||||
if (_currentInputPort == value) return;
|
||||
|
||||
_currentInputPort = value;
|
||||
|
||||
InputChanged?.Invoke(this, _currentInputPort);
|
||||
}
|
||||
return _currentInputPort;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that is raised when the input changes on the display.
|
||||
/// </summary>
|
||||
public event InputChangedEventHandler InputChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Event that is raised when the current source information changes.
|
||||
/// </summary>
|
||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CurrentSourceInfoKey
|
||||
/// </summary>
|
||||
public string CurrentSourceInfoKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current source information for the display.
|
||||
/// </summary>
|
||||
public SourceListItem CurrentSourceInfo
|
||||
protected set
|
||||
{
|
||||
get
|
||||
{
|
||||
return _CurrentSourceInfo;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == _CurrentSourceInfo) return;
|
||||
if (_currentInputPort == value) return;
|
||||
|
||||
var handler = CurrentSourceChange;
|
||||
_currentInputPort = value;
|
||||
|
||||
handler?.Invoke(_CurrentSourceInfo, ChangeType.WillChange);
|
||||
|
||||
_CurrentSourceInfo = value;
|
||||
|
||||
handler?.Invoke(_CurrentSourceInfo, ChangeType.DidChange);
|
||||
}
|
||||
InputChanged?.Invoke(this, _currentInputPort);
|
||||
}
|
||||
SourceListItem _CurrentSourceInfo;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Dictionary<eRoutingSignalType, SourceListItem> CurrentSources { get; private set; }
|
||||
/// <summary>
|
||||
/// Event that is raised when the input changes on the display.
|
||||
/// </summary>
|
||||
public event InputChangedEventHandler InputChanged;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; private set; }
|
||||
/// <summary>
|
||||
/// Event that is raised when the current source information changes.
|
||||
/// </summary>
|
||||
public event SourceInfoChangeHandler CurrentSourceChange;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler CurrentSourcesChanged;
|
||||
/// <summary>
|
||||
/// Gets or sets the CurrentSourceInfoKey
|
||||
/// </summary>
|
||||
public string CurrentSourceInfoKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets feedback indicating whether the display is currently cooling down after being powered off.
|
||||
/// </summary>
|
||||
public BoolFeedback IsCoolingDownFeedback { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the IsWarmingUpFeedback
|
||||
/// </summary>
|
||||
public BoolFeedback IsWarmingUpFeedback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the UsageTracker
|
||||
/// </summary>
|
||||
public UsageTracking UsageTracker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the WarmupTime
|
||||
/// </summary>
|
||||
public uint WarmupTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CooldownTime
|
||||
/// </summary>
|
||||
public uint CooldownTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Abstract function that must be implemented by derived classes to provide the cooling down feedback value.
|
||||
/// Must be implemented by concrete sub-classes.
|
||||
/// </summary>
|
||||
abstract protected Func<bool> IsCoolingDownFeedbackFunc { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Abstract function that must be implemented by derived classes to provide the warming up feedback value.
|
||||
/// Must be implemented by concrete sub-classes.
|
||||
/// </summary>
|
||||
abstract protected Func<bool> IsWarmingUpFeedbackFunc { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Timer used for managing display warmup timing.
|
||||
/// </summary>
|
||||
protected CTimer WarmupTimer;
|
||||
|
||||
/// <summary>
|
||||
/// Timer used for managing display cooldown timing.
|
||||
/// </summary>
|
||||
protected CTimer CooldownTimer;
|
||||
|
||||
#region IRoutingInputs Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of input ports available on this display device.
|
||||
/// </summary>
|
||||
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the DisplayBase class.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key identifier for this display device.</param>
|
||||
/// <param name="name">The friendly name for this display device.</param>
|
||||
protected DisplayBase(string key, string name)
|
||||
: base(key, name)
|
||||
/// <summary>
|
||||
/// Gets or sets the current source information for the display.
|
||||
/// </summary>
|
||||
public SourceListItem CurrentSourceInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
IsCoolingDownFeedback = new BoolFeedback("IsCoolingDown", IsCoolingDownFeedbackFunc);
|
||||
IsWarmingUpFeedback = new BoolFeedback("IsWarmingUp", IsWarmingUpFeedbackFunc);
|
||||
return _CurrentSourceInfo;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == _CurrentSourceInfo) return;
|
||||
|
||||
Feedbacks.Add(IsCoolingDownFeedback);
|
||||
Feedbacks.Add(IsWarmingUpFeedback);
|
||||
var handler = CurrentSourceChange;
|
||||
|
||||
InputPorts = new RoutingPortCollection<RoutingInputPort>();
|
||||
handler?.Invoke(_CurrentSourceInfo, ChangeType.WillChange);
|
||||
|
||||
CurrentSources = new Dictionary<eRoutingSignalType, SourceListItem>
|
||||
_CurrentSourceInfo = value;
|
||||
|
||||
handler?.Invoke(_CurrentSourceInfo, ChangeType.DidChange);
|
||||
}
|
||||
}
|
||||
SourceListItem _CurrentSourceInfo;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Dictionary<eRoutingSignalType, SourceListItem> CurrentSources { get; private set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Dictionary<eRoutingSignalType, string> CurrentSourceKeys { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler CurrentSourcesChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets feedback indicating whether the display is currently cooling down after being powered off.
|
||||
/// </summary>
|
||||
public BoolFeedback IsCoolingDownFeedback { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the IsWarmingUpFeedback
|
||||
/// </summary>
|
||||
public BoolFeedback IsWarmingUpFeedback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the UsageTracker
|
||||
/// </summary>
|
||||
public UsageTracking UsageTracker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the WarmupTime
|
||||
/// </summary>
|
||||
public uint WarmupTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the CooldownTime
|
||||
/// </summary>
|
||||
public uint CooldownTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Abstract function that must be implemented by derived classes to provide the cooling down feedback value.
|
||||
/// Must be implemented by concrete sub-classes.
|
||||
/// </summary>
|
||||
abstract protected Func<bool> IsCoolingDownFeedbackFunc { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Abstract function that must be implemented by derived classes to provide the warming up feedback value.
|
||||
/// Must be implemented by concrete sub-classes.
|
||||
/// </summary>
|
||||
abstract protected Func<bool> IsWarmingUpFeedbackFunc { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Timer used for managing display warmup timing.
|
||||
/// </summary>
|
||||
protected CTimer WarmupTimer;
|
||||
|
||||
/// <summary>
|
||||
/// Timer used for managing display cooldown timing.
|
||||
/// </summary>
|
||||
protected CTimer CooldownTimer;
|
||||
|
||||
#region IRoutingInputs Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of input ports available on this display device.
|
||||
/// </summary>
|
||||
public RoutingPortCollection<RoutingInputPort> InputPorts { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the DisplayBase class.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique key identifier for this display device.</param>
|
||||
/// <param name="name">The friendly name for this display device.</param>
|
||||
protected DisplayBase(string key, string name)
|
||||
: base(key, name)
|
||||
{
|
||||
IsCoolingDownFeedback = new BoolFeedback("IsCoolingDown", IsCoolingDownFeedbackFunc);
|
||||
IsWarmingUpFeedback = new BoolFeedback("IsWarmingUp", IsWarmingUpFeedbackFunc);
|
||||
|
||||
Feedbacks.Add(IsCoolingDownFeedback);
|
||||
Feedbacks.Add(IsWarmingUpFeedback);
|
||||
|
||||
InputPorts = new RoutingPortCollection<RoutingInputPort>();
|
||||
|
||||
CurrentSources = new Dictionary<eRoutingSignalType, SourceListItem>
|
||||
{
|
||||
{ eRoutingSignalType.Audio, null },
|
||||
{ eRoutingSignalType.Video, null },
|
||||
};
|
||||
|
||||
CurrentSourceKeys = new Dictionary<eRoutingSignalType, string>
|
||||
CurrentSourceKeys = new Dictionary<eRoutingSignalType, string>
|
||||
{
|
||||
{ eRoutingSignalType.Audio, string.Empty },
|
||||
{ eRoutingSignalType.Video, string.Empty },
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Powers on the display device. Must be implemented by derived classes.
|
||||
/// </summary>
|
||||
public abstract void PowerOn();
|
||||
|
||||
/// <summary>
|
||||
/// Powers off the display device. Must be implemented by derived classes.
|
||||
/// </summary>
|
||||
public abstract void PowerOff();
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the power state of the display device. Must be implemented by derived classes.
|
||||
/// </summary>
|
||||
public abstract void PowerToggle();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of feedback objects for this display device.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public virtual FeedbackCollection<Feedback> Feedbacks { get; private set; } = new FeedbackCollection<Feedback>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Executes a switch to the specified input on the display device. Must be implemented by derived classes.
|
||||
/// </summary>
|
||||
/// <param name="selector">The selector object that identifies which input to switch to.</param>
|
||||
public abstract void ExecuteSwitch(object selector);
|
||||
|
||||
/// <summary>
|
||||
/// Links the display device to an API using a trilist, join start, join map key, and bridge.
|
||||
/// This overload uses serialized join map configuration.
|
||||
/// </summary>
|
||||
/// <param name="displayDevice">The display device to link.</param>
|
||||
/// <param name="trilist">The BasicTriList for communication.</param>
|
||||
/// <param name="joinStart">The starting join number for the device.</param>
|
||||
/// <param name="joinMapKey">The key for the join map configuration.</param>
|
||||
/// <param name="bridge">The EISC API bridge instance.</param>
|
||||
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey,
|
||||
EiscApiAdvanced bridge)
|
||||
{
|
||||
var joinMap = new DisplayControllerJoinMap(joinStart);
|
||||
|
||||
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
|
||||
|
||||
if (!string.IsNullOrEmpty(joinMapSerialized))
|
||||
joinMap = JsonConvert.DeserializeObject<DisplayControllerJoinMap>(joinMapSerialized);
|
||||
|
||||
if (bridge != null)
|
||||
{
|
||||
bridge.AddJoinMap(Key, joinMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Powers on the display device. Must be implemented by derived classes.
|
||||
/// </summary>
|
||||
public abstract void PowerOn();
|
||||
LinkDisplayToApi(displayDevice, trilist, joinMap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Powers off the display device. Must be implemented by derived classes.
|
||||
/// </summary>
|
||||
public abstract void PowerOff();
|
||||
/// <summary>
|
||||
/// Links the display device to an API using a trilist and join map.
|
||||
/// This overload uses a pre-configured join map instance.
|
||||
/// </summary>
|
||||
/// <param name="displayDevice">The display device to link.</param>
|
||||
/// <param name="trilist">The BasicTriList for communication.</param>
|
||||
/// <param name="joinMap">The join map configuration for the device.</param>
|
||||
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, DisplayControllerJoinMap joinMap)
|
||||
{
|
||||
this.LogDebug("Linking to Trilist {ipId}", trilist.ID.ToString("X"));
|
||||
this.LogDebug("Linking to Display: {displayName}", displayDevice.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the power state of the display device. Must be implemented by derived classes.
|
||||
/// </summary>
|
||||
public abstract void PowerToggle();
|
||||
trilist.StringInput[joinMap.Name.JoinNumber].StringValue = displayDevice.Name;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection of feedback objects for this display device.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public virtual FeedbackCollection<Feedback> Feedbacks { get; private set; } = new FeedbackCollection<Feedback>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Executes a switch to the specified input on the display device. Must be implemented by derived classes.
|
||||
/// </summary>
|
||||
/// <param name="selector">The selector object that identifies which input to switch to.</param>
|
||||
public abstract void ExecuteSwitch(object selector);
|
||||
|
||||
/// <summary>
|
||||
/// Links the display device to an API using a trilist, join start, join map key, and bridge.
|
||||
/// This overload uses serialized join map configuration.
|
||||
/// </summary>
|
||||
/// <param name="displayDevice">The display device to link.</param>
|
||||
/// <param name="trilist">The BasicTriList for communication.</param>
|
||||
/// <param name="joinStart">The starting join number for the device.</param>
|
||||
/// <param name="joinMapKey">The key for the join map configuration.</param>
|
||||
/// <param name="bridge">The EISC API bridge instance.</param>
|
||||
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey,
|
||||
EiscApiAdvanced bridge)
|
||||
if (displayDevice is ICommunicationMonitor commMonitor)
|
||||
{
|
||||
var joinMap = new DisplayControllerJoinMap(joinStart);
|
||||
|
||||
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
|
||||
|
||||
if (!string.IsNullOrEmpty(joinMapSerialized))
|
||||
joinMap = JsonConvert.DeserializeObject<DisplayControllerJoinMap>(joinMapSerialized);
|
||||
|
||||
if (bridge != null)
|
||||
{
|
||||
bridge.AddJoinMap(Key, joinMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Information, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
|
||||
}
|
||||
|
||||
LinkDisplayToApi(displayDevice, trilist, joinMap);
|
||||
commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Links the display device to an API using a trilist and join map.
|
||||
/// This overload uses a pre-configured join map instance.
|
||||
/// </summary>
|
||||
/// <param name="displayDevice">The display device to link.</param>
|
||||
/// <param name="trilist">The BasicTriList for communication.</param>
|
||||
/// <param name="joinMap">The join map configuration for the device.</param>
|
||||
protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, DisplayControllerJoinMap joinMap)
|
||||
// TODO: revisit this as there could be issues with this approach
|
||||
var inputNumber = 0;
|
||||
var inputKeys = new List<string>();
|
||||
|
||||
var inputNumberFeedback = new IntFeedback("inputNumber", () => inputNumber);
|
||||
|
||||
// Add input number feedback to the device feedback collection to keep it around...
|
||||
Feedbacks.Add(inputNumberFeedback);
|
||||
|
||||
// Two way feedbacks
|
||||
if (displayDevice is TwoWayDisplayBase twoWayDisplay)
|
||||
{
|
||||
this.LogDebug("Linking to Trilist {ipId}", trilist.ID.ToString("X"));
|
||||
this.LogDebug("Linking to Display: {displayName}", displayDevice.Name);
|
||||
trilist.SetBool(joinMap.IsTwoWayDisplay.JoinNumber, true);
|
||||
|
||||
trilist.StringInput[joinMap.Name.JoinNumber].StringValue = displayDevice.Name;
|
||||
twoWayDisplay.CurrentInputFeedback.OutputChange += (o, a) => this.LogDebug("CurrentInputFeedback_OutputChange {input}", a.StringValue);
|
||||
|
||||
if (displayDevice is ICommunicationMonitor commMonitor)
|
||||
inputNumberFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputSelect.JoinNumber]);
|
||||
|
||||
twoWayDisplay.PowerIsOnFeedback.OutputChange += (o, a) =>
|
||||
{
|
||||
commMonitor.CommunicationMonitor.IsOnlineFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]);
|
||||
}
|
||||
|
||||
// TODO: revisit this as there could be issues with this approach
|
||||
var inputNumber = 0;
|
||||
var inputKeys = new List<string>();
|
||||
|
||||
var inputNumberFeedback = new IntFeedback("inputNumber", () => inputNumber);
|
||||
|
||||
// Add input number feedback to the device feedback collection to keep it around...
|
||||
Feedbacks.Add(inputNumberFeedback);
|
||||
|
||||
// Two way feedbacks
|
||||
if (displayDevice is TwoWayDisplayBase twoWayDisplay)
|
||||
{
|
||||
trilist.SetBool(joinMap.IsTwoWayDisplay.JoinNumber, true);
|
||||
|
||||
twoWayDisplay.CurrentInputFeedback.OutputChange += (o, a) => this.LogDebug("CurrentInputFeedback_OutputChange {input}", a.StringValue);
|
||||
|
||||
inputNumberFeedback.LinkInputSig(trilist.UShortInput[joinMap.InputSelect.JoinNumber]);
|
||||
|
||||
twoWayDisplay.PowerIsOnFeedback.OutputChange += (o, a) =>
|
||||
if (!a.BoolValue)
|
||||
{
|
||||
if (!a.BoolValue)
|
||||
{
|
||||
inputNumber = 102;
|
||||
inputNumberFeedback.FireUpdate();
|
||||
inputNumber = 102;
|
||||
inputNumberFeedback.FireUpdate();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
inputNumber = 0;
|
||||
inputNumberFeedback.FireUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
twoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]);
|
||||
twoWayDisplay.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]);
|
||||
}
|
||||
|
||||
// Power Off
|
||||
trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () =>
|
||||
{
|
||||
inputNumber = 102;
|
||||
inputNumberFeedback.FireUpdate();
|
||||
displayDevice.PowerOff();
|
||||
});
|
||||
|
||||
// PowerOn
|
||||
trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () =>
|
||||
{
|
||||
inputNumber = 0;
|
||||
inputNumberFeedback.FireUpdate();
|
||||
displayDevice.PowerOn();
|
||||
});
|
||||
|
||||
|
||||
for (int i = 0; i < displayDevice.InputPorts.Count; i++)
|
||||
{
|
||||
var localindex = i;
|
||||
if (localindex >= joinMap.InputNamesOffset.JoinSpan)
|
||||
{
|
||||
this.LogWarning("Device has {inputCount} inputs. The Join Map allows up to {joinSpan} inputs. Discarding inputs {discardStart} - {discardEnd} from bridge.",
|
||||
displayDevice.InputPorts.Count, joinMap.InputNamesOffset.JoinSpan, localindex + 1, displayDevice.InputPorts.Count);
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
inputKeys.Add(displayDevice.InputPorts[localindex].Key);
|
||||
|
||||
var tempKey = inputKeys.ElementAt(localindex);
|
||||
|
||||
trilist.SetSigTrueAction((ushort)(joinMap.InputSelectOffset.JoinNumber + localindex), () => displayDevice.ExecuteSwitch(displayDevice.InputPorts[tempKey].Selector));
|
||||
|
||||
this.LogDebug("Setting Input Select Action on Digital Join {joinNumber} to Input: {input}", joinMap.InputSelectOffset.JoinNumber + localindex, displayDevice.InputPorts[tempKey].Key);
|
||||
|
||||
trilist.SetString((uint)(joinMap.InputNamesOffset.JoinNumber + localindex), displayDevice.InputPorts[localindex].Key);
|
||||
}
|
||||
}
|
||||
|
||||
this.LogDebug("Setting Input Select Action on Analog Join {inputSelectJoin}", joinMap.InputSelect);
|
||||
|
||||
trilist.SetUShortSigAction(joinMap.InputSelect.JoinNumber, (requestedInput) =>
|
||||
{
|
||||
if (requestedInput == 0)
|
||||
{
|
||||
displayDevice.PowerOff();
|
||||
inputNumber = 0;
|
||||
return;
|
||||
inputNumberFeedback.FireUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
// using 1-based indexing for inputs coming from SIMPL, so need to check if the input is <= the count, not <
|
||||
if (requestedInput > 0 && requestedInput <= displayDevice.InputPorts.Count && requestedInput != inputNumber)
|
||||
{
|
||||
displayDevice.ExecuteSwitch(displayDevice.InputPorts.ElementAt(requestedInput - 1).Selector);
|
||||
|
||||
inputNumber = requestedInput;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestedInput == 102)
|
||||
{
|
||||
displayDevice.PowerToggle();
|
||||
return;
|
||||
}
|
||||
|
||||
if (displayDevice is TwoWayDisplayBase)
|
||||
{
|
||||
inputNumberFeedback?.FireUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var volumeDisplay = displayDevice as IBasicVolumeControls;
|
||||
if (volumeDisplay == null) return;
|
||||
|
||||
trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, volumeDisplay.VolumeUp);
|
||||
trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, volumeDisplay.VolumeDown);
|
||||
trilist.SetSigTrueAction(joinMap.VolumeMute.JoinNumber, volumeDisplay.MuteToggle);
|
||||
|
||||
var volumeDisplayWithFeedback = volumeDisplay as IBasicVolumeWithFeedback;
|
||||
|
||||
if (volumeDisplayWithFeedback == null) return;
|
||||
trilist.SetSigTrueAction(joinMap.VolumeMuteOn.JoinNumber, volumeDisplayWithFeedback.MuteOn);
|
||||
trilist.SetSigTrueAction(joinMap.VolumeMuteOff.JoinNumber, volumeDisplayWithFeedback.MuteOff);
|
||||
|
||||
|
||||
trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, volumeDisplayWithFeedback.SetVolume);
|
||||
volumeDisplayWithFeedback.VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]);
|
||||
volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMute.JoinNumber]);
|
||||
volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]);
|
||||
volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]);
|
||||
twoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.PowerOff.JoinNumber]);
|
||||
twoWayDisplay.PowerIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PowerOn.JoinNumber]);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
|
||||
// Power Off
|
||||
trilist.SetSigTrueAction(joinMap.PowerOff.JoinNumber, () =>
|
||||
{
|
||||
foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType)))
|
||||
{
|
||||
var flagValue = Convert.ToInt32(type);
|
||||
// Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag).
|
||||
// (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set.
|
||||
if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0)
|
||||
{
|
||||
this.LogDebug("Skipping {type}", type);
|
||||
continue;
|
||||
}
|
||||
inputNumber = 102;
|
||||
inputNumberFeedback.FireUpdate();
|
||||
displayDevice.PowerOff();
|
||||
});
|
||||
|
||||
this.LogDebug("setting {type}", type);
|
||||
|
||||
if (signalType.HasFlag(type))
|
||||
{
|
||||
UpdateCurrentSources(type, sourceListKey, sourceListItem);
|
||||
}
|
||||
}
|
||||
// Raise the CurrentSourcesChanged event
|
||||
CurrentSourcesChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
|
||||
// PowerOn
|
||||
trilist.SetSigTrueAction(joinMap.PowerOn.JoinNumber, () =>
|
||||
{
|
||||
if (CurrentSources.ContainsKey(signalType))
|
||||
inputNumber = 0;
|
||||
inputNumberFeedback.FireUpdate();
|
||||
displayDevice.PowerOn();
|
||||
});
|
||||
|
||||
|
||||
for (int i = 0; i < displayDevice.InputPorts.Count; i++)
|
||||
{
|
||||
var localindex = i;
|
||||
if (localindex >= joinMap.InputNamesOffset.JoinSpan)
|
||||
{
|
||||
CurrentSources[signalType] = sourceListItem;
|
||||
this.LogWarning("Device has {inputCount} inputs. The Join Map allows up to {joinSpan} inputs. Discarding inputs {discardStart} - {discardEnd} from bridge.",
|
||||
displayDevice.InputPorts.Count, joinMap.InputNamesOffset.JoinSpan, localindex + 1, displayDevice.InputPorts.Count);
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentSources.Add(signalType, sourceListItem);
|
||||
}
|
||||
inputKeys.Add(displayDevice.InputPorts[localindex].Key);
|
||||
|
||||
// Update the current source key for the specified signal type
|
||||
if (CurrentSourceKeys.ContainsKey(signalType))
|
||||
{
|
||||
CurrentSourceKeys[signalType] = sourceListKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentSourceKeys.Add(signalType, sourceListKey);
|
||||
var tempKey = inputKeys.ElementAt(localindex);
|
||||
|
||||
trilist.SetSigTrueAction((ushort)(joinMap.InputSelectOffset.JoinNumber + localindex), () => displayDevice.ExecuteSwitch(displayDevice.InputPorts[tempKey].Selector));
|
||||
|
||||
this.LogDebug("Setting Input Select Action on Digital Join {joinNumber} to Input: {input}", joinMap.InputSelectOffset.JoinNumber + localindex, displayDevice.InputPorts[tempKey].Key);
|
||||
|
||||
trilist.SetString((uint)(joinMap.InputNamesOffset.JoinNumber + localindex), displayDevice.InputPorts[localindex].Key);
|
||||
}
|
||||
}
|
||||
|
||||
this.LogDebug("Setting Input Select Action on Analog Join {inputSelectJoin}", joinMap.InputSelect);
|
||||
|
||||
trilist.SetUShortSigAction(joinMap.InputSelect.JoinNumber, (requestedInput) =>
|
||||
{
|
||||
if (requestedInput == 0)
|
||||
{
|
||||
displayDevice.PowerOff();
|
||||
inputNumber = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// using 1-based indexing for inputs coming from SIMPL, so need to check if the input is <= the count, not <
|
||||
if (requestedInput > 0 && requestedInput <= displayDevice.InputPorts.Count && requestedInput != inputNumber)
|
||||
{
|
||||
displayDevice.ExecuteSwitch(displayDevice.InputPorts.ElementAt(requestedInput - 1).Selector);
|
||||
|
||||
inputNumber = requestedInput;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestedInput == 102)
|
||||
{
|
||||
displayDevice.PowerToggle();
|
||||
return;
|
||||
}
|
||||
|
||||
if (displayDevice is TwoWayDisplayBase)
|
||||
{
|
||||
inputNumberFeedback?.FireUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var volumeDisplay = displayDevice as IBasicVolumeControls;
|
||||
if (volumeDisplay == null) return;
|
||||
|
||||
trilist.SetBoolSigAction(joinMap.VolumeUp.JoinNumber, volumeDisplay.VolumeUp);
|
||||
trilist.SetBoolSigAction(joinMap.VolumeDown.JoinNumber, volumeDisplay.VolumeDown);
|
||||
trilist.SetSigTrueAction(joinMap.VolumeMute.JoinNumber, volumeDisplay.MuteToggle);
|
||||
|
||||
var volumeDisplayWithFeedback = volumeDisplay as IBasicVolumeWithFeedback;
|
||||
|
||||
if (volumeDisplayWithFeedback == null) return;
|
||||
trilist.SetSigTrueAction(joinMap.VolumeMuteOn.JoinNumber, volumeDisplayWithFeedback.MuteOn);
|
||||
trilist.SetSigTrueAction(joinMap.VolumeMuteOff.JoinNumber, volumeDisplayWithFeedback.MuteOff);
|
||||
|
||||
|
||||
trilist.SetUShortSigAction(joinMap.VolumeLevel.JoinNumber, volumeDisplayWithFeedback.SetVolume);
|
||||
volumeDisplayWithFeedback.VolumeLevelFeedback.LinkInputSig(trilist.UShortInput[joinMap.VolumeLevel.JoinNumber]);
|
||||
volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMute.JoinNumber]);
|
||||
volumeDisplayWithFeedback.MuteFeedback.LinkInputSig(trilist.BooleanInput[joinMap.VolumeMuteOn.JoinNumber]);
|
||||
volumeDisplayWithFeedback.MuteFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.VolumeMuteOff.JoinNumber]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void SetCurrentSource(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
|
||||
{
|
||||
foreach (eRoutingSignalType type in Enum.GetValues(typeof(eRoutingSignalType)))
|
||||
{
|
||||
var flagValue = Convert.ToInt32(type);
|
||||
// Skip if flagValue is 0 or not a power of two (i.e., not a single-bit flag).
|
||||
// (flagValue & (flagValue - 1)) != 0 checks if more than one bit is set.
|
||||
if (flagValue == 0 || (flagValue & (flagValue - 1)) != 0)
|
||||
{
|
||||
this.LogDebug("Skipping {type}", type);
|
||||
continue;
|
||||
}
|
||||
|
||||
this.LogDebug("setting {type}", type);
|
||||
|
||||
if (signalType.HasFlag(type))
|
||||
{
|
||||
UpdateCurrentSources(type, sourceListKey, sourceListItem);
|
||||
}
|
||||
}
|
||||
// Raise the CurrentSourcesChanged event
|
||||
CurrentSourcesChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void UpdateCurrentSources(eRoutingSignalType signalType, string sourceListKey, SourceListItem sourceListItem)
|
||||
{
|
||||
if (CurrentSources.ContainsKey(signalType))
|
||||
{
|
||||
CurrentSources[signalType] = sourceListItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentSources.Add(signalType, sourceListItem);
|
||||
}
|
||||
|
||||
// Update the current source key for the specified signal type
|
||||
if (CurrentSourceKeys.ContainsKey(signalType))
|
||||
{
|
||||
CurrentSourceKeys[signalType] = sourceListKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentSourceKeys.Add(signalType, sourceListKey);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,89 +1,87 @@
|
|||
using System;
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Displays
|
||||
namespace PepperDash.Essentials.Devices.Displays;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputHdmi1
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputHdmi1
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputHdmi1
|
||||
/// Switches to HDMI 1 input
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputHdmi1
|
||||
{
|
||||
/// <summary>
|
||||
/// Switches to HDMI 1 input
|
||||
/// </summary>
|
||||
void InputHdmi1();
|
||||
}
|
||||
void InputHdmi1();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputHdmi2
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputHdmi2
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputHdmi2
|
||||
/// Switches to HDMI 2 input
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputHdmi2
|
||||
{
|
||||
/// <summary>
|
||||
/// Switches to HDMI 2 input
|
||||
/// </summary>
|
||||
void InputHdmi2();
|
||||
}
|
||||
void InputHdmi2();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputHdmi3
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputHdmi3
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputHdmi3
|
||||
/// Switches to HDMI 3 input
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputHdmi3
|
||||
{
|
||||
/// <summary>
|
||||
/// Switches to HDMI 3 input
|
||||
/// </summary>
|
||||
void InputHdmi3();
|
||||
}
|
||||
void InputHdmi3();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputHdmi4
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputHdmi4
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputHdmi4
|
||||
/// Switches to HDMI 4 input
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputHdmi4
|
||||
{
|
||||
/// <summary>
|
||||
/// Switches to HDMI 4 input
|
||||
/// </summary>
|
||||
void InputHdmi4();
|
||||
}
|
||||
void InputHdmi4();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputDisplayPort1
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputDisplayPort1
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputDisplayPort1
|
||||
/// Switches to DisplayPort 1 input
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputDisplayPort1
|
||||
{
|
||||
/// <summary>
|
||||
/// Switches to DisplayPort 1 input
|
||||
/// </summary>
|
||||
void InputDisplayPort1();
|
||||
}
|
||||
void InputDisplayPort1();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputDisplayPort2
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputDisplayPort2
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputDisplayPort2
|
||||
/// Switches to DisplayPort 2 input
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputDisplayPort2
|
||||
{
|
||||
/// <summary>
|
||||
/// Switches to DisplayPort 2 input
|
||||
/// </summary>
|
||||
void InputDisplayPort2();
|
||||
}
|
||||
void InputDisplayPort2();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputVga1
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputVga1
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for IInputVga1
|
||||
/// Switches to VGA 1 input
|
||||
/// </summary>
|
||||
[Obsolete()]
|
||||
public interface IInputVga1
|
||||
{
|
||||
/// <summary>
|
||||
/// Switches to VGA 1 input
|
||||
/// </summary>
|
||||
void InputVga1();
|
||||
}
|
||||
|
||||
}
|
||||
void InputVga1();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,82 +10,62 @@ using PepperDash.Essentials.Core.Config;
|
|||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Common.Displays
|
||||
namespace PepperDash.Essentials.Devices.Common.Displays;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a mock display device for testing and simulation purposes.
|
||||
/// </summary>
|
||||
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs<string>, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a MockDisplay
|
||||
/// </summary>
|
||||
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced, IHasInputs<string>, IRoutingSinkWithSwitchingWithInputPort, IHasPowerControlWithFeedback
|
||||
public ISelectableItems<string> Inputs { get; private set; }
|
||||
|
||||
bool _PowerIsOn;
|
||||
bool _IsWarmingUp;
|
||||
bool _IsCoolingDown;
|
||||
|
||||
protected override Func<bool> PowerIsOnFeedbackFunc
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Inputs
|
||||
/// </summary>
|
||||
public ISelectableItems<string> Inputs { get; private set; }
|
||||
|
||||
bool _PowerIsOn;
|
||||
bool _IsWarmingUp;
|
||||
bool _IsCoolingDown;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the power is on feedback function
|
||||
/// </summary>
|
||||
protected override Func<bool> PowerIsOnFeedbackFunc
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
return _PowerIsOn;
|
||||
};
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the is cooling down feedback function
|
||||
/// </summary>
|
||||
protected override Func<bool> IsCoolingDownFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
return () =>
|
||||
return () =>
|
||||
{
|
||||
return _IsCoolingDown;
|
||||
return _PowerIsOn;
|
||||
};
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the is warming up feedback function
|
||||
/// </summary>
|
||||
protected override Func<bool> IsWarmingUpFeedbackFunc
|
||||
}
|
||||
protected override Func<bool> IsCoolingDownFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
get
|
||||
return () =>
|
||||
{
|
||||
return () =>
|
||||
{
|
||||
return _IsWarmingUp;
|
||||
};
|
||||
}
|
||||
return _IsCoolingDown;
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the current input feedback function
|
||||
/// </summary>
|
||||
protected override Func<string> CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } }
|
||||
|
||||
int VolumeHeldRepeatInterval = 200;
|
||||
ushort VolumeInterval = 655;
|
||||
ushort _FakeVolumeLevel = 31768;
|
||||
bool _IsMuted;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MockDisplay class
|
||||
/// </summary>
|
||||
/// <param name="key">The device key</param>
|
||||
/// <param name="name">The device name</param>
|
||||
public MockDisplay(string key, string name)
|
||||
: base(key, name)
|
||||
}
|
||||
protected override Func<bool> IsWarmingUpFeedbackFunc
|
||||
{
|
||||
get
|
||||
{
|
||||
Inputs = new MockDisplayInputs
|
||||
return () =>
|
||||
{
|
||||
Items = new Dictionary<string, ISelectableItem>
|
||||
return _IsWarmingUp;
|
||||
};
|
||||
}
|
||||
}
|
||||
protected override Func<string> CurrentInputFeedbackFunc { get { return () => Inputs.CurrentItem; } }
|
||||
|
||||
int VolumeHeldRepeatInterval = 200;
|
||||
ushort VolumeInterval = 655;
|
||||
ushort _FakeVolumeLevel = 31768;
|
||||
bool _IsMuted;
|
||||
|
||||
public MockDisplay(string key, string name)
|
||||
: base(key, name)
|
||||
{
|
||||
Inputs = new MockDisplayInputs
|
||||
{
|
||||
Items = new Dictionary<string, ISelectableItem>
|
||||
{
|
||||
{ "HDMI1", new MockDisplayInput ( "HDMI1", "HDMI 1",this ) },
|
||||
{ "HDMI2", new MockDisplayInput ("HDMI2", "HDMI 2",this ) },
|
||||
|
|
@ -93,276 +73,239 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
|||
{ "HDMI4", new MockDisplayInput ("HDMI4", "HDMI 4",this )},
|
||||
{ "DP", new MockDisplayInput ("DP", "DisplayPort", this ) }
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate();
|
||||
Inputs.CurrentItemChanged += (o, a) => CurrentInputFeedback.FireUpdate();
|
||||
|
||||
var hdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
|
||||
var hdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.Hdmi, "HDMI1", this);
|
||||
var hdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.Hdmi, "HDMI2", this);
|
||||
var hdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.Hdmi, "HDMI3", this);
|
||||
var hdmiIn4 = new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.Hdmi, "HDMI4", this);
|
||||
var dpIn = new RoutingInputPort(RoutingPortNames.DisplayPortIn, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.DisplayPort, "DP", this);
|
||||
InputPorts.AddRange(new[] { hdmiIn1, hdmiIn2, hdmiIn3, hdmiIn4, dpIn });
|
||||
|
||||
VolumeLevelFeedback = new IntFeedback("volume", () => { return _FakeVolumeLevel; });
|
||||
MuteFeedback = new BoolFeedback("muteOn", () => _IsMuted);
|
||||
|
||||
WarmupTime = 10000;
|
||||
CooldownTime = 10000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PowerOn method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override void PowerOn()
|
||||
{
|
||||
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
|
||||
{
|
||||
_IsWarmingUp = true;
|
||||
IsWarmingUpFeedback.InvokeFireUpdate();
|
||||
// Fake power-up cycle
|
||||
WarmupTimer = new CTimer(o =>
|
||||
{
|
||||
_IsWarmingUp = false;
|
||||
_PowerIsOn = true;
|
||||
IsWarmingUpFeedback.InvokeFireUpdate();
|
||||
PowerIsOnFeedback.InvokeFireUpdate();
|
||||
}, WarmupTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PowerOff method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override void PowerOff()
|
||||
{
|
||||
// If a display has unreliable-power off feedback, just override this and
|
||||
// remove this check.
|
||||
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
|
||||
{
|
||||
_IsCoolingDown = true;
|
||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
||||
// Fake cool-down cycle
|
||||
CooldownTimer = new CTimer(o =>
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this);
|
||||
_IsCoolingDown = false;
|
||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
||||
_PowerIsOn = false;
|
||||
PowerIsOnFeedback.InvokeFireUpdate();
|
||||
}, CooldownTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PowerToggle method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override void PowerToggle()
|
||||
{
|
||||
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
|
||||
PowerOff();
|
||||
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
|
||||
PowerOn();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ExecuteSwitch method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override void ExecuteSwitch(object selector)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector);
|
||||
|
||||
if (!_PowerIsOn)
|
||||
{
|
||||
PowerOn();
|
||||
}
|
||||
|
||||
if (!Inputs.Items.TryGetValue(selector.ToString(), out var input))
|
||||
return;
|
||||
|
||||
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, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetInput method
|
||||
/// </summary>
|
||||
public void SetInput(string selector)
|
||||
{
|
||||
ISelectableItem currentInput = null;
|
||||
|
||||
try
|
||||
{
|
||||
currentInput = Inputs.Items.SingleOrDefault(Inputs => Inputs.Value.IsSelected).Value;
|
||||
}
|
||||
catch { }
|
||||
var hdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.Hdmi, "HDMI2", this);
|
||||
var hdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.Hdmi, "HDMI3", this);
|
||||
var hdmiIn4 = new RoutingInputPort(RoutingPortNames.HdmiIn4, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.Hdmi, "HDMI4", this);
|
||||
var dpIn = new RoutingInputPort(RoutingPortNames.DisplayPortIn, eRoutingSignalType.AudioVideo,
|
||||
eRoutingPortConnectionType.DisplayPort, "DP", this);
|
||||
InputPorts.AddRange(new[] { hdmiIn1, hdmiIn2, hdmiIn3, hdmiIn4, dpIn });
|
||||
|
||||
|
||||
if (currentInput != null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "SetInput: {0}", selector);
|
||||
currentInput.IsSelected = false;
|
||||
}
|
||||
VolumeLevelFeedback = new IntFeedback("volume", () => { return _FakeVolumeLevel; });
|
||||
MuteFeedback = new BoolFeedback("muteOn", () => _IsMuted);
|
||||
|
||||
if (!Inputs.Items.TryGetValue(selector, out var input))
|
||||
return;
|
||||
|
||||
input.IsSelected = true;
|
||||
|
||||
Inputs.CurrentItem = selector;
|
||||
}
|
||||
|
||||
|
||||
#region IBasicVolumeWithFeedback Members
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the VolumeLevelFeedback
|
||||
/// </summary>
|
||||
public IntFeedback VolumeLevelFeedback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// SetVolume method
|
||||
/// </summary>
|
||||
public void SetVolume(ushort level)
|
||||
{
|
||||
_FakeVolumeLevel = level;
|
||||
VolumeLevelFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MuteOn method
|
||||
/// </summary>
|
||||
public void MuteOn()
|
||||
{
|
||||
_IsMuted = true;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MuteOff method
|
||||
/// </summary>
|
||||
public void MuteOff()
|
||||
{
|
||||
_IsMuted = false;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MuteFeedback
|
||||
/// </summary>
|
||||
public BoolFeedback MuteFeedback { get; private set; }
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBasicVolumeControls Members
|
||||
|
||||
/// <summary>
|
||||
/// VolumeUp method
|
||||
/// </summary>
|
||||
public void VolumeUp(bool pressRelease)
|
||||
{
|
||||
//while (pressRelease)
|
||||
//{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease);
|
||||
if (pressRelease)
|
||||
{
|
||||
var newLevel = _FakeVolumeLevel + VolumeInterval;
|
||||
SetVolume((ushort)newLevel);
|
||||
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// VolumeDown method
|
||||
/// </summary>
|
||||
public void VolumeDown(bool pressRelease)
|
||||
{
|
||||
//while (pressRelease)
|
||||
//{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease);
|
||||
if (pressRelease)
|
||||
{
|
||||
var newLevel = _FakeVolumeLevel - VolumeInterval;
|
||||
SetVolume((ushort)newLevel);
|
||||
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MuteToggle method
|
||||
/// </summary>
|
||||
public void MuteToggle()
|
||||
{
|
||||
_IsMuted = !_IsMuted;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// LinkToApi method
|
||||
/// </summary>
|
||||
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
||||
{
|
||||
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
|
||||
}
|
||||
WarmupTime = 10000;
|
||||
CooldownTime = 10000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a MockDisplayFactory
|
||||
/// PowerOn method
|
||||
/// </summary>
|
||||
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
|
||||
/// <inheritdoc />
|
||||
public override void PowerOn()
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MockDisplayFactory class
|
||||
/// </summary>
|
||||
public MockDisplayFactory()
|
||||
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
|
||||
{
|
||||
TypeNames = new List<string>() { "mockdisplay", "mockdisplay2" };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BuildDevice method
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device");
|
||||
return new MockDisplay(dc.Key, dc.Name);
|
||||
_IsWarmingUp = true;
|
||||
IsWarmingUpFeedback.InvokeFireUpdate();
|
||||
// Fake power-up cycle
|
||||
WarmupTimer = new CTimer(o =>
|
||||
{
|
||||
_IsWarmingUp = false;
|
||||
_PowerIsOn = true;
|
||||
IsWarmingUpFeedback.InvokeFireUpdate();
|
||||
PowerIsOnFeedback.InvokeFireUpdate();
|
||||
}, WarmupTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void PowerOff()
|
||||
{
|
||||
// If a display has unreliable-power off feedback, just override this and
|
||||
// remove this check.
|
||||
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
|
||||
{
|
||||
_IsCoolingDown = true;
|
||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
||||
// Fake cool-down cycle
|
||||
CooldownTimer = new CTimer(o =>
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this);
|
||||
_IsCoolingDown = false;
|
||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
||||
_PowerIsOn = false;
|
||||
PowerIsOnFeedback.InvokeFireUpdate();
|
||||
}, CooldownTime);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PowerToggle()
|
||||
{
|
||||
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
|
||||
PowerOff();
|
||||
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
|
||||
PowerOn();
|
||||
}
|
||||
|
||||
public override void ExecuteSwitch(object selector)
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector);
|
||||
|
||||
if (!_PowerIsOn)
|
||||
{
|
||||
PowerOn();
|
||||
}
|
||||
|
||||
if (!Inputs.Items.TryGetValue(selector.ToString(), out var input))
|
||||
return;
|
||||
|
||||
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, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetInput(string selector)
|
||||
{
|
||||
ISelectableItem currentInput = null;
|
||||
|
||||
|
||||
if (currentInput != null)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "SetInput: {0}", selector);
|
||||
currentInput.IsSelected = false;
|
||||
}
|
||||
|
||||
if (!Inputs.Items.TryGetValue(selector, out var input))
|
||||
return;
|
||||
|
||||
input.IsSelected = true;
|
||||
|
||||
Inputs.CurrentItem = selector;
|
||||
}
|
||||
|
||||
|
||||
#region IBasicVolumeWithFeedback Members
|
||||
|
||||
public IntFeedback VolumeLevelFeedback { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// SetVolume method
|
||||
/// </summary>
|
||||
public void SetVolume(ushort level)
|
||||
{
|
||||
_FakeVolumeLevel = level;
|
||||
VolumeLevelFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MuteOn method
|
||||
/// </summary>
|
||||
public void MuteOn()
|
||||
{
|
||||
_IsMuted = true;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MuteOff method
|
||||
/// </summary>
|
||||
public void MuteOff()
|
||||
{
|
||||
_IsMuted = false;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the MuteFeedback
|
||||
/// </summary>
|
||||
public BoolFeedback MuteFeedback { get; private set; }
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBasicVolumeControls Members
|
||||
|
||||
public void VolumeUp(bool pressRelease)
|
||||
{
|
||||
//while (pressRelease)
|
||||
//{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease);
|
||||
if (pressRelease)
|
||||
{
|
||||
var newLevel = _FakeVolumeLevel + VolumeInterval;
|
||||
SetVolume((ushort)newLevel);
|
||||
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
public void VolumeDown(bool pressRelease)
|
||||
{
|
||||
//while (pressRelease)
|
||||
//{
|
||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease);
|
||||
if (pressRelease)
|
||||
{
|
||||
var newLevel = _FakeVolumeLevel - VolumeInterval;
|
||||
SetVolume((ushort)newLevel);
|
||||
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MuteToggle method
|
||||
/// </summary>
|
||||
public void MuteToggle()
|
||||
{
|
||||
_IsMuted = !_IsMuted;
|
||||
MuteFeedback.InvokeFireUpdate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
||||
{
|
||||
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a MockDisplayFactory
|
||||
/// </summary>
|
||||
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MockDisplayFactory class
|
||||
/// </summary>
|
||||
public MockDisplayFactory()
|
||||
{
|
||||
TypeNames = new List<string>() { "mockdisplay", "mockdisplay2" };
|
||||
}
|
||||
|
||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||
{
|
||||
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device");
|
||||
return new MockDisplay(dc.Key, dc.Name);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,135 +2,95 @@
|
|||
using System.Collections.Generic;
|
||||
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||
|
||||
namespace PepperDash.Essentials.Devices.Common.Displays
|
||||
namespace PepperDash.Essentials.Devices.Common.Displays;
|
||||
|
||||
public class MockDisplayInputs : ISelectableItems<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a MockDisplayInputs
|
||||
/// </summary>
|
||||
public class MockDisplayInputs : ISelectableItems<string>
|
||||
private Dictionary<string, ISelectableItem> _items;
|
||||
|
||||
public Dictionary<string, ISelectableItem> Items
|
||||
{
|
||||
private Dictionary<string, ISelectableItem> _items;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the collection of selectable items
|
||||
/// </summary>
|
||||
public Dictionary<string, ISelectableItem> Items
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return _items;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_items == value)
|
||||
return;
|
||||
|
||||
_items = value;
|
||||
|
||||
ItemsUpdated?.Invoke(this, null);
|
||||
}
|
||||
return _items;
|
||||
}
|
||||
|
||||
private string _currentItem;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the currently selected item
|
||||
/// </summary>
|
||||
public string CurrentItem
|
||||
set
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentItem;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_currentItem == value)
|
||||
return;
|
||||
if (_items == value)
|
||||
return;
|
||||
|
||||
_currentItem = value;
|
||||
_items = value;
|
||||
|
||||
CurrentItemChanged?.Invoke(this, null);
|
||||
}
|
||||
ItemsUpdated?.Invoke(this, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the items collection is updated
|
||||
/// </summary>
|
||||
public event EventHandler ItemsUpdated;
|
||||
/// <summary>
|
||||
/// Occurs when the current item changes
|
||||
/// </summary>
|
||||
public event EventHandler CurrentItemChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a MockDisplayInput
|
||||
/// </summary>
|
||||
public class MockDisplayInput : ISelectableItem
|
||||
private string _currentItem;
|
||||
|
||||
public string CurrentItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentItem;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_currentItem == value)
|
||||
return;
|
||||
|
||||
_currentItem = value;
|
||||
|
||||
CurrentItemChanged?.Invoke(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler ItemsUpdated;
|
||||
public event EventHandler CurrentItemChanged;
|
||||
}
|
||||
|
||||
public class MockDisplayInput : ISelectableItem
|
||||
{
|
||||
private MockDisplay _parent;
|
||||
|
||||
private bool _isSelected;
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
private MockDisplay _parent;
|
||||
|
||||
private bool _isSelected;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this input is selected
|
||||
/// </summary>
|
||||
public bool IsSelected
|
||||
get
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isSelected;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_isSelected == value)
|
||||
return;
|
||||
|
||||
_isSelected = value;
|
||||
|
||||
ItemUpdated?.Invoke(this, null);
|
||||
}
|
||||
return _isSelected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Key
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when this item is updated
|
||||
/// </summary>
|
||||
public event EventHandler ItemUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the MockDisplayInput class
|
||||
/// </summary>
|
||||
/// <param name="key">The input key</param>
|
||||
/// <param name="name">The input name</param>
|
||||
/// <param name="parent">The parent mock display</param>
|
||||
public MockDisplayInput(string key, string name, MockDisplay parent)
|
||||
set
|
||||
{
|
||||
Key = key;
|
||||
Name = name;
|
||||
_parent = parent;
|
||||
if (_isSelected == value)
|
||||
return;
|
||||
|
||||
_isSelected = value;
|
||||
|
||||
ItemUpdated?.Invoke(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Select method
|
||||
/// </summary>
|
||||
public void Select()
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Key { get; set; }
|
||||
|
||||
public event EventHandler ItemUpdated;
|
||||
|
||||
public MockDisplayInput(string key, string name, MockDisplay parent)
|
||||
{
|
||||
Key = key;
|
||||
Name = name;
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public void Select()
|
||||
{
|
||||
if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn();
|
||||
|
||||
foreach(var input in _parent.Inputs.Items)
|
||||
{
|
||||
if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn();
|
||||
|
||||
foreach (var input in _parent.Inputs.Items)
|
||||
{
|
||||
input.Value.IsSelected = input.Key == this.Key;
|
||||
}
|
||||
input.Value.IsSelected = input.Key == this.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -434,7 +434,7 @@ namespace PepperDash.Essentials.Devices.Common.Shades
|
|||
/// <summary>
|
||||
/// Factory for ScreenLiftController devices
|
||||
/// </summary>
|
||||
public class ScreenLiftControllerFactory : EssentialsDeviceFactory<RelayControlledShade>
|
||||
public class ScreenLiftControllerFactory : EssentialsDeviceFactory<ScreenLiftController>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor for ScreenLiftControllerFactory
|
||||
|
|
@ -453,4 +453,4 @@ namespace PepperDash.Essentials.Devices.Common.Shades
|
|||
return new ScreenLiftController(dc.Key, dc.Name, props);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue