From 20257e425ebaf47b4c86b5186f3e207899d0d6dd Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 24 Jun 2020 16:39:39 -0600 Subject: [PATCH] Refactoring things to base class --- .../Room/Types/EssentialsHuddleSpaceRoom.cs | 154 ++-- .../Room/Types/EssentialsHuddleVtc1Room.cs | 186 ++--- .../Room/EssentialsRoomBase.cs | 690 ++++++++++-------- 3 files changed, 491 insertions(+), 539 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs index cd69671f..864f195d 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs @@ -13,49 +13,9 @@ namespace PepperDash.Essentials { public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasCurrentVolumeControls, IHasDefaultDisplay { - public event EventHandler CurrentVolumeDeviceChange; + // public event SourceInfoChangeHandler CurrentSourceChange; - protected override Func OnFeedbackFunc - { - get - { - return () => - { - var disp = DefaultDisplay as DisplayBase; - var val = CurrentSourceInfo != null - && CurrentSourceInfo.Type == eSourceListItemType.Route - && disp != null; - //&& disp.PowerIsOnFeedback.BoolValue; - return val; - }; - } - } - - protected override Func IsWarmingFeedbackFunc - { - get - { - return () => - { - var disp = DefaultDisplay as DisplayBase; - return disp != null && disp.IsWarmingUpFeedback.BoolValue; - }; - } - } - - protected override Func IsCoolingFeedbackFunc - { - get - { - return () => - { - var disp = DefaultDisplay as DisplayBase; - return disp != null && disp.IsCoolingDownFeedback.BoolValue; - }; - } - } - public EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; private set; } public IRoutingSinkWithSwitching DefaultDisplay { get; private set; } @@ -74,33 +34,6 @@ namespace PepperDash.Essentials public bool EnablePowerOnToLastSource { get; set; } string _lastSourceKey; - /// - /// - /// - public IBasicVolumeControls CurrentVolumeControls - { - get { return _currentAudioDevice; } - set - { - if (value == _currentAudioDevice) return; - - var oldDev = _currentAudioDevice; - // derigister this room from the device, if it can - if (oldDev is IInUseTracking) - (oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio"); - var handler = CurrentVolumeDeviceChange; - if (handler != null) - CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange)); - _currentAudioDevice = value; - if (handler != null) - CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange)); - // register this room with new device, if it can - if (_currentAudioDevice is IInUseTracking) - (_currentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio"); - } - } - IBasicVolumeControls _currentAudioDevice; - /// /// The SourceListItem last run - containing names and icons /// @@ -152,7 +85,7 @@ namespace PepperDash.Essentials } } - void Initialize() + private void Initialize() { if (DefaultAudioDevice is IBasicVolumeControls) DefaultVolumeControls = DefaultAudioDevice as IBasicVolumeControls; @@ -160,8 +93,35 @@ namespace PepperDash.Essentials DefaultVolumeControls = (DefaultAudioDevice as IHasVolumeDevice).VolumeDevice; CurrentVolumeControls = DefaultVolumeControls; + SourceListKey = "default"; + EnablePowerOnToLastSource = true; + var disp = DefaultDisplay as DisplayBase; - if (disp != null) + if (disp == null) return; + + IsWarmingFeedbackFunc = () => disp.IsWarmingUpFeedback.BoolValue; + + IsCoolingFeedbackFunc = () => disp.IsCoolingDownFeedback.BoolValue; + + OnFeedbackFunc = () => CurrentSourceInfo != null + && CurrentSourceInfo.Type == eSourceListItemType.Route; + + InitializeDisplay(disp); + } + + + protected override void IsCoolingDownFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + IsCoolingDownFeedback.FireUpdate(); + } + + protected override void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + var display = sender as DisplayBase; + + if (display == null) return; + + if (display.PowerIsOnFeedback.BoolValue == OnFeedback.BoolValue) { // Link power, warming, cooling to display var dispTwoWay = disp as IHasPowerControlWithFeedback; @@ -177,33 +137,35 @@ namespace PepperDash.Essentials } }; } - - disp.IsWarmingUpFeedback.OutputChange += (o, a) => - { - IsWarmingUpFeedback.FireUpdate(); - - if (IsWarmingUpFeedback.BoolValue) - { - return; - } - - var display = DefaultDisplay as IBasicVolumeWithFeedback; - - if (display == null) - { - Debug.Console(0, this, Debug.ErrorLogLevel.Error, - "Default display {0} is not volume control control provider", DefaultDisplay.Key); - return; - } - - display.SetVolume(DefaultVolume); - }; - disp.IsCoolingDownFeedback.OutputChange += (o, a) => IsCoolingDownFeedback.FireUpdate(); } - - SourceListKey = "default"; - EnablePowerOnToLastSource = true; - } + + if (!display.PowerIsOnFeedback.BoolValue) + { + CurrentSourceInfo = null; + } + OnFeedback.FireUpdate(); + } + + protected override void IsWarmingUpFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs) + { + IsWarmingUpFeedback.FireUpdate(); + + if (IsWarmingUpFeedback.BoolValue) + { + return; + } + + var displayVolumeControl = DefaultDisplay as IBasicVolumeWithFeedback; + + if (displayVolumeControl == null) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Error, + "Default display {0} is not volume control control provider", DefaultDisplay.Key); + return; + } + + displayVolumeControl.SetVolume(DefaultVolume); + } protected override void CustomSetConfig(DeviceConfig config) { diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index 3d483951..ed9582a0 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -48,65 +48,7 @@ namespace PepperDash.Essentials public BoolFeedback IsSharingFeedback { get; private set; } //************************ - - public override string SourceListKey - { - get - { - return _SourceListKey; - } - set - { - _SourceListKey = value; - SetCodecExternalSources(); - - } - } - - protected override Func OnFeedbackFunc - { - get - { - return () => - { - var disp = DefaultDisplay as DisplayBase; - var val = CurrentSourceInfo != null - && CurrentSourceInfo.Type == eSourceListItemType.Route - && disp != null; - //&& disp.PowerIsOnFeedback.BoolValue; - return val; - }; - } - } - /// - /// - /// - protected override Func IsWarmingFeedbackFunc - { - get - { - return () => - { - var disp = DefaultDisplay as DisplayBase; - return disp != null && disp.IsWarmingUpFeedback.BoolValue; - }; - } - } - /// - /// - /// - protected override Func IsCoolingFeedbackFunc - { - get - { - return () => - { - var disp = DefaultDisplay as DisplayBase; - return disp != null && disp.IsCoolingDownFeedback.BoolValue; - }; - } - } - + public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; } public IRoutingSinkWithSwitching DefaultDisplay { get; private set; } @@ -129,34 +71,6 @@ namespace PepperDash.Essentials public bool EnablePowerOnToLastSource { get; set; } private string _lastSourceKey; - /// - /// Sets the volume control device, and attaches/removes InUseTrackers with "audio" - /// tag to device. - /// - public IBasicVolumeControls CurrentVolumeControls - { - get { return _currentAudioDevice; } - set - { - if (value == _currentAudioDevice) return; - - var oldDev = _currentAudioDevice; - // derigister this room from the device, if it can - if (oldDev is IInUseTracking) - (oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio"); - var handler = CurrentVolumeDeviceChange; - if (handler != null) - CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange)); - _currentAudioDevice = value; - if (handler != null) - CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange)); - // register this room with new device, if it can - if (_currentAudioDevice is IInUseTracking) - (_currentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio"); - } - } - IBasicVolumeControls _currentAudioDevice; - /// /// The SourceListItem last run - containing names and icons /// @@ -264,48 +178,6 @@ namespace PepperDash.Essentials return inAudioCall || inVideoCall; }); - var disp = DefaultDisplay as DisplayBase; - if (disp != null) - { - // Link power, warming, cooling to display - var dispTwoWay = disp as IHasPowerControlWithFeedback; - if (dispTwoWay != null) - { - dispTwoWay.PowerIsOnFeedback.OutputChange += (o, a) => - { - if (dispTwoWay.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue) - { - if (!dispTwoWay.PowerIsOnFeedback.BoolValue) - CurrentSourceInfo = null; - OnFeedback.FireUpdate(); - } - if (dispTwoWay.PowerIsOnFeedback.BoolValue) - { - SetDefaultLevels(); - } - }; - } - - disp.IsWarmingUpFeedback.OutputChange += (o, a) => - { - IsWarmingUpFeedback.FireUpdate(); - if (IsWarmingUpFeedback.BoolValue) - { - return; - } - - var basicVolumeWithFeedback = CurrentVolumeControls as IBasicVolumeWithFeedback; - if (basicVolumeWithFeedback != null) - { - basicVolumeWithFeedback.SetVolume(DefaultVolume); - } - }; - disp.IsCoolingDownFeedback.OutputChange += (o, a) => IsCoolingDownFeedback.FireUpdate(); - - } - - - // Get Microphone Privacy object, if any MUST HAPPEN AFTER setting InCallFeedback MicrophonePrivacy = EssentialsRoomConfigHelper.GetMicrophonePrivacy(PropertiesConfig, this); @@ -334,6 +206,18 @@ namespace PepperDash.Essentials SourceListKey = "default"; EnablePowerOnToLastSource = true; + + var disp = DefaultDisplay as DisplayBase; + if (disp == null) + { + return; + } + + OnFeedbackFunc = () => CurrentSourceInfo != null + && CurrentSourceInfo.Type == eSourceListItemType.Route; + + InitializeDisplay(disp); + } catch (Exception e) { @@ -341,6 +225,50 @@ namespace PepperDash.Essentials } } + #region Overrides of EssentialsRoomBase + + protected override void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs args) + { + var disp = sender as DisplayBase; + + if (disp == null) return; + + if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue) + { + if (!disp.PowerIsOnFeedback.BoolValue) + CurrentSourceInfo = null; + OnFeedback.FireUpdate(); + } + if (disp.PowerIsOnFeedback.BoolValue) + { + SetDefaultLevels(); + } + } + + protected override void IsCoolingDownFeedbackOnOutputChange(object sender, FeedbackEventArgs args) + { + IsCoolingDownFeedback.FireUpdate(); + } + + protected override void IsWarmingUpFeedbackOnOutputChange(object sender, FeedbackEventArgs args) + { + IsWarmingUpFeedback.FireUpdate(); + + if (IsWarmingUpFeedback.BoolValue) + { + return; + } + + var basicVolumeWithFeedback = CurrentVolumeControls as IBasicVolumeWithFeedback; + if (basicVolumeWithFeedback != null) + { + basicVolumeWithFeedback.SetVolume(DefaultVolume); + } + } + + + #endregion + protected override void CustomSetConfig(DeviceConfig config) { var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs index 66c4143f..8f5c86e1 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs @@ -1,315 +1,377 @@ -using System; -using System.Collections.Generic; -using PepperDash.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Devices; - -namespace PepperDash.Essentials.Core -{ - /// - /// - /// - public abstract class EssentialsRoomBase : ReconfigurableDevice - { - public BoolFeedback OnFeedback { get; private set; } - - /// - /// Fires when the RoomOccupancy object is set - /// - public event EventHandler RoomOccupancyIsSet; - - public BoolFeedback IsWarmingUpFeedback { get; private set; } - public BoolFeedback IsCoolingDownFeedback { get; private set; } - - public IOccupancyStatusProvider RoomOccupancy { get; private set; } - - public bool OccupancyStatusProviderIsRemote { get; private set; } - - protected abstract Func IsWarmingFeedbackFunc { get; } - protected abstract Func IsCoolingFeedbackFunc { get; } - - /// - /// The config name of the source list - /// - public string SourceListKey { get; set; } - - /// - /// Timer used for informing the UIs of a shutdown - /// - public SecondsCountdownTimer ShutdownPromptTimer { get; private set; } - - public int ShutdownPromptSeconds { get; set; } - public int ShutdownVacancySeconds { get; set; } - public eShutdownType ShutdownType { get; private set; } - - public EssentialsRoomEmergencyBase Emergency { get; set; } - - public Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; } - - public string LogoUrl { get; set; } - - protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; } - - public eVacancyMode VacancyMode { get; private set; } - - /// - /// Seconds after vacancy prompt is displayed until shutdown - /// - protected int RoomVacancyShutdownSeconds; - - /// - /// Seconds after vacancy detected until prompt is displayed - /// - protected int RoomVacancyShutdownPromptSeconds; - - /// - /// - /// - protected abstract Func OnFeedbackFunc { get; } - - protected Dictionary SavedVolumeLevels = new Dictionary(); - - /// - /// When volume control devices change, should we zero the one that we are leaving? - /// - public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; } - - - protected EssentialsRoomBase(DeviceConfig config) - : base(config) - { - // Setup the ShutdownPromptTimer - ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); - ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => - { - if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue) - ShutdownType = eShutdownType.None; - }; - ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered - - ShutdownPromptSeconds = 60; - ShutdownVacancySeconds = 120; - - ShutdownType = eShutdownType.None; - - RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer"); - //RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) => - //{ - // if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue) - // ShutdownType = ShutdownType.Vacancy; - //}; - RoomVacancyShutdownTimer.HasFinished += RoomVacancyShutdownPromptTimer_HasFinished; // Shutdown is triggered - - RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning - RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt - VacancyMode = eVacancyMode.None; - - OnFeedback = new BoolFeedback(OnFeedbackFunc); - - IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc); - IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc); - - AddPostActivationAction(() => - { - if (RoomOccupancy != null) - OnRoomOccupancyIsSet(); - }); - } - - void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e) - { - switch (VacancyMode) - { - case eVacancyMode.None: - StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); - break; - case eVacancyMode.InInitialVacancy: - StartRoomVacancyTimer(eVacancyMode.InShutdownWarning); - break; - case eVacancyMode.InShutdownWarning: - { - StartShutdown(eShutdownType.Vacancy); - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting Down due to vacancy."); - break; - } - } - } - - /// - /// - /// - /// - public void StartShutdown(eShutdownType type) - { - // Check for shutdowns running. Manual should override other shutdowns - - switch (type) - { - case eShutdownType.Manual: - ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds; - break; - case eShutdownType.Vacancy: - ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds; - break; - } - ShutdownType = type; - ShutdownPromptTimer.Start(); - - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "ShutdownPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount); - } - - public void StartRoomVacancyTimer(eVacancyMode mode) - { - switch (mode) - { - case eVacancyMode.None: - RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds; - break; - case eVacancyMode.InInitialVacancy: - RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds; - break; - case eVacancyMode.InShutdownWarning: - RoomVacancyShutdownTimer.SecondsToCount = 60; - break; - } - VacancyMode = mode; - RoomVacancyShutdownTimer.Start(); - - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount); - } - - /// - /// Resets the vacancy mode and shutsdwon the room - /// - public void Shutdown() - { - VacancyMode = eVacancyMode.None; - EndShutdown(); - } - - /// - /// This method is for the derived class to define it's specific shutdown - /// requirements but should not be called directly. It is called by Shutdown() - /// - protected abstract void EndShutdown(); - - - /// - /// Override this to implement a default volume level(s) method - /// - public abstract void SetDefaultLevels(); - - /// - /// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device - /// - /// - /// - public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes) - { - var provider = statusProvider as IKeyed; - - if (provider == null) - { - Debug.Console(0, this, "ERROR: Occupancy sensor device is null"); - return; - } - - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Room Occupancy set to device: '{0}'", provider.Key); - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Timeout Minutes from Config is: {0}", timeoutMinutes); - - // If status provider is fusion, set flag to remote - if (statusProvider is Fusion.EssentialsHuddleSpaceFusionSystemControllerBase) - OccupancyStatusProviderIsRemote = true; - - if(timeoutMinutes > 0) - RoomVacancyShutdownSeconds = timeoutMinutes * 60; - - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); - - RoomOccupancy = statusProvider; - - RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; - RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; - - OnRoomOccupancyIsSet(); - } - - void OnRoomOccupancyIsSet() - { - var handler = RoomOccupancyIsSet; - if (handler != null) - handler(this, new EventArgs()); - } - - /// - /// To allow base class to power room on to last source - /// - public abstract void PowerOnToDefaultOrLastSource(); - - /// - /// To allow base class to power room on to default source - /// - /// - public abstract bool RunDefaultPresentRoute(); - - void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e) - { - if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false) - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Vacancy Detected"); - // Trigger the timer when the room is vacant - StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); - } - else - { - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Occupancy Detected"); - // Reset the timer when the room is occupied - RoomVacancyShutdownTimer.Cancel(); - } - } - - /// - /// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed - /// - /// - public abstract void RoomVacatedForTimeoutPeriod(object o); - } - - /// - /// To describe the various ways a room may be shutting down - /// - public enum eShutdownType - { - None = 0, - External, - Manual, - Vacancy - } - - public enum eVacancyMode - { - None = 0, - InInitialVacancy, - InShutdownWarning - } - - /// - /// - /// - public enum eWarmingCoolingMode - { - None, - Warming, - Cooling - } - - public abstract class EssentialsRoomEmergencyBase : IKeyed - { - public string Key { get; private set; } - - protected EssentialsRoomEmergencyBase(string key) - { - Key = key; - } - } +using System; +using System.Collections.Generic; +using Crestron.SimplSharp.Reflection; +using PepperDash.Core; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Devices; + +namespace PepperDash.Essentials.Core +{ + /// + /// + /// + public abstract class EssentialsRoomBase : ReconfigurableDevice + { + public event EventHandler CurrentVolumeDeviceChange; + + /// + /// Sets the volume control device, and attaches/removes InUseTrackers with "audio" + /// tag to device. + /// + public IBasicVolumeControls CurrentVolumeControls + { + get { return CurrentAudioDevice; } + set + { + if (value == CurrentAudioDevice) + { + return; + } + + var handler = CurrentVolumeDeviceChange; + + if (handler != null) + { + CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(CurrentAudioDevice, value, ChangeType.WillChange)); + CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(CurrentAudioDevice, value, ChangeType.DidChange)); + } + + var oldDevice = value as IInUseTracking; + var newDevice = value as IInUseTracking; + + UpdateInUseTracking(oldDevice, newDevice); + + CurrentAudioDevice = value; + } + } + protected IBasicVolumeControls CurrentAudioDevice; + + public BoolFeedback OnFeedback { get; private set; } + + /// + /// Fires when the RoomOccupancy object is set + /// + public event EventHandler RoomOccupancyIsSet; + + public BoolFeedback IsWarmingUpFeedback { get; private set; } + public BoolFeedback IsCoolingDownFeedback { get; private set; } + + public IOccupancyStatusProvider RoomOccupancy { get; private set; } + + public bool OccupancyStatusProviderIsRemote { get; private set; } + + protected Func IsWarmingFeedbackFunc; + protected Func IsCoolingFeedbackFunc; + /// + /// The config name of the source list + /// + public string SourceListKey { get; set; } + + /// + /// Timer used for informing the UIs of a shutdown + /// + public SecondsCountdownTimer ShutdownPromptTimer { get; private set; } + + public int ShutdownPromptSeconds { get; set; } + public int ShutdownVacancySeconds { get; set; } + public eShutdownType ShutdownType { get; private set; } + + public EssentialsRoomEmergencyBase Emergency { get; set; } + + public Privacy.MicrophonePrivacyController MicrophonePrivacy { get; set; } + + public string LogoUrl { get; set; } + + protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; } + + public eVacancyMode VacancyMode { get; private set; } + + /// + /// Seconds after vacancy prompt is displayed until shutdown + /// + protected int RoomVacancyShutdownSeconds; + + /// + /// Seconds after vacancy detected until prompt is displayed + /// + protected int RoomVacancyShutdownPromptSeconds; + + /// + /// + /// + protected Func OnFeedbackFunc; + + protected Dictionary SavedVolumeLevels = new Dictionary(); + + /// + /// When volume control devices change, should we zero the one that we are leaving? + /// + public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; } + + + protected EssentialsRoomBase(DeviceConfig config) + : base(config) + { + // Setup the ShutdownPromptTimer + ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); + ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => + { + if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue) + ShutdownType = eShutdownType.None; + }; + ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered + + ShutdownPromptSeconds = 60; + ShutdownVacancySeconds = 120; + + ShutdownType = eShutdownType.None; + + RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer"); + //RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) => + //{ + // if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue) + // ShutdownType = ShutdownType.Vacancy; + //}; + RoomVacancyShutdownTimer.HasFinished += RoomVacancyShutdownPromptTimer_HasFinished; // Shutdown is triggered + + RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning + RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt + VacancyMode = eVacancyMode.None; + + OnFeedback = new BoolFeedback(OnFeedbackFunc); + + IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc); + IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc); + + AddPostActivationAction(() => + { + if (RoomOccupancy != null) + OnRoomOccupancyIsSet(); + }); + } + + protected void InitializeDisplay(DisplayBase display) + { + // Link power, warming, cooling to display + display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange; + + display.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedbackOnOutputChange; + display.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedbackOnOutputChange; + } + + protected void UpdateInUseTracking(IInUseTracking oldDev, IInUseTracking newDev) + { + // derigister this room from the device, if it can + if (oldDev != null) + { + oldDev.InUseTracker.RemoveUser(this, "audio"); + } + + // register this room with new device, if it can + if (newDev != null) + { + newDev.InUseTracker.AddUser(this, "audio"); + } + } + + protected abstract void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs args); + protected abstract void IsWarmingUpFeedbackOnOutputChange(object sender, FeedbackEventArgs args); + protected abstract void IsCoolingDownFeedbackOnOutputChange(object sender, FeedbackEventArgs args); + + private void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e) + { + switch (VacancyMode) + { + case eVacancyMode.None: + StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); + break; + case eVacancyMode.InInitialVacancy: + StartRoomVacancyTimer(eVacancyMode.InShutdownWarning); + break; + case eVacancyMode.InShutdownWarning: + { + StartShutdown(eShutdownType.Vacancy); + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Shutting Down due to vacancy."); + break; + } + } + } + + /// + /// + /// + /// + public void StartShutdown(eShutdownType type) + { + // Check for shutdowns running. Manual should override other shutdowns + + switch (type) + { + case eShutdownType.Manual: + ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds; + break; + case eShutdownType.Vacancy: + ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds; + break; + } + ShutdownType = type; + ShutdownPromptTimer.Start(); + + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "ShutdownPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount); + } + + public void StartRoomVacancyTimer(eVacancyMode mode) + { + switch (mode) + { + case eVacancyMode.None: + RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds; + break; + case eVacancyMode.InInitialVacancy: + RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds; + break; + case eVacancyMode.InShutdownWarning: + RoomVacancyShutdownTimer.SecondsToCount = 60; + break; + } + VacancyMode = mode; + RoomVacancyShutdownTimer.Start(); + + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount); + } + + /// + /// Resets the vacancy mode and shutsdwon the room + /// + public void Shutdown() + { + VacancyMode = eVacancyMode.None; + EndShutdown(); + } + + /// + /// This method is for the derived class to define it's specific shutdown + /// requirements but should not be called directly. It is called by Shutdown() + /// + protected abstract void EndShutdown(); + + + /// + /// Override this to implement a default volume level(s) method + /// + public abstract void SetDefaultLevels(); + + /// + /// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device + /// + /// + /// + public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes) + { + var provider = statusProvider as IKeyed; + + if (provider == null) + { + Debug.Console(0, this, "ERROR: Occupancy sensor device is null"); + return; + } + + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Room Occupancy set to device: '{0}'", provider.Key); + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Timeout Minutes from Config is: {0}", timeoutMinutes); + + // If status provider is fusion, set flag to remote + if (statusProvider is Fusion.EssentialsHuddleSpaceFusionSystemControllerBase) + OccupancyStatusProviderIsRemote = true; + + if(timeoutMinutes > 0) + RoomVacancyShutdownSeconds = timeoutMinutes * 60; + + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); + + RoomOccupancy = statusProvider; + + RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; + RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; + + OnRoomOccupancyIsSet(); + } + + void OnRoomOccupancyIsSet() + { + var handler = RoomOccupancyIsSet; + if (handler != null) + handler(this, new EventArgs()); + } + + /// + /// To allow base class to power room on to last source + /// + public abstract void PowerOnToDefaultOrLastSource(); + + /// + /// To allow base class to power room on to default source + /// + /// + public abstract bool RunDefaultPresentRoute(); + + void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e) + { + if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Vacancy Detected"); + // Trigger the timer when the room is vacant + StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); + } + else + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Notice: Occupancy Detected"); + // Reset the timer when the room is occupied + RoomVacancyShutdownTimer.Cancel(); + } + } + + /// + /// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed + /// + /// + public abstract void RoomVacatedForTimeoutPeriod(object o); + } + + /// + /// To describe the various ways a room may be shutting down + /// + public enum eShutdownType + { + None = 0, + External, + Manual, + Vacancy + } + + public enum eVacancyMode + { + None = 0, + InInitialVacancy, + InShutdownWarning + } + + /// + /// + /// + public enum eWarmingCoolingMode + { + None, + Warming, + Cooling + } + + public abstract class EssentialsRoomEmergencyBase : IKeyed + { + public string Key { get; private set; } + + protected EssentialsRoomEmergencyBase(string key) + { + Key = key; + } + } } \ No newline at end of file