Merge branch 'feature-2.0.0/room-combiner-updates' into feature-2.0.0/video-codec-interface-uiextensions

This commit is contained in:
Joshua_Gutenplan
2024-05-10 21:36:53 -07:00
11 changed files with 358 additions and 59 deletions

View File

@@ -0,0 +1,27 @@
using Crestron.SimplSharpPro.DeviceSupport;
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
/// <summary>
/// Defines a class that has warm up and cool down
/// </summary>
public interface IProjectorScreenLiftControl
{
void Raise();
void Lower();
BoolFeedback IsInUpPosition { get; }
bool InUpPosition { get; }
event EventHandler<EventArgs> PositionChanged;
string DisplayDeviceKey { get; }
eScreenLiftControlType Type { get; } // screen/lift
}
public enum eScreenLiftControlType
{
lift,
screen
}
}

View File

@@ -220,19 +220,5 @@ namespace PepperDash.Essentials.Core
}
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
{
public MockDisplayFactory()
{
TypeNames = new List<string>() { "mockdisplay" };
}
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);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
@@ -17,7 +18,7 @@ namespace PepperDash.Essentials.Core
{
private IPartitionStateProvider _partitionSensor;
private bool isInAutoMode;
public bool IsInAutoMode { get; private set; }
private bool _partitionPresent;
@@ -64,7 +65,7 @@ namespace PepperDash.Essentials.Core
SetManualMode();
}
}
else
else
{
SetManualMode();
}
@@ -74,7 +75,7 @@ namespace PepperDash.Essentials.Core
void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
if (isInAutoMode)
if (IsInAutoMode)
{
PartitionPresentFeedback.FireUpdate();
}
@@ -86,7 +87,7 @@ namespace PepperDash.Essentials.Core
public void SetAutoMode()
{
isInAutoMode = true;
IsInAutoMode = true;
if (PartitionPresentFeedback != null)
{
PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue);
@@ -98,13 +99,14 @@ namespace PepperDash.Essentials.Core
if (_partitionSensor != null)
{
_partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange;
_partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange;
}
}
public void SetManualMode()
{
isInAutoMode = false;
IsInAutoMode = false;
if (PartitionPresentFeedback != null)
{
PartitionPresentFeedback.SetValueFunc(() => _partitionPresent);
@@ -123,7 +125,7 @@ namespace PepperDash.Essentials.Core
public void SetPartitionStatePresent()
{
if (!isInAutoMode)
if (!IsInAutoMode)
{
PartitionPresent = true;
PartitionPresentFeedback.FireUpdate();
@@ -132,7 +134,7 @@ namespace PepperDash.Essentials.Core
public void SetPartitionStateNotPresent()
{
if (!isInAutoMode)
if (!IsInAutoMode)
{
PartitionPresent = false;
PartitionPresentFeedback.FireUpdate();
@@ -141,7 +143,10 @@ namespace PepperDash.Essentials.Core
public void ToggglePartitionState()
{
if (!isInAutoMode)
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Toggling Partition State for {Key}", this);
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"IsInAutoMode: {IsInAutoMode}", this);
if (!IsInAutoMode)
{
PartitionPresent = !PartitionPresent;
PartitionPresentFeedback.FireUpdate();

View File

@@ -24,6 +24,9 @@ namespace PepperDash.Essentials.Core
[JsonProperty("adjacentRoomKeys")]
List<string> AdjacentRoomKeys { get; }
[JsonProperty("isInAutoMode")]
bool IsInAutoMode { get; }
void SetPartitionStatePresent();
void SetPartitionStateNotPresent();

View File

@@ -137,7 +137,11 @@ namespace PepperDash.Essentials.Core
void StartDebounceTimer()
{
var time = _scenarioChangeDebounceTimeSeconds * 1000;
// default to 500ms for manual mode
var time = 500;
// if in auto mode, debounce the scenario change
if(IsInAutoMode) time = _scenarioChangeDebounceTimeSeconds * 1000;
if (_scenarioChangeDebounceTimer == null)
{
@@ -211,7 +215,7 @@ namespace PepperDash.Essentials.Core
{
_currentScenario.Activate();
Debug.LogMessage(LogEventLevel.Debug, this, "Current Scenario: {0}", _currentScenario.Name);
Debug.LogMessage(LogEventLevel.Debug, $"Current Scenario: {_currentScenario.Name}", this);
}
var handler = RoomCombinationScenarioChanged;
@@ -246,7 +250,7 @@ namespace PepperDash.Essentials.Core
public void TogglePartitionState(string partitionKey)
{
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IPartitionController;
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey));
if (partition != null)
{

View File

@@ -141,6 +141,7 @@ namespace PepperDash.Essentials.Core
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
ShutdownType = eShutdownType.None;
};
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
ShutdownPromptSeconds = 60;

View File

@@ -159,4 +159,13 @@ namespace PepperDash.Essentials.Core
Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; }
}
public interface IHasAccessoryDevices : IKeyName
{
List<string> AccessoryDeviceKeys { get; }
}
public interface IHasCiscoNavigatorTouchpanel
{
string CiscoNavigatorTouchpanelKey { get; }
}
}

View File

@@ -52,8 +52,8 @@ namespace PepperDash.Essentials.Core
var timeSpan = FinishTime - DateTime.Now;
Debug.LogMessage(LogEventLevel.Verbose, this,
"timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}",
Debug.LogMessage(LogEventLevel.Verbose,
"timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}", this,
timeSpan.Minutes, timeSpan.Seconds, timeSpan.TotalSeconds);
if (Math.Floor(timeSpan.TotalSeconds) < 60 && Math.Floor(timeSpan.TotalSeconds) >= 0) //ignore milliseconds
@@ -103,6 +103,7 @@ namespace PepperDash.Essentials.Core
public void Reset()
{
_isRunning = false;
IsRunningFeedback.FireUpdate();
Start();
}
@@ -133,7 +134,11 @@ namespace PepperDash.Essentials.Core
void StopHelper()
{
if (_secondTimer != null)
{
_secondTimer.Stop();
_secondTimer = null;
}
_isRunning = false;
IsRunningFeedback.FireUpdate();
}

View File

@@ -6,6 +6,7 @@ using Crestron.SimplSharpPro.DeviceSupport;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
@@ -120,7 +121,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays
// Fake cool-down cycle
CooldownTimer = new CTimer(o =>
{
Debug.LogMessage(LogEventLevel.Verbose, this, "Cooldown timer ending");
Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this);
_IsCoolingDown = false;
IsCoolingDownFeedback.InvokeFireUpdate();
_PowerIsOn = false;
@@ -141,10 +142,10 @@ namespace PepperDash.Essentials.Devices.Common.Displays
{
Debug.LogMessage(LogEventLevel.Verbose, this, "ExecuteSwitch: {0}", selector);
if (!_PowerIsOn)
{
PowerOn();
}
if (!_PowerIsOn)
{
PowerOn();
}
if (!Inputs.Items.TryGetValue(selector.ToString(), out var input))
return;
@@ -152,32 +153,6 @@ namespace PepperDash.Essentials.Devices.Common.Displays
input.Select();
}
public void SetInput(string selector)
{
ISelectableItem currentInput = null;
try
{
currentInput = Inputs.Items.SingleOrDefault(Inputs => Inputs.Value.IsSelected).Value;
}
catch { }
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
@@ -251,4 +226,17 @@ namespace PepperDash.Essentials.Devices.Common.Displays
}
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
{
public MockDisplayFactory()
{
TypeNames = new List<string>() { "mockdisplay" };
}
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);
}
}
}

View File

@@ -90,7 +90,12 @@ namespace PepperDash.Essentials.Devices.Common.Displays
public void Select()
{
_parent.SetInput(Key);
if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn();
foreach(var input in _parent.Inputs.Items)
{
input.Value.IsSelected = input.Key == this.Key;
}
}
}
}

View File

@@ -0,0 +1,266 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.CrestronIO;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Devices.Common;
using Serilog.Events;
namespace PepperDash.Essentials.Devices.Common.Shades
{
/// <summary>
/// Controls a single shade using three relays
/// </summary>
public class ScreenLiftController : EssentialsDevice, IProjectorScreenLiftControl
{
readonly ScreenLiftControllerConfigProperties Config;
readonly ScreenLiftRelaysConfig RaiseRelayConfig;
readonly ScreenLiftRelaysConfig LowerRelayConfig;
readonly ScreenLiftRelaysConfig LatchedRelayConfig;
Displays.DisplayBase DisplayDevice;
ISwitchedOutput RaiseRelay;
ISwitchedOutput LowerRelay;
ISwitchedOutput LatchedRelay;
public bool InUpPosition
{
get { return _isInUpPosition; }
set
{
if (value == _isInUpPosition) return;
_isInUpPosition = value;
IsInUpPosition.FireUpdate();
PositionChanged?.Invoke(this, new EventArgs());
}
}
private bool _isInUpPosition { get; set; }
public eScreenLiftControlType Type { get; private set; }
public eScreenLiftControlMode Mode { get; private set; }
public string DisplayDeviceKey { get; private set; }
public BoolFeedback IsInUpPosition { get; private set; }
public event EventHandler<EventArgs> PositionChanged;
public ScreenLiftController(string key, string name, ScreenLiftControllerConfigProperties config)
: base(key, name)
{
Config = config;
DisplayDeviceKey = Config.DisplayDeviceKey;
Mode = Config.Mode;
Type = Config.Type;
IsInUpPosition = new BoolFeedback(() => _isInUpPosition);
switch (Mode)
{
case eScreenLiftControlMode.momentary:
{
RaiseRelayConfig = Config.Relays["raise"];
LowerRelayConfig = Config.Relays["lower"];
break;
}
case eScreenLiftControlMode.latched:
{
LatchedRelayConfig = Config.Relays["latched"];
break;
}
}
}
private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
if (!DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.lift)
{
Raise();
return;
}
if (DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.screen)
{
Raise();
return;
}
}
private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
if (DisplayDevice.IsWarmingUpFeedback.BoolValue)
{
Lower();
}
}
public override bool CustomActivate()
{
//Create ISwitchedOutput objects based on props
switch (Mode)
{
case eScreenLiftControlMode.momentary:
{
Debug.LogMessage(LogEventLevel.Debug, this, $"Getting relays for {Mode}");
RaiseRelay = GetSwitchedOutputFromDevice(RaiseRelayConfig.DeviceKey);
LowerRelay = GetSwitchedOutputFromDevice(LowerRelayConfig.DeviceKey);
break;
}
case eScreenLiftControlMode.latched:
{
Debug.LogMessage(LogEventLevel.Debug, this, $"Getting relays for {Mode}");
LatchedRelay = GetSwitchedOutputFromDevice(LatchedRelayConfig.DeviceKey);
break;
}
}
Debug.LogMessage(LogEventLevel.Debug, this, $"Getting display with key {DisplayDeviceKey}");
DisplayDevice = GetDisplayBaseFromDevice(DisplayDeviceKey);
if (DisplayDevice != null)
{
Debug.LogMessage(LogEventLevel.Debug, this, $"Subscribing to {DisplayDeviceKey} feedbacks");
DisplayDevice.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange;
DisplayDevice.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
}
return base.CustomActivate();
}
public void Raise()
{
if (RaiseRelay == null && LatchedRelay == null) return;
Debug.LogMessage(LogEventLevel.Debug, this, $"Raising {Type}");
switch (Mode)
{
case eScreenLiftControlMode.momentary:
{
PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs);
break;
}
case eScreenLiftControlMode.latched:
{
LatchedRelay.Off();
break;
}
}
InUpPosition = true;
}
public void Lower()
{
if (LowerRelay == null && LatchedRelay == null) return;
Debug.LogMessage(LogEventLevel.Debug, this, $"Lowering {Type}");
switch (Mode)
{
case eScreenLiftControlMode.momentary:
{
PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs);
break;
}
case eScreenLiftControlMode.latched:
{
LatchedRelay.On();
break;
}
}
InUpPosition = false;
}
void PulseOutput(ISwitchedOutput output, int pulseTime)
{
output.On();
CTimer pulseTimer = new CTimer(new CTimerCallbackFunction((o) => output.Off()), pulseTime);
}
/// <summary>
/// Attempts to get the port on teh specified device from config
/// </summary>
/// <param name="relayConfig"></param>
/// <returns></returns>
ISwitchedOutput GetSwitchedOutputFromDevice(string relayKey)
{
var portDevice = DeviceManager.GetDeviceForKey(relayKey);
if (portDevice != null)
{
return (portDevice as ISwitchedOutput);
}
else
{
Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get relay device with key '{0}'", relayKey);
return null;
}
}
Displays.DisplayBase GetDisplayBaseFromDevice(string displayKey)
{
var displayDevice = DeviceManager.GetDeviceForKey(displayKey);
if (displayDevice != null)
{
return displayDevice as Displays.DisplayBase;
}
else
{
Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get display device with key '{0}'", displayKey);
return null;
}
}
}
public class ScreenLiftControllerConfigProperties
{
[JsonProperty("displayDeviceKey")]
public string DisplayDeviceKey { get; set; }
[JsonProperty("type")]
[JsonConverter(typeof(StringEnumConverter))]
public eScreenLiftControlType Type { get; set; }
[JsonProperty("mode")]
[JsonConverter(typeof(StringEnumConverter))]
public eScreenLiftControlMode Mode { get; set; }
[JsonProperty("relays")]
public Dictionary<string,ScreenLiftRelaysConfig> Relays { get; set; }
}
public class ScreenLiftRelaysConfig
{
[JsonProperty("deviceKey")]
public string DeviceKey { get; set; }
[JsonProperty("pulseTimeInMs")]
public int PulseTimeInMs { get; set; }
}
public class ScreenLiftControllerFactory : EssentialsDeviceFactory<RelayControlledShade>
{
public ScreenLiftControllerFactory()
{
TypeNames = new List<string>() { "screenliftcontroller" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device");
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<ScreenLiftControllerConfigProperties>(dc.Properties.ToString());
return new ScreenLiftController(dc.Key, dc.Name, props);
}
}
public enum eScreenLiftControlMode
{
momentary,
latched
}
}