diff --git a/PepperDashEssentials/AppServer/Interfaces.cs b/PepperDashEssentials/AppServer/Interfaces.cs index df651ef8..4372ef8a 100644 --- a/PepperDashEssentials/AppServer/Interfaces.cs +++ b/PepperDashEssentials/AppServer/Interfaces.cs @@ -19,42 +19,3 @@ namespace PepperDash.Essentials.Room.Cotija } } -namespace PepperDash.Essentials -{ - /// - /// For rooms with a single presentation source, change event - /// - public interface IHasCurrentSourceInfoChange - { - string CurrentSourceInfoKey { get; } - SourceListItem CurrentSourceInfo { get; } - event SourceInfoChangeHandler CurrentSingleSourceChange; - } - - - /// - /// For rooms with routing - /// - public interface IRunRouteAction - { - void RunRouteAction(string routeKey); - - void RunRouteAction(string routeKey, Action successCallback); - } - - /// - /// For rooms that default presentation only routing - /// - public interface IRunDefaultPresentRoute - { - bool RunDefaultPresentRoute(); - } - - /// - /// For rooms that have default presentation and calling routes - /// - public interface IRunDefaultCallRoute : IRunDefaultPresentRoute - { - bool RunDefaultCallRoute(); - } -} \ No newline at end of file diff --git a/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs b/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs index 4fd75a36..62a2957c 100644 --- a/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs +++ b/PepperDashEssentials/AppServer/RoomBridges/CotijaEssentialsHuddleSpaceRoomBridge.cs @@ -93,7 +93,7 @@ namespace PepperDash.Essentials var sscRoom = Room as IHasCurrentSourceInfoChange; if(sscRoom != null) - sscRoom.CurrentSingleSourceChange += new SourceInfoChangeHandler(Room_CurrentSingleSourceChange); + sscRoom.CurrentSingleDisplaySourceChange += new SourceInfoChangeHandler(Room_CurrentSingleSourceChange); var vcRoom = Room as IHasVideoCodec; if (vcRoom != null && vcRoom.VideoCodec != null) diff --git a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/EssentialsHuddleVtc1FusionController.cs b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs similarity index 99% rename from PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/EssentialsHuddleVtc1FusionController.cs rename to PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs index c79d49d7..16d7e3d2 100644 --- a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/EssentialsHuddleVtc1FusionController.cs +++ b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs @@ -14,6 +14,7 @@ using PepperDash.Core; using PepperDash.Essentials; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; +using PepperDash.Core.Fusion; using PepperDash.Essentials.Devices.Common; using PepperDash.Essentials.Devices.Common.Occupancy; @@ -181,7 +182,7 @@ namespace PepperDash.Essentials.Fusion // Moved to CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source", eSigIoMask.InputSigOnly); // Don't think we need to get current status of this as nothing should be alive yet. - (Room as EssentialsHuddleVtc1Room).CurrentSingleSourceChange += Room_CurrentSourceInfoChange; + (Room as EssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange; FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource); @@ -220,7 +221,7 @@ namespace PepperDash.Essentials.Fusion break; } - var laptops = dict.Where(d => d.Value.SourceDevice is Laptop); + var laptops = dict.Where(d => d.Value.SourceDevice is Core.Devices.Laptop); i = 1; foreach (var kvp in laptops) { diff --git a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionSystemController.cs.orig b/PepperDashEssentials/Fusion/FusionSystemController.cs.orig similarity index 100% rename from PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionSystemController.cs.orig rename to PepperDashEssentials/Fusion/FusionSystemController.cs.orig diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 6ef7e20f..348a84a5 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -173,16 +173,11 @@ - - - - - + - - + @@ -206,10 +201,10 @@ + - @@ -273,6 +268,9 @@ Essentials Devices Common + + + diff --git a/PepperDashEssentials/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs b/PepperDashEssentials/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs new file mode 100644 index 00000000..6abafc24 --- /dev/null +++ b/PepperDashEssentials/Room/Config/EssentialsDualDisplayRoomPropertiesConfig.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Room.Config +{ + public class EssentialsDualDisplayRoomPropertiesConfig : EssentialsNDisplayRoomPropertiesConfig + { + + public const string LeftDisplayId = "leftDisplay"; + public const string RightDisplayId = "rightDisplay"; + } +} \ No newline at end of file diff --git a/PepperDashEssentials/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs b/PepperDashEssentials/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs index 16e49933..5ce13bfa 100644 --- a/PepperDashEssentials/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsHuddleVtc1PropertiesConfig.cs @@ -8,19 +8,10 @@ using Newtonsoft.Json; namespace PepperDash.Essentials.Room.Config { - public class EssentialsHuddleVtc1PropertiesConfig : EssentialsRoomPropertiesConfig + public class EssentialsHuddleVtc1PropertiesConfig : EssentialsConferenceRoomPropertiesConfig { [JsonProperty("defaultDisplayKey")] public string DefaultDisplayKey { get; set; } - [JsonProperty("defaultAudioKey")] - public string DefaultAudioKey { get; set; } - [JsonProperty("sourceListKey")] - public string SourceListKey { get; set; } - [JsonProperty("defaultSourceItem")] - public string DefaultSourceItem { get; set; } - [JsonProperty("videoCodecKey")] - public string VideoCodecKey { get; set; } - [JsonProperty("audioCodecKey")] - public string AudioCodecKey { get; set; } + } } \ No newline at end of file diff --git a/PepperDashEssentials/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs b/PepperDashEssentials/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs index 6bd2009e..b72dd9b9 100644 --- a/PepperDashEssentials/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsNDisplayRoomPropertiesConfig.cs @@ -4,22 +4,27 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Room.Config { /// /// /// - public class EssentialsNDisplayRoomPropertiesConfig : EssentialsRoomPropertiesConfig + public class EssentialsNDisplayRoomPropertiesConfig : EssentialsConferenceRoomPropertiesConfig { + [JsonProperty("defaultAudioBehavior")] public string DefaultAudioBehavior { get; set; } - public string DefaultAudioKey { get; set; } + [JsonProperty("defaultVideoBehavior")] public string DefaultVideoBehavior { get; set; } + [JsonProperty("displays")] public Dictionary Displays { get; set; } - public string SourceListKey { get; set; } public EssentialsNDisplayRoomPropertiesConfig() { Displays = new Dictionary(); } + } + } \ No newline at end of file diff --git a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs index 7b7718eb..aa5fe12e 100644 --- a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs @@ -76,7 +76,7 @@ namespace PepperDash.Essentials.Room.Config } // Get the MicrophonePrivacy device from the device manager var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as - PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController); + Core.Privacy.MicrophonePrivacyController); // Set this room as the IPrivacy device if (mP == null) { @@ -175,6 +175,25 @@ namespace PepperDash.Essentials.Room.Config public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; } } + public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig + { + [JsonProperty("defaultAudioKey")] + public string DefaultAudioKey { get; set; } + [JsonProperty("sourceListKey")] + public string SourceListKey { get; set; } + [JsonProperty("defaultSourceItem")] + public string DefaultSourceItem { get; set; } + + } + + public class EssentialsConferenceRoomPropertiesConfig : EssentialsAvRoomPropertiesConfig + { + [JsonProperty("videoCodecKey")] + public string VideoCodecKey { get; set; } + [JsonProperty("audioCodecKey")] + public string AudioCodecKey { get; set; } + } + public class EssentialsEnvironmentPropertiesConfig { public bool Enabled { get; set; } diff --git a/PepperDashEssentials/Room/Emergency/EsentialsRoomEmergencyContactClosure.cs b/PepperDashEssentials/Room/Emergency/EsentialsRoomEmergencyContactClosure.cs index 09e09bda..ab40d2fe 100644 --- a/PepperDashEssentials/Room/Emergency/EsentialsRoomEmergencyContactClosure.cs +++ b/PepperDashEssentials/Room/Emergency/EsentialsRoomEmergencyContactClosure.cs @@ -12,15 +12,7 @@ using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Room { - public abstract class EssentialsRoomEmergencyBase : IKeyed - { - public string Key { get; private set; } - public EssentialsRoomEmergencyBase(string key) - { - Key = key; - } - } public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase diff --git a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs new file mode 100644 index 00000000..207fbf8d --- /dev/null +++ b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using Newtonsoft.Json; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Devices; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Room.Config; +using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.VideoCodec; +using PepperDash.Essentials.Devices.Common.AudioCodec; + +namespace PepperDash.Essentials.Room.Types +{ + public class EssentialsDualDisplayRoom : EssentialsNDisplayRoomBase, IHasCurrentVolumeControls, + IRunRouteAction, IPrivacy, IPrivacy, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec + { + public event EventHandler CurrentVolumeDeviceChange; + + public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; } + + //************************ + // Call-related stuff + + public BoolFeedback InCallFeedback { get; private set; } + + /// + /// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis + /// + public IntFeedback CallTypeFeedback { get; private set; } + + /// + /// + /// + public BoolFeedback PrivacyModeIsOnFeedback { get; private set; } + + /// + /// When something in the room is sharing with the far end or through other means + /// + public BoolFeedback IsSharingFeedback { get; private set; } + + IRoutingSinkWithSwitching LeftDisplay { get; private set; } + IRoutingSinkWithSwitching RightDisplay { get; private set; } + + + protected override Func OnFeedbackFunc + { + get + { + return () => + { + var leftDisp = LeftDisplay as DisplayBase; + var rightDisp = RightDisplay as DisplayBase; + var val = leftDisp != null && leftDisp.CurrentSourceInfo != null + && leftDisp.CurrentSourceInfo.Type == eSourceListItemType.Route + && rightDisp != null && rightDisp.CurrentSourceInfo != null + && rightDisp.CurrentSourceInfo.Type == eSourceListItemType.Route; + return val; + }; + } + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs index 63f0bb29..429a6102 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs @@ -16,7 +16,7 @@ namespace PepperDash.Essentials public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasCurrentVolumeControls { public event EventHandler CurrentVolumeDeviceChange; - public event SourceInfoChangeHandler CurrentSingleSourceChange; + public event SourceInfoChangeHandler CurrentSourceChange; protected override Func OnFeedbackFunc { @@ -76,11 +76,6 @@ namespace PepperDash.Essentials public bool ExcludeFromGlobalFunctions { get; set; } - /// - /// The config name of the source list - /// - public string SourceListKey { get; set; } - public string DefaultSourceItem { get; set; } public ushort DefaultVolume { get; set; } @@ -128,7 +123,7 @@ namespace PepperDash.Essentials { if (value == _CurrentSourceInfo) return; - var handler = CurrentSingleSourceChange; + var handler = CurrentSourceChange; // remove from in-use tracker, if so equipped if(_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control"); @@ -251,7 +246,7 @@ namespace PepperDash.Essentials // Add Occupancy object from config if (PropertiesConfig.Occupancy != null) this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as - PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes); + IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes); this.LogoUrl = PropertiesConfig.Logo.GetUrl(); this.SourceListKey = PropertiesConfig.SourceListKey; diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index d83c8e9a..3ea1705b 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -20,7 +20,7 @@ namespace PepperDash.Essentials IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec { public event EventHandler CurrentVolumeDeviceChange; - public event SourceInfoChangeHandler CurrentSingleSourceChange; + public event SourceInfoChangeHandler CurrentSourceChange; //************************ @@ -166,7 +166,7 @@ namespace PepperDash.Essentials { if (value == _CurrentSourceInfo) return; - var handler = CurrentSingleSourceChange; + var handler = CurrentSourceChange; // remove from in-use tracker, if so equipped if(_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control"); @@ -330,7 +330,7 @@ namespace PepperDash.Essentials // Add Occupancy object from config if (PropertiesConfig.Occupancy != null) this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as - PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes); + IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes); this.LogoUrl = PropertiesConfig.Logo.GetUrl(); this.SourceListKey = PropertiesConfig.SourceListKey; diff --git a/PepperDashEssentials/Room/Types/EssentialsNDisplayRoomBase.cs b/PepperDashEssentials/Room/Types/EssentialsNDisplayRoomBase.cs index 9cdb14c9..21130cc7 100644 --- a/PepperDashEssentials/Room/Types/EssentialsNDisplayRoomBase.cs +++ b/PepperDashEssentials/Room/Types/EssentialsNDisplayRoomBase.cs @@ -19,13 +19,10 @@ namespace PepperDash.Essentials.Room.Types /// public abstract class EssentialsNDisplayRoomBase : EssentialsRoomBase { - public event SourceInfoChangeHandler CurrentSingleSourceChange; + //public event SourceInfoChangeHandler CurrentSingleSourceChange; public Dictionary Displays { get; protected set; } - protected override Func IsWarmingFeedbackFunc { get { return () => false; ; } } - protected override Func IsCoolingFeedbackFunc { get { return () => false; } } - public EssentialsNDisplayRoomBase(DeviceConfig config) : base (config) { diff --git a/PepperDashEssentials/UI/SubpageReferenceListSourceItem.cs b/PepperDashEssentials/UI/SubpageReferenceListSourceItem.cs index 73cc5e71..e9701bae 100644 --- a/PepperDashEssentials/UI/SubpageReferenceListSourceItem.cs +++ b/PepperDashEssentials/UI/SubpageReferenceListSourceItem.cs @@ -25,8 +25,8 @@ namespace PepperDash.Essentials public void RegisterForSourceChange(IHasCurrentSourceInfoChange room) { - room.CurrentSingleSourceChange -= room_CurrentSourceInfoChange; - room.CurrentSingleSourceChange += room_CurrentSourceInfoChange; + room.CurrentSingleDisplaySourceChange -= room_CurrentSourceInfoChange; + room.CurrentSingleDisplaySourceChange += room_CurrentSourceInfoChange; } void room_CurrentSourceInfoChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs index 9a2b7a31..fca0dd71 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs @@ -733,7 +733,7 @@ namespace PepperDash.Essentials // Disconnect current room _CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange; ClearAudioDeviceConnections(); - _CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange; + _CurrentRoom.CurrentSourceChange -= this.CurrentRoom_SourceInfoChange; DisconnectSource(_CurrentRoom.CurrentSourceInfo); _CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted; _CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished; @@ -803,7 +803,7 @@ namespace PepperDash.Essentials _CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange; RefreshAudioDeviceConnections(); - _CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange; + _CurrentRoom.CurrentSourceChange += CurrentRoom_SourceInfoChange; RefreshSourceInfo(); (Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom); diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs index be51a4aa..de831b8c 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs @@ -885,7 +885,7 @@ namespace PepperDash.Essentials // Disconnect current room _CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange; ClearAudioDeviceConnections(); - _CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange; + _CurrentRoom.CurrentSourceChange -= this.CurrentRoom_SourceInfoChange; DisconnectSource(_CurrentRoom.CurrentSourceInfo); _CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted; _CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished; @@ -924,7 +924,7 @@ namespace PepperDash.Essentials _CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange; RefreshAudioDeviceConnections(); - _CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange; + _CurrentRoom.CurrentSourceChange += CurrentRoom_SourceInfoChange; RefreshSourceInfo(); if (_CurrentRoom.VideoCodec is IHasScheduleAwareness) @@ -939,7 +939,7 @@ namespace PepperDash.Essentials SetActiveCallListSharingContentStatus(); if (_CurrentRoom != null) - _CurrentRoom.CurrentSingleSourceChange += new SourceInfoChangeHandler(CurrentRoom_CurrentSingleSourceChange); + _CurrentRoom.CurrentSourceChange += new SourceInfoChangeHandler(CurrentRoom_CurrentSingleSourceChange); TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, () => _CurrentRoom.RunRouteAction("codecOsd")); diff --git a/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs b/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs index e942913a..60ccf96a 100644 --- a/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs +++ b/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs @@ -64,7 +64,7 @@ namespace PepperDash.Essentials parent.SetItemMainText(index, room.Name); UpdateItem(room.CurrentSourceInfo); // Watch for later changes - room.CurrentSingleSourceChange += new SourceInfoChangeHandler(room_CurrentSourceInfoChange); + room.CurrentSourceChange += new SourceInfoChangeHandler(room_CurrentSourceInfoChange); parent.SetItemButtonAction(index, buttonAction); } diff --git a/PepperDashEssentials/UIDrivers/SourceChangeArgs.cs b/PepperDashEssentials/UIDrivers/SourceChangeArgs.cs index 621ba257..c777c08e 100644 --- a/PepperDashEssentials/UIDrivers/SourceChangeArgs.cs +++ b/PepperDashEssentials/UIDrivers/SourceChangeArgs.cs @@ -9,8 +9,8 @@ using PepperDash.Essentials.Core; namespace PepperDash.Essentials { - /// - /// The handler type for a Room's SourceInfoChange - /// - public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type); + ///// + ///// The handler type for a Room's SourceInfoChange + ///// + //public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type); } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/PC/InRoomPc.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/PC/InRoomPc.cs similarity index 97% rename from essentials-framework/Essentials Devices Common/Essentials Devices Common/PC/InRoomPc.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/PC/InRoomPc.cs index f3c8ca0e..9a13106f 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/PC/InRoomPc.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/PC/InRoomPc.cs @@ -7,7 +7,7 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Routing; using PepperDash.Core; -namespace PepperDash.Essentials.Devices.Common +namespace PepperDash.Essentials.Core.Devices { /// /// This DVD class should cover most IR, one-way DVD and Bluray fuctions diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/PC/Laptop.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/PC/Laptop.cs similarity index 97% rename from essentials-framework/Essentials Devices Common/Essentials Devices Common/PC/Laptop.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/PC/Laptop.cs index 6ed08e58..a1a8b30b 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/PC/Laptop.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/PC/Laptop.cs @@ -7,7 +7,7 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Routing; using PepperDash.Core; -namespace PepperDash.Essentials.Devices.Common +namespace PepperDash.Essentials.Core.Devices { /// /// This DVD class should cover most IR, one-way DVD and Bluray fuctions diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/DisplayBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/DisplayBase.cs index 9ef0ee86..8b3b6191 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/DisplayBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/DisplayBase.cs @@ -18,6 +18,11 @@ namespace PepperDash.Essentials.Core /// public abstract class DisplayBase : Device, IHasFeedback, IRoutingSinkWithSwitching, IPower, IWarmingCooling, IUsageTracking { + public event SourceInfoChangeHandler CurrentSourceChange; + + public string CurrentSourceInfoKey { get; protected set; } + public SourceListItem CurrentSourceInfo { get; protected set; } + public BoolFeedback PowerIsOnFeedback { get; protected set; } public BoolFeedback IsCoolingDownFeedback { get; protected set; } public BoolFeedback IsWarmingUpFeedback { get; private set; } diff --git a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs similarity index 98% rename from PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index e7623975..e844e91f 100644 --- a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -18,12 +18,10 @@ using PepperDash.Core; using PepperDash.Essentials; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Devices.Common; -using PepperDash.Essentials.Devices.Common.Occupancy; -namespace PepperDash.Essentials.Fusion +namespace PepperDash.Essentials.Core.Fusion { public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider { @@ -330,11 +328,11 @@ namespace PepperDash.Essentials.Fusion // Moved to CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source", eSigIoMask.InputSigOnly); // Don't think we need to get current status of this as nothing should be alive yet. - (Room as EssentialsHuddleSpaceRoom).CurrentSingleSourceChange += new SourceInfoChangeHandler(Room_CurrentSourceInfoChange); + (Room as IHasCurrentSourceInfoChange).CurrentSourceChange += new SourceInfoChangeHandler(Room_CurrentSourceInfoChange); - FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleSpaceRoom).PowerOnToDefaultOrLastSource); - FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff")); + FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsRoomBase).PowerOnToDefaultOrLastSource); + FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as IRunRouteAction).RunRouteAction("roomOff")); // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); FusionRoom.ErrorMessage.InputSig.StringValue = "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; @@ -990,7 +988,7 @@ namespace PepperDash.Essentials.Fusion protected virtual void SetUpSources() { // Sources - var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsHuddleSpaceRoom).SourceListKey); + var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsRoomBase).SourceListKey); if (dict != null) { // NEW PROCESS: @@ -1015,7 +1013,7 @@ namespace PepperDash.Essentials.Fusion break; } - var laptops = dict.Where(d => d.Value.SourceDevice is Laptop); + var laptops = dict.Where(d => d.Value.SourceDevice is Devices.Laptop); i = 1; foreach (var kvp in laptops) { @@ -1041,7 +1039,7 @@ namespace PepperDash.Essentials.Fusion else { Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'", - (Room as EssentialsHuddleSpaceRoom).SourceListKey, Room.Key); + (Room as EssentialsRoomBase).SourceListKey, Room.Key); } } @@ -1088,7 +1086,7 @@ namespace PepperDash.Essentials.Fusion SourceToFeedbackSigs.Add(pSrc, sigD.InputSig); // And respond to selection in Fusion - sigD.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleSpaceRoom).RunRouteAction(routeKey)); + sigD.OutputSig.SetSigFalseAction(() => (Room as IRunRouteAction).RunRouteAction(routeKey)); } catch (Exception) { @@ -1290,7 +1288,7 @@ namespace PepperDash.Essentials.Fusion // Current Source var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig); - defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff"); }); ; + defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as IRunRouteAction).RunRouteAction("roomOff"); }); ; } } diff --git a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionCustomPropertiesBridge.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs similarity index 98% rename from PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionCustomPropertiesBridge.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs index b5704b40..01b230f9 100644 --- a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionCustomPropertiesBridge.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs @@ -10,9 +10,8 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; -using PepperDash.Essentials.Room.Behaviours; -namespace PepperDash.Essentials.Fusion +namespace PepperDash.Essentials.Core.Fusion { /// /// Handles mapping Fusion Custom Property values to system properties diff --git a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionEventHandlers.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionEventHandlers.cs similarity index 88% rename from PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionEventHandlers.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionEventHandlers.cs index 4987c047..26647a96 100644 --- a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionEventHandlers.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionEventHandlers.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; -namespace PepperDash.Essentials.Fusion +namespace PepperDash.Essentials.Core.Fusion { public class ScheduleChangeEventArgs : EventArgs { diff --git a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionProcessorQueries.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionProcessorQueries.cs similarity index 97% rename from PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionProcessorQueries.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionProcessorQueries.cs index 8757be62..62109d97 100644 --- a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionProcessorQueries.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionProcessorQueries.cs @@ -4,9 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Fusion +namespace PepperDash.Essentials.Core.Fusion { /// /// When created, runs progcomments on every slot and stores the program names in a list diff --git a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionRviDataClasses.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionRviDataClasses.cs similarity index 99% rename from PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionRviDataClasses.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionRviDataClasses.cs index 3752531a..99fc0abb 100644 --- a/PepperDashEssentials/FOR REFERENCE UI/OTHER/Fusion/FusionRviDataClasses.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionRviDataClasses.cs @@ -7,7 +7,7 @@ using Crestron.SimplSharpPro.Fusion; using PepperDash.Core; -namespace PepperDash.Essentials.Fusion +namespace PepperDash.Essentials.Core.Fusion { // Helper Classes for GUIDs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/MOVED FusionSystemController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/MOVED FusionSystemController.cs deleted file mode 100644 index 8e7e70c6..00000000 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/MOVED FusionSystemController.cs +++ /dev/null @@ -1,377 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text; - -//using Crestron.SimplSharp; -//using Crestron.SimplSharpPro; -//using Crestron.SimplSharpPro.DeviceSupport; - -//using Crestron.SimplSharpPro.Fusion; -//using PepperDash.Essentials.Core; - -//using PepperDash.Core; - - -//namespace PepperDash.Essentials.Core.Fusion -//{ -// public class EssentialsHuddleSpaceFusionSystemController : Device -// { -// FusionRoom FusionRoom; -// Room Room; -// Dictionary SourceToFeedbackSigs = new Dictionary(); - -// StatusMonitorCollection ErrorMessageRollUp; - -// public EssentialsHuddleSpaceFusionSystemController(HuddleSpaceRoom room, uint ipId) -// : base(room.Key + "-fusion") -// { -// Room = room; - -// FusionRoom = new FusionRoom(ipId, Global.ControlSystem, room.Name, "awesomeGuid-" + room.Key); -// FusionRoom.Register(); - -// FusionRoom.FusionStateChange += new FusionStateEventHandler(FusionRoom_FusionStateChange); - -// // Room to fusion room -// room.RoomIsOn.LinkInputSig(FusionRoom.SystemPowerOn.InputSig); -// var srcName = FusionRoom.CreateOffsetStringSig(50, "Source - Name", eSigIoMask.InputSigOnly); -// room.CurrentSourceName.LinkInputSig(srcName.InputSig); - -// FusionRoom.SystemPowerOn.OutputSig.UserObject = new Action(b => { if (b) room.RoomOn(null); }); -// FusionRoom.SystemPowerOff.OutputSig.UserObject = new Action(b => { if (b) room.RoomOff(); }); -// // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); -// FusionRoom.ErrorMessage.InputSig.StringValue = "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; - -// // Sources -// foreach (var src in room.Sources) -// { -// var srcNum = src.Key; -// var pSrc = src.Value as IPresentationSource; -// var keyNum = ExtractNumberFromKey(pSrc.Key); -// if (keyNum == -1) -// { -// Debug.Console(1, this, "WARNING: Cannot link source '{0}' to numbered Fusion attributes", pSrc.Key); -// continue; -// } -// string attrName = null; -// uint attrNum = Convert.ToUInt32(keyNum); -// switch (pSrc.Type) -// { -// case PresentationSourceType.None: -// break; -// case PresentationSourceType.SetTopBox: -// attrName = "Source - TV " + keyNum; -// attrNum += 115; // TV starts at 116 -// break; -// case PresentationSourceType.Dvd: -// attrName = "Source - DVD " + keyNum; -// attrNum += 120; // DVD starts at 121 -// break; -// case PresentationSourceType.PC: -// attrName = "Source - PC " + keyNum; -// attrNum += 110; // PC starts at 111 -// break; -// case PresentationSourceType.Laptop: -// attrName = "Source - Laptop " + keyNum; -// attrNum += 100; // Laptops start at 101 -// break; -// case PresentationSourceType.VCR: -// attrName = "Source - VCR " + keyNum; -// attrNum += 125; // VCRs start at 126 -// break; -// } -// if (attrName == null) -// { -// Debug.Console(1, this, "Source type {0} does not have corresponsing Fusion attribute type, skipping", pSrc.Type); -// continue; -// } -// Debug.Console(2, this, "Creating attribute '{0}' with join {1} for source {2}", attrName, attrNum, pSrc.Key); -// var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputOutputSig); -// // Need feedback when this source is selected -// // Event handler, added below, will compare source changes with this sig dict -// SourceToFeedbackSigs.Add(pSrc, sigD.InputSig); - -// // And respond to selection in Fusion -// sigD.OutputSig.UserObject = new Action(b => { if(b) room.SelectSource(pSrc); }); -// } - -// // Attach to all room's devices with monitors. -// //foreach (var dev in DeviceManager.Devices) -// foreach (var dev in DeviceManager.GetDevices()) -// { -// if (!(dev is ICommunicationMonitor)) -// continue; - -// var keyNum = ExtractNumberFromKey(dev.Key); -// if (keyNum == -1) -// { -// Debug.Console(1, this, "WARNING: Cannot link device '{0}' to numbered Fusion monitoring attributes", dev.Key); -// continue; -// } -// string attrName = null; -// uint attrNum = Convert.ToUInt32(keyNum); - -// //if (dev is SmartGraphicsTouchpanelControllerBase) -// //{ -// // if (attrNum > 10) -// // continue; -// // attrName = "Device Ok - Touch Panel " + attrNum; -// // attrNum += 200; -// //} -// //// add xpanel here - -// //else -// if (dev is DisplayBase) -// { -// if (attrNum > 10) -// continue; -// attrName = "Device Ok - Display " + attrNum; -// attrNum += 240; -// } -// //else if (dev is DvdDeviceBase) -// //{ -// // if (attrNum > 5) -// // continue; -// // attrName = "Device Ok - DVD " + attrNum; -// // attrNum += 260; -// //} -// // add set top box - -// // add Cresnet roll-up - -// // add DM-devices roll-up - -// if (attrName != null) -// { -// // Link comm status to sig and update -// var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly); -// var smd = dev as ICommunicationMonitor; -// sigD.InputSig.BoolValue = smd.CommunicationMonitor.Status == MonitorStatus.IsOk; -// smd.CommunicationMonitor.StatusChange += (o, a) => { sigD.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; }; -// Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", dev.Key, attrName); -// } -// } - -// // Don't think we need to get current status of this as nothing should be alive yet. -// room.PresentationSourceChange += Room_PresentationSourceChange; - -// // these get used in multiple places -// var display = room.Display; -// var dispPowerOnAction = new Action(b => { if (!b) display.PowerOn(); }); -// var dispPowerOffAction = new Action(b => { if (!b) display.PowerOff(); }); - -// // Display to fusion room sigs -// FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction; -// FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction; -// display.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig); -// if (display is IDisplayUsage) -// (display as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig); - -// // Roll up ALL device errors -// ErrorMessageRollUp = new StatusMonitorCollection(this); -// foreach (var dev in DeviceManager.GetDevices()) -// { -// var md = dev as ICommunicationMonitor; -// if (md != null) -// { -// ErrorMessageRollUp.AddMonitor(md.CommunicationMonitor); -// Debug.Console(2, this, "Adding '{0}' to room's overall error monitor", md.CommunicationMonitor.Parent.Key); -// } -// } -// ErrorMessageRollUp.Start(); -// FusionRoom.ErrorMessage.InputSig.StringValue = ErrorMessageRollUp.Message; -// ErrorMessageRollUp.StatusChange += (o, a) => { -// FusionRoom.ErrorMessage.InputSig.StringValue = ErrorMessageRollUp.Message; }; - - -// // static assets --------------- testing - -// // test assets --- THESE ARE BOTH WIRED TO AssetUsage somewhere internally. -// var ta1 = FusionRoom.CreateStaticAsset(1, "Test asset 1", "Awesome Asset", "Awesome123"); -// ta1.AssetError.InputSig.StringValue = "This should be error"; - - -// var ta2 = FusionRoom.CreateStaticAsset(2, "Test asset 2", "Awesome Asset", "Awesome1232"); -// ta2.AssetUsage.InputSig.StringValue = "This should be usage"; - - -// // Make a display asset -// var dispAsset = FusionRoom.CreateStaticAsset(3, display.Name, "Display", "awesomeDisplayId" + room.Key); -// dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; -// dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; -// display.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig); -// // NO!! display.PowerIsOn.LinkComplementInputSig(dispAsset.PowerOff.InputSig); -// // Use extension methods -// dispAsset.TrySetMakeModel(display); -// dispAsset.TryLinkAssetErrorToCommunication(display); - - -// // Make it so! -// FusionRVI.GenerateFileForAllFusionDevices(); -// } - -// /// -// /// Helper to get the number from the end of a device's key string -// /// -// /// -1 if no number matched -// int ExtractNumberFromKey(string key) -// { -// var capture = System.Text.RegularExpressions.Regex.Match(key, @"\D+(\d+)"); -// if (!capture.Success) -// return -1; -// else return Convert.ToInt32(capture.Groups[1].Value); -// } - -// void Room_PresentationSourceChange(object sender, EssentialsRoomSourceChangeEventArgs e) -// { -// if (e.OldSource != null) -// { -// if (SourceToFeedbackSigs.ContainsKey(e.OldSource)) -// SourceToFeedbackSigs[e.OldSource].BoolValue = false; -// } -// if (e.NewSource != null) -// { -// if (SourceToFeedbackSigs.ContainsKey(e.NewSource)) -// SourceToFeedbackSigs[e.NewSource].BoolValue = true; -// } -// } - -// void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args) -// { - -// // The sig/UO method: Need separate handlers for fixed and user sigs, all flavors, -// // even though they all contain sigs. - -// var sigData = (args.UserConfiguredSigDetail as BooleanSigDataFixedName); -// if (sigData != null) -// { -// var outSig = sigData.OutputSig; -// if (outSig.UserObject is Action) -// (outSig.UserObject as Action).Invoke(outSig.BoolValue); -// else if (outSig.UserObject is Action) -// (outSig.UserObject as Action).Invoke(outSig.UShortValue); -// else if (outSig.UserObject is Action) -// (outSig.UserObject as Action).Invoke(outSig.StringValue); -// return; -// } - -// var attrData = (args.UserConfiguredSigDetail as BooleanSigData); -// if (attrData != null) -// { -// var outSig = attrData.OutputSig; -// if (outSig.UserObject is Action) -// (outSig.UserObject as Action).Invoke(outSig.BoolValue); -// else if (outSig.UserObject is Action) -// (outSig.UserObject as Action).Invoke(outSig.UShortValue); -// else if (outSig.UserObject is Action) -// (outSig.UserObject as Action).Invoke(outSig.StringValue); -// return; -// } - -// } -// } - - -// public static class FusionRoomExtensions -// { -// /// -// /// Creates and returns a fusion attribute. The join number will match the established Simpl -// /// standard of 50+, and will generate a 50+ join in the RVI. It calls -// /// FusionRoom.AddSig with join number - 49 -// /// -// /// The new attribute -// public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) -// { -// if (number < 50) throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); -// number -= 49; -// fr.AddSig(eSigType.Bool, number, name, mask); -// return fr.UserDefinedBooleanSigDetails[number]; -// } - -// /// -// /// Creates and returns a fusion attribute. The join number will match the established Simpl -// /// standard of 50+, and will generate a 50+ join in the RVI. It calls -// /// FusionRoom.AddSig with join number - 49 -// /// -// /// The new attribute -// public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) -// { -// if (number < 50) throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); -// number -= 49; -// fr.AddSig(eSigType.UShort, number, name, mask); -// return fr.UserDefinedUShortSigDetails[number]; -// } - -// /// -// /// Creates and returns a fusion attribute. The join number will match the established Simpl -// /// standard of 50+, and will generate a 50+ join in the RVI. It calls -// /// FusionRoom.AddSig with join number - 49 -// /// -// /// The new attribute -// public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) -// { -// if (number < 50) throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); -// number -= 49; -// fr.AddSig(eSigType.String, number, name, mask); -// return fr.UserDefinedStringSigDetails[number]; -// } - -// /// -// /// Creates and returns a static asset -// /// -// /// the new asset -// public static FusionStaticAsset CreateStaticAsset(this FusionRoom fr, uint number, string name, string type, string instanceId) -// { -// fr.AddAsset(eAssetType.StaticAsset, number, name, type, instanceId); -// return fr.UserConfigurableAssetDetails[number].Asset as FusionStaticAsset; -// } -// } - -// //************************************************************************************************ -// /// -// /// Extensions to enhance Fusion room, asset and signal creation. -// /// -// public static class FusionStaticAssetExtensions -// { -// /// -// /// Tries to set a Fusion asset with the make and model of a device. -// /// If the provided Device is IMakeModel, will set the corresponding parameters on the fusion static asset. -// /// Otherwise, does nothing. -// /// -// public static void TrySetMakeModel(this FusionStaticAsset asset, Device device) -// { -// var mm = device as IMakeModel; -// if (mm != null) -// { -// asset.ParamMake.Value = mm.DeviceMake; -// asset.ParamModel.Value = mm.DeviceModel; -// } -// } - -// /// -// /// Tries to attach the AssetError input on a Fusion asset to a Device's -// /// CommunicationMonitor.StatusChange event. Does nothing if the device is not -// /// IStatusMonitor -// /// -// /// -// /// -// public static void TryLinkAssetErrorToCommunication(this FusionStaticAsset asset, Device device) -// { -// if (device is ICommunicationMonitor) -// { -// var monitor = (device as ICommunicationMonitor).CommunicationMonitor; -// monitor.StatusChange += (o, a) => -// { -// // Link connected and error inputs on asset -// asset.Connected.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; -// asset.AssetError.InputSig.StringValue = a.Status.ToString(); -// }; -// // set current value -// asset.Connected.InputSig.BoolValue = monitor.Status == MonitorStatus.IsOk; -// asset.AssetError.InputSig.StringValue = monitor.Status.ToString(); -// } -// } -// } - -//} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/MIcrophone/MicrophonePrivacyController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs similarity index 99% rename from essentials-framework/Essentials Devices Common/Essentials Devices Common/MIcrophone/MicrophonePrivacyController.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs index 177fffd1..a5b0b715 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/MIcrophone/MicrophonePrivacyController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs @@ -9,7 +9,7 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.CrestronIO; -namespace PepperDash.Essentials.Devices.Common.Microphones +namespace PepperDash.Essentials.Core.Privacy { /// /// Used for applications where one or more microphones with momentary contact closure outputs are used to diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/MIcrophone/MicrophonePrivacyControllerConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyControllerConfig.cs similarity index 89% rename from essentials-framework/Essentials Devices Common/Essentials Devices Common/MIcrophone/MicrophonePrivacyControllerConfig.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyControllerConfig.cs index 238fc7cf..1c172090 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/MIcrophone/MicrophonePrivacyControllerConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyControllerConfig.cs @@ -6,7 +6,7 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core.CrestronIO; -namespace PepperDash.Essentials.Devices.Common.Microphones +namespace PepperDash.Essentials.Core.Privacy { public class MicrophonePrivacyControllerConfig { diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 9eca4e25..73ee7517 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -123,6 +123,8 @@ + + @@ -132,12 +134,19 @@ + + + + + + + @@ -173,6 +182,10 @@ + + + + @@ -191,7 +204,6 @@ - @@ -238,7 +250,6 @@ - diff --git a/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs similarity index 96% rename from PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs index b12fd2e5..fcb04420 100644 --- a/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs @@ -1,526 +1,525 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using Crestron.SimplSharp; -using Crestron.SimplSharp.Scheduler; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Devices; -using PepperDash.Essentials.Devices.Common.Occupancy; - -namespace PepperDash.Essentials.Room.Behaviours -{ - /// - /// A device that when linked to a room can power the room on when enabled during scheduled hours. - /// - public class RoomOnToDefaultSourceWhenOccupied : ReconfigurableDevice - { - RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig; - - public bool FeatureEnabled { get; private set; } - - public DateTime FeatureEnabledTime { get; private set; } - - ScheduledEvent FeatureEnableEvent; - - const string FeatureEnableEventName = "EnableRoomOnToDefaultSourceWhenOccupied"; - - public DateTime FeatureDisabledTime { get; private set; } - - ScheduledEvent FeatureDisableEvent; - - const string FeatureDisableEventName = "DisableRoomOnToDefaultSourceWhenOccupied"; - - ScheduledEventGroup FeatureEventGroup; - - public EssentialsRoomBase Room { get; private set; } - - private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom; - - public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) : - base (config) - { - PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); - - FeatureEventGroup = new ScheduledEventGroup(this.Key); - - FeatureEventGroup.RetrieveAllEvents(); - - // Add to the global class for tracking - Scheduler.AddEventGroup(FeatureEventGroup); - - AddPostActivationAction(() => - { - // Subscribe to room event to know when RoomOccupancy is set and ready to be subscribed to - if (Room != null) - Room.RoomOccupancyIsSet += new EventHandler(RoomOccupancyIsSet); - - else - Debug.Console(1, this, "Room has no RoomOccupancy object set"); - - var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion"; - - FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Fusion.EssentialsHuddleSpaceFusionSystemControllerBase; - - if (FusionRoom == null) - Debug.Console(1, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey); - }); - } - - public override bool CustomActivate() - { - SetUpDevice(); - - return base.CustomActivate(); - } - - /// - /// Sets up device based on config values - /// - void SetUpDevice() - { - Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as EssentialsRoomBase; - - if (Room != null) - { - try - { - FeatureEnabledTime = DateTime.Parse(PropertiesConfig.OccupancyStartTime); - - if (FeatureEnabledTime != null) - { - Debug.Console(1, this, "Enabled Time: {0}", FeatureEnabledTime.ToString()); - } - else - Debug.Console(1, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyStartTime); - } - catch (Exception e) - { - Debug.Console(1, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e); - } - - try - { - FeatureDisabledTime = DateTime.Parse(PropertiesConfig.OccupancyEndTime); - - if (FeatureDisabledTime != null) - { - Debug.Console(1, this, "Disabled Time: {0}", FeatureDisabledTime.ToString()); - } - else - Debug.Console(1, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyEndTime); - } - catch (Exception e) - { - Debug.Console(1, this, "Unable to parse a DateTime config value \n Error: {1}", e); - } - - if (!PropertiesConfig.EnableRoomOnWhenOccupied) - FeatureEventGroup.ClearAllEvents(); - else - { - AddEnableEventToGroup(); - - AddDisableEventToGroup(); - - FeatureEventGroup.UserGroupCallBack += new ScheduledEventGroup.UserEventGroupCallBack(FeatureEventGroup_UserGroupCallBack); - - FeatureEventGroup.EnableAllEvents(); - } - - FeatureEnabled = CheckIfFeatureShouldBeEnabled(); - } - else - Debug.Console(1, this, "Unable to get room from Device Manager with key: {0}", PropertiesConfig.RoomKey); - } - - - protected override void CustomSetConfig(DeviceConfig config) - { - var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); - - if(newPropertiesConfig != null) - PropertiesConfig = newPropertiesConfig; - - ConfigWriter.UpdateDeviceConfig(config); - - SetUpDevice(); - } - - /// - /// Subscribe to feedback from RoomIsOccupiedFeedback on Room - /// - /// - /// - void RoomOccupancyIsSet(object sender, EventArgs e) - { - if (Room.RoomOccupancy != null) - { - Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; - Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += new EventHandler(RoomIsOccupiedFeedback_OutputChange); - Debug.Console(1, this, "Subscribed to RoomOccupancy status from: '{0}'", Room.Key); - } - } - - void FeatureEventGroup_UserGroupCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) - { - if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) - { - if (SchEvent.Name == FeatureEnableEventName) - { - if (PropertiesConfig.EnableRoomOnWhenOccupied) - FeatureEnabled = true; - - Debug.Console(1, this, "*****Feature Enabled by event.*****"); - } - else if (SchEvent.Name == FeatureDisableEventName) - { - FeatureEnabled = false; - - Debug.Console(1, this, "*****Feature Disabled by event.*****"); - } - } - } - - /// - /// Checks if the feature should be currently enabled. Used on startup if processor starts after start time but before end time - /// - /// - bool CheckIfFeatureShouldBeEnabled() - { - bool enabled = false; - - if(PropertiesConfig.EnableRoomOnWhenOccupied) - { - Debug.Console(1, this, "Current Time: {0} \n FeatureEnabledTime: {1} \n FeatureDisabledTime: {2}", DateTime.Now, FeatureEnabledTime, FeatureDisabledTime); - - if (DateTime.Now.TimeOfDay.CompareTo(FeatureEnabledTime.TimeOfDay) >= 0 && FeatureDisabledTime.TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0) - { - if (SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(DateTime.Now, CalculateDaysOfWeekRecurrence())) - { - enabled = true; - } - } - } - - if(enabled) - Debug.Console(1, this, "*****Feature Enabled*****"); - else - Debug.Console(1, this, "*****Feature Disabled*****"); - - return enabled; - } - - /// - /// Respond to Occupancy status event - /// - /// - /// - void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) - { - Debug.Console(1, this, "RoomIsOccupiedFeeback.OutputChange event fired. e.BoolValue: {0}", e.BoolValue); - if(e.BoolValue) - { - // Occupancy detected - - if (FeatureEnabled) - { - // Check room power state first - if (!Room.OnFeedback.BoolValue) - { - Debug.Console(1, this, "Powering Room on to default source"); - Room.RunDefaultPresentRoute(); - } - } - } - } - - void CreateEvent(ScheduledEvent schEvent, string name) - { - Debug.Console(1, this, "Adding Event: '{0}'", name); - // Create the event - if (schEvent == null) - schEvent = new ScheduledEvent(name, FeatureEventGroup); - - // Set up its initial properties - - if(!schEvent.Acknowledgeable) - schEvent.Acknowledgeable = true; - - if(!schEvent.Persistent) - schEvent.Persistent = true; - - schEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); - - // Set config driven properties - - if (schEvent.Name == FeatureEnableEventName) - { - schEvent.Description = "Enables the RoomOnToDefaultSourceWhenOccupiedFeature"; - - var eventRecurrennce = CalculateDaysOfWeekRecurrence(); - - var eventTime = new DateTime(); - - // Check to make sure the date for this event is in the future - if (DateTime.Now.CompareTo(FeatureEnabledTime) > 0) - eventTime = FeatureEnabledTime.AddDays(1); - else - eventTime = FeatureEnabledTime; - - Debug.Console(1, this, "eventTime (before recurrence check): {0}", eventTime); - - // Check day of week against recurrence days and move date ahead as necessary to avoid throwing an exception by trying to set the event - // start date on a day of the week that doesn't match teh recurrence values - while(!SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(eventTime, eventRecurrennce)) - { - eventTime = eventTime.AddDays(1); - Debug.Console(1, this, "eventTime does not fall on a recurrence weekday. eventTime: {0}", eventTime); - } - - schEvent.DateAndTime.SetAbsoluteEventTime(eventTime); - - Debug.Console(1, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); - - CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureEnabledTime, FeatureDisabledTime); - - schEvent.Recurrence.Weekly(eventRecurrennce); - - } - else if (schEvent.Name == FeatureDisableEventName) - { - schEvent.Description = "Disables the RoomOnToDefaultSourceWhenOccupiedFeature"; - - // Check to make sure the date for this event is in the future - if (DateTime.Now.CompareTo(FeatureDisabledTime) > 0) - schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime.AddDays(1)); - else - schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime); - - Debug.Console(1, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); - - CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureDisabledTime, FeatureEnabledTime); - - schEvent.Recurrence.Daily(); - } - } - - void CalculateAndSetAcknowledgeExpirationTimeout(ScheduledEvent schEvent, DateTime time1, DateTime time2) - { - Debug.Console(1, this, "time1.Hour = {0}", time1.Hour); - Debug.Console(1, this, "time2.Hour = {0}", time2.Hour); - Debug.Console(1, this, "time1.Minute = {0}", time1.Minute); - Debug.Console(1, this, "time2.Minute = {0}", time2.Minute); - - // Calculate the Acknowledge Expiration timer to be the time between the enable and dispable events, less one minute - var ackHours = time2.Hour - time1.Hour; - if(ackHours < 0) - ackHours = ackHours + 24; - var ackMinutes = time2.Minute - time1.Minute; - - Debug.Console(1, this, "ackHours = {0}, ackMinutes = {1}", ackHours, ackMinutes); - - var ackTotalMinutes = ((ackHours * 60) + ackMinutes) - 1; - - var ackExpHour = ackTotalMinutes / 60; - var ackExpMinutes = ackTotalMinutes % 60; - - Debug.Console(1, this, "Acknowledge Expiration Timeout: {0} hours, {1} minutes", ackExpHour, ackExpMinutes); - - schEvent.AcknowledgeExpirationTimeout.Hour = (ushort)(ackHours); - schEvent.AcknowledgeExpirationTimeout.Minute = (ushort)(ackExpMinutes); - } - - /// - /// Checks existing event to see if it matches the execution time - /// - /// - /// - bool CheckExistingEventTimeForMatch(ScheduledEvent existingEvent, DateTime newTime) - { - bool isMatch = true; - - // Check to see if hour and minute match - if (existingEvent.DateAndTime.Hour != newTime.Hour || existingEvent.DateAndTime.Minute != newTime.Minute) - return false; - - - return isMatch; - } - - /// - /// Checks existing event to see if it matches the recurrence days - /// - /// - /// - /// - bool CheckExistingEventRecurrenceForMatch(ScheduledEvent existingEvent, ScheduledEventCommon.eWeekDays eWeekdays) - { - bool isMatch = true; - - // Check to see if recurrence matches - if (eWeekdays != existingEvent.Recurrence.RecurrenceDays) - return false; - - return isMatch; - } - - /// - /// Adds the Enable event to the local event group and sets its properties based on config - /// - void AddEnableEventToGroup() - { - if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureEnableEventName)) - { - CreateEvent(FeatureEnableEvent, FeatureEnableEventName); - } - else - { - // Check if existing event has same time and recurrence as config values - - FeatureEnableEvent = FeatureEventGroup.ScheduledEvents[FeatureEnableEventName]; - Debug.Console(1, this, "Enable event already found in group"); - - // Check config times and days against DateAndTime of existing event. If different, delete existing event and create new event - if(!CheckExistingEventTimeForMatch(FeatureEnableEvent, FeatureEnabledTime) || !CheckExistingEventRecurrenceForMatch(FeatureEnableEvent, CalculateDaysOfWeekRecurrence())) - { - Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureEnableEvent.Name); - FeatureEventGroup.DeleteEvent(FeatureEnableEvent); - - FeatureEnableEvent = null; - - CreateEvent(FeatureEnableEvent, FeatureEnableEventName); - } - } - - } - - /// - /// Adds the Enable event to the local event group and sets its properties based on config - /// - void AddDisableEventToGroup() - { - if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureDisableEventName)) - { - CreateEvent(FeatureDisableEvent, FeatureDisableEventName); - } - else - { - FeatureDisableEvent = FeatureEventGroup.ScheduledEvents[FeatureDisableEventName]; - Debug.Console(1, this, "Disable event already found in group"); - - // Check config times against DateAndTime of existing event. If different, delete existing event and create new event - if(!CheckExistingEventTimeForMatch(FeatureDisableEvent, FeatureDisabledTime)) - { - Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureDisableEvent.Name); - - FeatureEventGroup.DeleteEvent(FeatureDisableEvent); - - FeatureDisableEvent = null; - - CreateEvent(FeatureDisableEvent, FeatureDisableEventName); - } - } - } - - - /// - /// Calculates the correct bitfield enum value for the event recurrence based on the config values - /// - /// - ScheduledEventCommon.eWeekDays CalculateDaysOfWeekRecurrence() - { - ScheduledEventCommon.eWeekDays value = new ScheduledEventCommon.eWeekDays(); - - if (PropertiesConfig.EnableSunday) - value = value | ScheduledEventCommon.eWeekDays.Sunday; - if (PropertiesConfig.EnableMonday) - value = value | ScheduledEventCommon.eWeekDays.Monday; - if (PropertiesConfig.EnableTuesday) - value = value | ScheduledEventCommon.eWeekDays.Tuesday; - if (PropertiesConfig.EnableWednesday) - value = value | ScheduledEventCommon.eWeekDays.Wednesday; - if (PropertiesConfig.EnableThursday) - value = value | ScheduledEventCommon.eWeekDays.Thursday; - if (PropertiesConfig.EnableFriday) - value = value | ScheduledEventCommon.eWeekDays.Friday; - if (PropertiesConfig.EnableSaturday) - value = value | ScheduledEventCommon.eWeekDays.Saturday; - - return value; - } - - /// - /// Callback for event that enables feature. Enables feature if config property is true - /// - /// - /// - void FeatureEnableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) - { - if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) - { - if(PropertiesConfig.EnableRoomOnWhenOccupied) - FeatureEnabled = true; - - Debug.Console(1, this, "RoomOnToDefaultSourceWhenOccupied Feature Enabled."); - } - } - - /// - /// Callback for event that enables feature. Disables feature - /// - /// - /// - void FeatureDisableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) - { - if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) - { - FeatureEnabled = false; - - Debug.Console(1, this, "RoomOnToDefaultSourceWhenOccupied Feature Disabled."); - } - } - } - - public class RoomOnToDefaultSourceWhenOccupiedConfig - { - [JsonProperty("roomKey")] - public string RoomKey { get; set; } - - [JsonProperty("enableRoomOnWhenOccupied")] - public bool EnableRoomOnWhenOccupied { get; set; } - - [JsonProperty("occupancyStartTime")] - public string OccupancyStartTime { get; set; } - - [JsonProperty("occupancyEndTime")] - public string OccupancyEndTime { get; set; } - - [JsonProperty("enableSunday")] - public bool EnableSunday { get; set; } - - [JsonProperty("enableMonday")] - public bool EnableMonday { get; set; } - - [JsonProperty("enableTuesday")] - public bool EnableTuesday { get; set; } - - [JsonProperty("enableWednesday")] - public bool EnableWednesday { get; set; } - - [JsonProperty("enableThursday")] - public bool EnableThursday { get; set; } - - [JsonProperty("enableFriday")] - public bool EnableFriday { get; set; } - - [JsonProperty("enableSaturday")] - public bool EnableSaturday { get; set; } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Crestron.SimplSharp; +using Crestron.SimplSharp.Scheduler; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Devices; + +namespace PepperDash.Essentials.Core +{ + /// + /// A device that when linked to a room can power the room on when enabled during scheduled hours. + /// + public class RoomOnToDefaultSourceWhenOccupied : ReconfigurableDevice + { + RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig; + + public bool FeatureEnabled { get; private set; } + + public DateTime FeatureEnabledTime { get; private set; } + + ScheduledEvent FeatureEnableEvent; + + const string FeatureEnableEventName = "EnableRoomOnToDefaultSourceWhenOccupied"; + + public DateTime FeatureDisabledTime { get; private set; } + + ScheduledEvent FeatureDisableEvent; + + const string FeatureDisableEventName = "DisableRoomOnToDefaultSourceWhenOccupied"; + + ScheduledEventGroup FeatureEventGroup; + + public EssentialsRoomBase Room { get; private set; } + + private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom; + + public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) : + base (config) + { + PropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); + + FeatureEventGroup = new ScheduledEventGroup(this.Key); + + FeatureEventGroup.RetrieveAllEvents(); + + // Add to the global class for tracking + Scheduler.AddEventGroup(FeatureEventGroup); + + AddPostActivationAction(() => + { + // Subscribe to room event to know when RoomOccupancy is set and ready to be subscribed to + if (Room != null) + Room.RoomOccupancyIsSet += new EventHandler(RoomOccupancyIsSet); + + else + Debug.Console(1, this, "Room has no RoomOccupancy object set"); + + var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion"; + + FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase; + + if (FusionRoom == null) + Debug.Console(1, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey); + }); + } + + public override bool CustomActivate() + { + SetUpDevice(); + + return base.CustomActivate(); + } + + /// + /// Sets up device based on config values + /// + void SetUpDevice() + { + Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as EssentialsRoomBase; + + if (Room != null) + { + try + { + FeatureEnabledTime = DateTime.Parse(PropertiesConfig.OccupancyStartTime); + + if (FeatureEnabledTime != null) + { + Debug.Console(1, this, "Enabled Time: {0}", FeatureEnabledTime.ToString()); + } + else + Debug.Console(1, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyStartTime); + } + catch (Exception e) + { + Debug.Console(1, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e); + } + + try + { + FeatureDisabledTime = DateTime.Parse(PropertiesConfig.OccupancyEndTime); + + if (FeatureDisabledTime != null) + { + Debug.Console(1, this, "Disabled Time: {0}", FeatureDisabledTime.ToString()); + } + else + Debug.Console(1, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyEndTime); + } + catch (Exception e) + { + Debug.Console(1, this, "Unable to parse a DateTime config value \n Error: {1}", e); + } + + if (!PropertiesConfig.EnableRoomOnWhenOccupied) + FeatureEventGroup.ClearAllEvents(); + else + { + AddEnableEventToGroup(); + + AddDisableEventToGroup(); + + FeatureEventGroup.UserGroupCallBack += new ScheduledEventGroup.UserEventGroupCallBack(FeatureEventGroup_UserGroupCallBack); + + FeatureEventGroup.EnableAllEvents(); + } + + FeatureEnabled = CheckIfFeatureShouldBeEnabled(); + } + else + Debug.Console(1, this, "Unable to get room from Device Manager with key: {0}", PropertiesConfig.RoomKey); + } + + + protected override void CustomSetConfig(DeviceConfig config) + { + var newPropertiesConfig = JsonConvert.DeserializeObject(config.Properties.ToString()); + + if(newPropertiesConfig != null) + PropertiesConfig = newPropertiesConfig; + + ConfigWriter.UpdateDeviceConfig(config); + + SetUpDevice(); + } + + /// + /// Subscribe to feedback from RoomIsOccupiedFeedback on Room + /// + /// + /// + void RoomOccupancyIsSet(object sender, EventArgs e) + { + if (Room.RoomOccupancy != null) + { + Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; + Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += new EventHandler(RoomIsOccupiedFeedback_OutputChange); + Debug.Console(1, this, "Subscribed to RoomOccupancy status from: '{0}'", Room.Key); + } + } + + void FeatureEventGroup_UserGroupCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) + { + if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) + { + if (SchEvent.Name == FeatureEnableEventName) + { + if (PropertiesConfig.EnableRoomOnWhenOccupied) + FeatureEnabled = true; + + Debug.Console(1, this, "*****Feature Enabled by event.*****"); + } + else if (SchEvent.Name == FeatureDisableEventName) + { + FeatureEnabled = false; + + Debug.Console(1, this, "*****Feature Disabled by event.*****"); + } + } + } + + /// + /// Checks if the feature should be currently enabled. Used on startup if processor starts after start time but before end time + /// + /// + bool CheckIfFeatureShouldBeEnabled() + { + bool enabled = false; + + if(PropertiesConfig.EnableRoomOnWhenOccupied) + { + Debug.Console(1, this, "Current Time: {0} \n FeatureEnabledTime: {1} \n FeatureDisabledTime: {2}", DateTime.Now, FeatureEnabledTime, FeatureDisabledTime); + + if (DateTime.Now.TimeOfDay.CompareTo(FeatureEnabledTime.TimeOfDay) >= 0 && FeatureDisabledTime.TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0) + { + if (SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(DateTime.Now, CalculateDaysOfWeekRecurrence())) + { + enabled = true; + } + } + } + + if(enabled) + Debug.Console(1, this, "*****Feature Enabled*****"); + else + Debug.Console(1, this, "*****Feature Disabled*****"); + + return enabled; + } + + /// + /// Respond to Occupancy status event + /// + /// + /// + void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + Debug.Console(1, this, "RoomIsOccupiedFeeback.OutputChange event fired. e.BoolValue: {0}", e.BoolValue); + if(e.BoolValue) + { + // Occupancy detected + + if (FeatureEnabled) + { + // Check room power state first + if (!Room.OnFeedback.BoolValue) + { + Debug.Console(1, this, "Powering Room on to default source"); + Room.RunDefaultPresentRoute(); + } + } + } + } + + void CreateEvent(ScheduledEvent schEvent, string name) + { + Debug.Console(1, this, "Adding Event: '{0}'", name); + // Create the event + if (schEvent == null) + schEvent = new ScheduledEvent(name, FeatureEventGroup); + + // Set up its initial properties + + if(!schEvent.Acknowledgeable) + schEvent.Acknowledgeable = true; + + if(!schEvent.Persistent) + schEvent.Persistent = true; + + schEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); + + // Set config driven properties + + if (schEvent.Name == FeatureEnableEventName) + { + schEvent.Description = "Enables the RoomOnToDefaultSourceWhenOccupiedFeature"; + + var eventRecurrennce = CalculateDaysOfWeekRecurrence(); + + var eventTime = new DateTime(); + + // Check to make sure the date for this event is in the future + if (DateTime.Now.CompareTo(FeatureEnabledTime) > 0) + eventTime = FeatureEnabledTime.AddDays(1); + else + eventTime = FeatureEnabledTime; + + Debug.Console(1, this, "eventTime (before recurrence check): {0}", eventTime); + + // Check day of week against recurrence days and move date ahead as necessary to avoid throwing an exception by trying to set the event + // start date on a day of the week that doesn't match teh recurrence values + while(!SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(eventTime, eventRecurrennce)) + { + eventTime = eventTime.AddDays(1); + Debug.Console(1, this, "eventTime does not fall on a recurrence weekday. eventTime: {0}", eventTime); + } + + schEvent.DateAndTime.SetAbsoluteEventTime(eventTime); + + Debug.Console(1, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); + + CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureEnabledTime, FeatureDisabledTime); + + schEvent.Recurrence.Weekly(eventRecurrennce); + + } + else if (schEvent.Name == FeatureDisableEventName) + { + schEvent.Description = "Disables the RoomOnToDefaultSourceWhenOccupiedFeature"; + + // Check to make sure the date for this event is in the future + if (DateTime.Now.CompareTo(FeatureDisabledTime) > 0) + schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime.AddDays(1)); + else + schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime); + + Debug.Console(1, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString()); + + CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureDisabledTime, FeatureEnabledTime); + + schEvent.Recurrence.Daily(); + } + } + + void CalculateAndSetAcknowledgeExpirationTimeout(ScheduledEvent schEvent, DateTime time1, DateTime time2) + { + Debug.Console(1, this, "time1.Hour = {0}", time1.Hour); + Debug.Console(1, this, "time2.Hour = {0}", time2.Hour); + Debug.Console(1, this, "time1.Minute = {0}", time1.Minute); + Debug.Console(1, this, "time2.Minute = {0}", time2.Minute); + + // Calculate the Acknowledge Expiration timer to be the time between the enable and dispable events, less one minute + var ackHours = time2.Hour - time1.Hour; + if(ackHours < 0) + ackHours = ackHours + 24; + var ackMinutes = time2.Minute - time1.Minute; + + Debug.Console(1, this, "ackHours = {0}, ackMinutes = {1}", ackHours, ackMinutes); + + var ackTotalMinutes = ((ackHours * 60) + ackMinutes) - 1; + + var ackExpHour = ackTotalMinutes / 60; + var ackExpMinutes = ackTotalMinutes % 60; + + Debug.Console(1, this, "Acknowledge Expiration Timeout: {0} hours, {1} minutes", ackExpHour, ackExpMinutes); + + schEvent.AcknowledgeExpirationTimeout.Hour = (ushort)(ackHours); + schEvent.AcknowledgeExpirationTimeout.Minute = (ushort)(ackExpMinutes); + } + + /// + /// Checks existing event to see if it matches the execution time + /// + /// + /// + bool CheckExistingEventTimeForMatch(ScheduledEvent existingEvent, DateTime newTime) + { + bool isMatch = true; + + // Check to see if hour and minute match + if (existingEvent.DateAndTime.Hour != newTime.Hour || existingEvent.DateAndTime.Minute != newTime.Minute) + return false; + + + return isMatch; + } + + /// + /// Checks existing event to see if it matches the recurrence days + /// + /// + /// + /// + bool CheckExistingEventRecurrenceForMatch(ScheduledEvent existingEvent, ScheduledEventCommon.eWeekDays eWeekdays) + { + bool isMatch = true; + + // Check to see if recurrence matches + if (eWeekdays != existingEvent.Recurrence.RecurrenceDays) + return false; + + return isMatch; + } + + /// + /// Adds the Enable event to the local event group and sets its properties based on config + /// + void AddEnableEventToGroup() + { + if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureEnableEventName)) + { + CreateEvent(FeatureEnableEvent, FeatureEnableEventName); + } + else + { + // Check if existing event has same time and recurrence as config values + + FeatureEnableEvent = FeatureEventGroup.ScheduledEvents[FeatureEnableEventName]; + Debug.Console(1, this, "Enable event already found in group"); + + // Check config times and days against DateAndTime of existing event. If different, delete existing event and create new event + if(!CheckExistingEventTimeForMatch(FeatureEnableEvent, FeatureEnabledTime) || !CheckExistingEventRecurrenceForMatch(FeatureEnableEvent, CalculateDaysOfWeekRecurrence())) + { + Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureEnableEvent.Name); + FeatureEventGroup.DeleteEvent(FeatureEnableEvent); + + FeatureEnableEvent = null; + + CreateEvent(FeatureEnableEvent, FeatureEnableEventName); + } + } + + } + + /// + /// Adds the Enable event to the local event group and sets its properties based on config + /// + void AddDisableEventToGroup() + { + if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureDisableEventName)) + { + CreateEvent(FeatureDisableEvent, FeatureDisableEventName); + } + else + { + FeatureDisableEvent = FeatureEventGroup.ScheduledEvents[FeatureDisableEventName]; + Debug.Console(1, this, "Disable event already found in group"); + + // Check config times against DateAndTime of existing event. If different, delete existing event and create new event + if(!CheckExistingEventTimeForMatch(FeatureDisableEvent, FeatureDisabledTime)) + { + Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureDisableEvent.Name); + + FeatureEventGroup.DeleteEvent(FeatureDisableEvent); + + FeatureDisableEvent = null; + + CreateEvent(FeatureDisableEvent, FeatureDisableEventName); + } + } + } + + + /// + /// Calculates the correct bitfield enum value for the event recurrence based on the config values + /// + /// + ScheduledEventCommon.eWeekDays CalculateDaysOfWeekRecurrence() + { + ScheduledEventCommon.eWeekDays value = new ScheduledEventCommon.eWeekDays(); + + if (PropertiesConfig.EnableSunday) + value = value | ScheduledEventCommon.eWeekDays.Sunday; + if (PropertiesConfig.EnableMonday) + value = value | ScheduledEventCommon.eWeekDays.Monday; + if (PropertiesConfig.EnableTuesday) + value = value | ScheduledEventCommon.eWeekDays.Tuesday; + if (PropertiesConfig.EnableWednesday) + value = value | ScheduledEventCommon.eWeekDays.Wednesday; + if (PropertiesConfig.EnableThursday) + value = value | ScheduledEventCommon.eWeekDays.Thursday; + if (PropertiesConfig.EnableFriday) + value = value | ScheduledEventCommon.eWeekDays.Friday; + if (PropertiesConfig.EnableSaturday) + value = value | ScheduledEventCommon.eWeekDays.Saturday; + + return value; + } + + /// + /// Callback for event that enables feature. Enables feature if config property is true + /// + /// + /// + void FeatureEnableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) + { + if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) + { + if(PropertiesConfig.EnableRoomOnWhenOccupied) + FeatureEnabled = true; + + Debug.Console(1, this, "RoomOnToDefaultSourceWhenOccupied Feature Enabled."); + } + } + + /// + /// Callback for event that enables feature. Disables feature + /// + /// + /// + void FeatureDisableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type) + { + if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration) + { + FeatureEnabled = false; + + Debug.Console(1, this, "RoomOnToDefaultSourceWhenOccupied Feature Disabled."); + } + } + } + + public class RoomOnToDefaultSourceWhenOccupiedConfig + { + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + [JsonProperty("enableRoomOnWhenOccupied")] + public bool EnableRoomOnWhenOccupied { get; set; } + + [JsonProperty("occupancyStartTime")] + public string OccupancyStartTime { get; set; } + + [JsonProperty("occupancyEndTime")] + public string OccupancyEndTime { get; set; } + + [JsonProperty("enableSunday")] + public bool EnableSunday { get; set; } + + [JsonProperty("enableMonday")] + public bool EnableMonday { get; set; } + + [JsonProperty("enableTuesday")] + public bool EnableTuesday { get; set; } + + [JsonProperty("enableWednesday")] + public bool EnableWednesday { get; set; } + + [JsonProperty("enableThursday")] + public bool EnableThursday { get; set; } + + [JsonProperty("enableFriday")] + public bool EnableFriday { get; set; } + + [JsonProperty("enableSaturday")] + public bool EnableSaturday { get; set; } + } } \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs similarity index 93% rename from PepperDashEssentials/Room/Types/EssentialsRoomBase.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs index fc177b51..e8193837 100644 --- a/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs @@ -1,297 +1,311 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharp.Scheduler; - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Devices; -using PepperDash.Essentials.Devices.Common.Occupancy; - -namespace PepperDash.Essentials -{ - /// - /// - /// - 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; } - - /// - /// 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 PepperDash.Essentials.Room.EssentialsRoomEmergencyBase Emergency { get; set; } - - public PepperDash.Essentials.Devices.Common.Microphones.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; } - - - public 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 += new EventHandler(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, "Shutting Down due to vacancy."); - break; - } - default: - break; - } - } - - /// - /// - /// - /// - public void StartShutdown(eShutdownType type) - { - // Check for shutdowns running. Manual should override other shutdowns - - if (type == eShutdownType.Manual) - ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds; - else if (type == eShutdownType.Vacancy) - ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds; - ShutdownType = type; - ShutdownPromptTimer.Start(); - - Debug.Console(0, this, "ShutdwonPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount); - } - - public void StartRoomVacancyTimer(eVacancyMode mode) - { - if (mode == eVacancyMode.None) - RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds; - else if (mode == eVacancyMode.InInitialVacancy) - RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds; - VacancyMode = mode; - RoomVacancyShutdownTimer.Start(); - - Debug.Console(0, this, "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) - { - if (statusProvider == null) - { - Debug.Console(0, this, "ERROR: Occupancy sensor device is null"); - return; - } - - // If status provider is fusion, set flag to remote - if (statusProvider is PepperDash.Essentials.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase) - OccupancyStatusProviderIsRemote = true; - - if(timeoutMinutes > 0) - RoomVacancyShutdownSeconds = timeoutMinutes * 60; - - Debug.Console(1, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); - - RoomOccupancy = statusProvider; - - OnRoomOccupancyIsSet(); - - RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; - RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; - - Debug.Console(0, this, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key); - } - - 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, "Notice: Vacancy Detected"); - // Trigger the timer when the room is vacant - StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); - } - else - { - Debug.Console(1, this, "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 - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharp.Scheduler; + +using PepperDash.Core; +using PepperDash.Essentials.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 Core.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; } + + + public 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 += new EventHandler(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, "Shutting Down due to vacancy."); + break; + } + default: + break; + } + } + + /// + /// + /// + /// + public void StartShutdown(eShutdownType type) + { + // Check for shutdowns running. Manual should override other shutdowns + + if (type == eShutdownType.Manual) + ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds; + else if (type == eShutdownType.Vacancy) + ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds; + ShutdownType = type; + ShutdownPromptTimer.Start(); + + Debug.Console(0, this, "ShutdwonPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount); + } + + public void StartRoomVacancyTimer(eVacancyMode mode) + { + if (mode == eVacancyMode.None) + RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds; + else if (mode == eVacancyMode.InInitialVacancy) + RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds; + VacancyMode = mode; + RoomVacancyShutdownTimer.Start(); + + Debug.Console(0, this, "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) + { + if (statusProvider == null) + { + Debug.Console(0, this, "ERROR: Occupancy sensor device is null"); + return; + } + + // If status provider is fusion, set flag to remote + if (statusProvider is Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase) + OccupancyStatusProviderIsRemote = true; + + if(timeoutMinutes > 0) + RoomVacancyShutdownSeconds = timeoutMinutes * 60; + + Debug.Console(1, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds); + + RoomOccupancy = statusProvider; + + OnRoomOccupancyIsSet(); + + RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange; + RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; + + Debug.Console(0, this, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key); + } + + 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, "Notice: Vacancy Detected"); + // Trigger the timer when the room is vacant + StartRoomVacancyTimer(eVacancyMode.InInitialVacancy); + } + else + { + Debug.Console(1, this, "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; } + + public EssentialsRoomEmergencyBase(string key) + { + Key = key; + } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs new file mode 100644 index 00000000..8ce3a45d --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + + /// + /// For rooms with routing + /// + public interface IRunRouteAction + { + void RunRouteAction(string routeKey); + + void RunRouteAction(string routeKey, Action successCallback); + } + + /// + /// For rooms that default presentation only routing + /// + public interface IRunDefaultPresentRoute + { + bool RunDefaultPresentRoute(); + } + + /// + /// For rooms that have default presentation and calling routes + /// + public interface IRunDefaultCallRoute : IRunDefaultPresentRoute + { + bool RunDefaultCallRoute(); + } + +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/MOVED RoomEventArgs.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/MOVED RoomEventArgs.cs deleted file mode 100644 index bca9bb62..00000000 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/MOVED RoomEventArgs.cs +++ /dev/null @@ -1,41 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text; -//using Crestron.SimplSharp; - -//namespace PepperDash.Essentials.Core -//{ -// public class EssentialsRoomSourceChangeEventArgs : EventArgs -// { -// public EssentialsRoom Room { get; private set; } -// public IPresentationSource OldSource { get; private set; } -// public IPresentationSource NewSource { get; private set; } - -// public EssentialsRoomSourceChangeEventArgs(EssentialsRoom room, -// IPresentationSource oldSource, IPresentationSource newSource) -// { -// Room = room; -// OldSource = oldSource; -// NewSource = newSource; -// } -// } - - - -// public class EssentialsRoomAudioDeviceChangeEventArgs : EventArgs -// { -// public EssentialsRoom Room { get; private set; } -// public IBasicVolumeControls OldDevice { get; private set; } -// public IBasicVolumeControls NewDevice { get; private set; } - -// public EssentialsRoomAudioDeviceChangeEventArgs(EssentialsRoom room, -// IBasicVolumeControls oldDevice, IBasicVolumeControls newDevice) -// { -// Room = room; -// OldDevice = oldDevice; -// NewDevice = newDevice; -// } -// } - -//} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/iOccupancyStatusProvider.cs similarity index 82% rename from essentials-framework/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs rename to essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/iOccupancyStatusProvider.cs index 02054535..f46f10b1 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/iOccupancyStatusProvider.cs @@ -6,7 +6,7 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; -namespace PepperDash.Essentials.Devices.Common.Occupancy +namespace PepperDash.Essentials.Core { public interface IOccupancyStatusProvider { diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingInterfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingInterfaces.cs index 76745f22..af8612d2 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingInterfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Routing/RoutingInterfaces.cs @@ -11,9 +11,26 @@ using PepperDash.Core; namespace PepperDash.Essentials.Core { + + /// + /// The handler type for a Room's SourceInfoChange + /// + public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type); + + //******************************************************************************************* // Interfaces + /// + /// For rooms with a single presentation source, change event + /// + public interface IHasCurrentSourceInfoChange + { + string CurrentSourceInfoKey { get; } + SourceListItem CurrentSourceInfo { get; } + event SourceInfoChangeHandler CurrentSourceChange; + } + /// /// Defines a class that has a collection of RoutingInputPorts @@ -43,7 +60,7 @@ namespace PepperDash.Essentials.Core /// /// Endpoint device like a display, that selects inputs /// - public interface IRoutingSinkWithSwitching : IRoutingSinkNoSwitching + public interface IRoutingSinkWithSwitching : IRoutingSinkNoSwitching, IHasCurrentSourceInfoChange { //void ClearRoute(); void ExecuteSwitch(object inputSelector); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index ec276366..bed83feb 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -150,13 +150,8 @@ - - - - -