From c3c79489902139e5670f99713f93c9425fc6fbe8 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 3 Oct 2017 23:34:23 -0600 Subject: [PATCH 1/2] Started working on Room Occupancy --- .../PepperDash_Essentials_Core.csproj | 1 + .../PepperDashEssentialsBase/Room/Room.cs | 2 +- .../Room/iHasOccupancyAwareness.cs | 24 +++++ .../Codec/iHasScheduleAwareness.cs | 99 ++++++++++++++++++- .../Essentials Devices Common.csproj | 2 + .../Occupancy/GlsOirCsmExBatt.cs | 16 +++ .../Occupancy/iOccupancyStatusProvider.cs | 13 +++ .../CiscoCodec/BookingsDataClasses.cs | 2 - .../VideoCodec/CiscoCodec/CiscoCodec.cs | 5 + 9 files changed, 157 insertions(+), 7 deletions(-) create mode 100644 Essentials Core/PepperDashEssentialsBase/Room/iHasOccupancyAwareness.cs create mode 100644 Essentials Devices Common/Essentials Devices Common/Occupancy/GlsOirCsmExBatt.cs create mode 100644 Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs diff --git a/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index ab03ff44..0e115543 100644 --- a/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -142,6 +142,7 @@ + diff --git a/Essentials Core/PepperDashEssentialsBase/Room/Room.cs b/Essentials Core/PepperDashEssentialsBase/Room/Room.cs index 20947d95..2f1594ed 100644 --- a/Essentials Core/PepperDashEssentialsBase/Room/Room.cs +++ b/Essentials Core/PepperDashEssentialsBase/Room/Room.cs @@ -16,7 +16,7 @@ namespace PepperDash.Essentials.Core { public abstract BoolFeedback RoomIsOnFeedback { get; protected set; } public abstract BoolFeedback IsCoolingDownFeedback { get; protected set; } - public abstract BoolFeedback IsWarmingUpFeedback { get; protected set; } + public abstract BoolFeedback IsWarmingUpFeedback { get; protected set; } // In concrete classes, these should be computed from the relevant devices public virtual uint CooldownTime { get { return 10000; } } diff --git a/Essentials Core/PepperDashEssentialsBase/Room/iHasOccupancyAwareness.cs b/Essentials Core/PepperDashEssentialsBase/Room/iHasOccupancyAwareness.cs new file mode 100644 index 00000000..d6165d6c --- /dev/null +++ b/Essentials Core/PepperDashEssentialsBase/Room/iHasOccupancyAwareness.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.GeneralIO; + +namespace PepperDash.Essentials.Core.Room +{ + public interface IHasOccupancyAwareness + { + OccupancyStatus RoomOccupancy { get; } + + } + + public class OccupancyStatus + { + BoolFeedback RoomIsOccupied { get; } + + + } + + +} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs b/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs index a641328c..49c5c645 100644 --- a/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs +++ b/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs @@ -6,6 +6,15 @@ using Crestron.SimplSharp; namespace PepperDash.Essentials.Devices.Common.Codec { + public enum eMeetingEventChangeType + { + Unkown = 0, + MeetingStartWarning, + MeetingStart, + MeetingEndWarning, + MeetingEnd + } + public interface IHasScheduleAwareness { CodecScheduleAwareness CodecSchedule { get; } @@ -13,11 +22,70 @@ namespace PepperDash.Essentials.Devices.Common.Codec public class CodecScheduleAwareness { - public List Meetings { get; set; } + List _Meetings; + + public event EventHandler MeetingEventChange; + + public event EventHandler MeetingsListHasChanged; + + public List Meetings + { + get + { + return _Meetings; + } + set + { + _Meetings = value; + + var handler = MeetingsListHasChanged; + if (handler != null) + { + handler(this, new EventArgs()); + } + } + } + + private CTimer ScheduleChecker; public CodecScheduleAwareness() { Meetings = new List(); + + ScheduleChecker = new CTimer(CheckSchedule, null, 1000, 1000); + } + + private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting) + { + var handler = MeetingEventChange; + if (handler != null) + { + handler(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting }); + } + } + + private void CheckSchedule(object o) + { + // Iterate the meeting list and check if any meeting need to do anythingk + + foreach (Meeting m in Meetings) + { + eMeetingEventChangeType changeType = eMeetingEventChangeType.Unkown; + + if (m.TimeToMeetingStart.TotalMinutes == m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to start + changeType = eMeetingEventChangeType.MeetingStartWarning; + else if (m.TimeToMeetingStart.TotalMinutes == 0) // Meeting Start + changeType = eMeetingEventChangeType.MeetingStart; + else if (m.TimeToMeetingEnd.TotalMinutes == m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to end + changeType = eMeetingEventChangeType.MeetingEndWarning; + else if (m.TimeToMeetingEnd.TotalMinutes == 0) // Meeting has ended + changeType = eMeetingEventChangeType.MeetingEnd; + + if (changeType != eMeetingEventChangeType.Unkown) + OnMeetingChange(changeType, m); + } + + } } @@ -26,10 +94,26 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public class Meeting { + public TimeSpan MeetingWarningMinutes = TimeSpan.FromMinutes(5); + public string Id { get; set; } public string Organizer { get; set; } public string Title { get; set; } public string Agenda { get; set; } + public TimeSpan TimeToMeetingStart + { + get + { + return StartTime - DateTime.Now; + } + } + public TimeSpan TimeToMeetingEnd + { + get + { + return EndTime - DateTime.Now; + } + } public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } public TimeSpan Duration @@ -44,11 +128,18 @@ namespace PepperDash.Essentials.Devices.Common.Codec { get { - return StartTime.AddMinutes(-5) <= DateTime.Now - && DateTime.Now <= EndTime.AddMinutes(-5); + return StartTime.AddMinutes(-5) <= DateTime.Now + && DateTime.Now <= EndTime.AddMinutes(-5); } } public string ConferenceNumberToDial { get; set; } public string ConferencePassword { get; set; } } -} \ No newline at end of file + + public class MeetingEventArgs : EventArgs + { + public eMeetingEventChangeType ChangeType { get; set; } + public Meeting Meeting { get; set; } + } + +} diff --git a/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index 3dcbcc6c..d0a854b3 100644 --- a/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -130,6 +130,8 @@ + + diff --git a/Essentials Devices Common/Essentials Devices Common/Occupancy/GlsOirCsmExBatt.cs b/Essentials Devices Common/Essentials Devices Common/Occupancy/GlsOirCsmExBatt.cs new file mode 100644 index 00000000..c2aa7ed9 --- /dev/null +++ b/Essentials Devices Common/Essentials Devices Common/Occupancy/GlsOirCsmExBatt.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.GeneralIO; + +namespace PepperDash.Essentials.Devices.Common.Occupancy +{ + public class EssentialsGlsOirCsmExBatt : GlsOccupancySensorBase, IOccupancyStatusProvider + { + public GlsOirCsmExBatt OccSensor { get; set; } + + + } +} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs b/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs new file mode 100644 index 00000000..8f019fd6 --- /dev/null +++ b/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Devices.Common.Occupancy +{ + public interface IOccupancyStatusProvider + { + // Need to define a common interface that can be applied to Crestron Occ sensor as well as 3rd party devices. How to accomplish? + } +} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/BookingsDataClasses.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/BookingsDataClasses.cs index 19c54028..2905f285 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/BookingsDataClasses.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/BookingsDataClasses.cs @@ -288,8 +288,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec meetings.OrderBy(m => m.StartTime); - - return meetings; } } diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs index b702a5f6..16bf5f38 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs @@ -6,6 +6,7 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.Net.Https; using Crestron.SimplSharp.CrestronXml; using Crestron.SimplSharp.CrestronXml.Serialization; +//using Crestron.SimplSharpPro; using Newtonsoft.Json; using Cisco_One_Button_To_Push; using Cisco_SX80_Corporate_Phone_Book; @@ -34,6 +35,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public BoolFeedback RoomIsOccupiedFeedback { get; private set; } + //public BoolOutputSig OccupancyDetectedFeedback { get; private set; } + public IntFeedback PeopleCountFeedback { get; private set; } public BoolFeedback SpeakerTrackIsOnFeedback { get; private set; } @@ -628,6 +631,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco JsonConvert.PopulateObject(response, codecBookings); CodecSchedule.Meetings = CiscoCodecBookings.GetGenericMeetingsFromBookingResult(codecBookings.CommandResponse.BookingsListResult.Booking); + + } } From 3c3fca7766a8dd1f15c07524f395dc142260eada Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 5 Oct 2017 16:04:45 -0600 Subject: [PATCH 2/2] Updates to Room Occupancy and added additional interfaces for codec layouts, selfview --- .../PepperDash_Essentials_Core.csproj | 1 - .../PepperDashEssentialsBase/Room/Room.cs | 108 ++++----- .../Room/iHasOccupancyAwareness.cs | 24 -- .../Codec/iHasScheduleAwareness.cs | 4 +- .../Essentials Devices Common.csproj | 5 +- ...entialsGlsOccupancySensorBaseController.cs | 29 +++ .../EssentialsOccupancyAggregator.cs | 45 ++++ .../Occupancy/GlsOirCsmExBatt.cs | 16 -- .../Occupancy/iOccupancyStatusProvider.cs | 4 +- .../VideoCodec/CiscoCodec/CiscoCodec.cs | 210 ++++++++++++++++-- .../VideoCodec/CiscoCodec/xStatus.cs | 72 +++++- .../VideoCodec/Interfaces/IHasCodecLayouts.cs | 20 ++ .../Interfaces/IHasCodecSelfview.cs | 24 ++ ...tialsHuddleSpaceFusionSystemController.cs} | 0 .../PepperDashEssentials.csproj | 2 +- .../Room/Types/EssentialsHuddleSpaceRoom.cs | 7 +- .../Room/Types/EssentialsHuddleVtc1Room.cs | 7 +- .../Room/Types/EssentialsPresentationRoom.cs | 8 +- .../Room/Types/EssentialsRoomBase.cs | 50 ++++- 19 files changed, 498 insertions(+), 138 deletions(-) delete mode 100644 Essentials Core/PepperDashEssentialsBase/Room/iHasOccupancyAwareness.cs create mode 100644 Essentials Devices Common/Essentials Devices Common/Occupancy/EssentialsGlsOccupancySensorBaseController.cs create mode 100644 Essentials Devices Common/Essentials Devices Common/Occupancy/EssentialsOccupancyAggregator.cs delete mode 100644 Essentials Devices Common/Essentials Devices Common/Occupancy/GlsOirCsmExBatt.cs create mode 100644 Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecLayouts.cs create mode 100644 Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecSelfview.cs rename Essentials/PepperDashEssentials/OTHER/Fusion/{FusionSystemController.cs => EssentialsHuddleSpaceFusionSystemController.cs} (100%) diff --git a/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 0e115543..ab03ff44 100644 --- a/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -142,7 +142,6 @@ - diff --git a/Essentials Core/PepperDashEssentialsBase/Room/Room.cs b/Essentials Core/PepperDashEssentialsBase/Room/Room.cs index 2f1594ed..97bc8b32 100644 --- a/Essentials Core/PepperDashEssentialsBase/Room/Room.cs +++ b/Essentials Core/PepperDashEssentialsBase/Room/Room.cs @@ -1,56 +1,56 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; - -using PepperDash.Core; - - -namespace PepperDash.Essentials.Core -{ - //*************************************************************************************************** - - public abstract class Room : Device, IHasFeedback - { - public abstract BoolFeedback RoomIsOnFeedback { get; protected set; } - public abstract BoolFeedback IsCoolingDownFeedback { get; protected set; } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; + +using PepperDash.Core; + + +namespace PepperDash.Essentials.Core +{ + //*************************************************************************************************** + + public abstract class Room : Device, IHasFeedback + { + public abstract BoolFeedback RoomIsOnFeedback { get; protected set; } + public abstract BoolFeedback IsCoolingDownFeedback { get; protected set; } public abstract BoolFeedback IsWarmingUpFeedback { get; protected set; } - - // In concrete classes, these should be computed from the relevant devices - public virtual uint CooldownTime { get { return 10000; } } - public virtual uint WarmupTime { get { return 5000; } } - - public string Description { get; set; } - public string HelpMessage { get; set; } - - public Room(string key, string name) - : base(key, name) - { - Description = ""; - HelpMessage = ""; - } - - public virtual void RoomOn() { } - - public virtual void RoomOff() { } - - #region IDeviceWithOutputs Members - - public virtual List Feedbacks - { - get - { - return new List - { - RoomIsOnFeedback, - IsCoolingDownFeedback, - IsWarmingUpFeedback - }; - } - } - - #endregion - } + + // In concrete classes, these should be computed from the relevant devices + public virtual uint CooldownTime { get { return 10000; } } + public virtual uint WarmupTime { get { return 5000; } } + + public string Description { get; set; } + public string HelpMessage { get; set; } + + public Room(string key, string name) + : base(key, name) + { + Description = ""; + HelpMessage = ""; + } + + public virtual void RoomOn() { } + + public virtual void RoomOff() { } + + #region IDeviceWithOutputs Members + + public virtual List Feedbacks + { + get + { + return new List + { + RoomIsOnFeedback, + IsCoolingDownFeedback, + IsWarmingUpFeedback + }; + } + } + + #endregion + } } \ No newline at end of file diff --git a/Essentials Core/PepperDashEssentialsBase/Room/iHasOccupancyAwareness.cs b/Essentials Core/PepperDashEssentialsBase/Room/iHasOccupancyAwareness.cs deleted file mode 100644 index d6165d6c..00000000 --- a/Essentials Core/PepperDashEssentialsBase/Room/iHasOccupancyAwareness.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.GeneralIO; - -namespace PepperDash.Essentials.Core.Room -{ - public interface IHasOccupancyAwareness - { - OccupancyStatus RoomOccupancy { get; } - - } - - public class OccupancyStatus - { - BoolFeedback RoomIsOccupied { get; } - - - } - - -} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs b/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs index 49c5c645..0ca05ee0 100644 --- a/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs +++ b/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs @@ -72,11 +72,11 @@ namespace PepperDash.Essentials.Devices.Common.Codec { eMeetingEventChangeType changeType = eMeetingEventChangeType.Unkown; - if (m.TimeToMeetingStart.TotalMinutes == m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to start + if (m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to start changeType = eMeetingEventChangeType.MeetingStartWarning; else if (m.TimeToMeetingStart.TotalMinutes == 0) // Meeting Start changeType = eMeetingEventChangeType.MeetingStart; - else if (m.TimeToMeetingEnd.TotalMinutes == m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to end + else if (m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to end changeType = eMeetingEventChangeType.MeetingEndWarning; else if (m.TimeToMeetingEnd.TotalMinutes == 0) // Meeting has ended changeType = eMeetingEventChangeType.MeetingEnd; diff --git a/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index d0a854b3..ec42d9b5 100644 --- a/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -130,7 +130,8 @@ - + + @@ -150,6 +151,8 @@ + + diff --git a/Essentials Devices Common/Essentials Devices Common/Occupancy/EssentialsGlsOccupancySensorBaseController.cs b/Essentials Devices Common/Essentials Devices Common/Occupancy/EssentialsGlsOccupancySensorBaseController.cs new file mode 100644 index 00000000..e9c73ace --- /dev/null +++ b/Essentials Devices Common/Essentials Devices Common/Occupancy/EssentialsGlsOccupancySensorBaseController.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.GeneralIO; + +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.Occupancy +{ + public class EssentialsGlsOccupancySensorBaseController : CrestronGenericBaseDevice, IOccupancyStatusProvider + { + public GlsOccupancySensorBase OccSensor { get; private set; } + + public BoolFeedback RoomIsOccupiedFeedback { get; private set; } + + public EssentialsGlsOccupancySensorBaseController(string key, string name, GlsOccupancySensorBase sensor, GlsOccupancySensorConfigurationProperties props) + : base(key, name, sensor) + { + + } + } + + public class GlsOccupancySensorConfigurationProperties + { + + } +} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Occupancy/EssentialsOccupancyAggregator.cs b/Essentials Devices Common/Essentials Devices Common/Occupancy/EssentialsOccupancyAggregator.cs new file mode 100644 index 00000000..8a7d2ca2 --- /dev/null +++ b/Essentials Devices Common/Essentials Devices Common/Occupancy/EssentialsOccupancyAggregator.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.Occupancy +{ + /// + /// Aggregates the RoomIsOccupied feedbacks of one or more IOccupancyStatusProvider objects + /// + public class EssentialsOccupancyAggregator : Device, IOccupancyStatusProvider + { + /// + /// Aggregated feedback of all linked IOccupancyStatusProvider devices + /// + public BoolFeedback RoomIsOccupiedFeedback + { + get + { + return AggregatedOccupancyStatus.Output; + } + } + + private BoolFeedbackOr AggregatedOccupancyStatus; + + public EssentialsOccupancyAggregator(string key, string name) + : base(key, name) + { + AggregatedOccupancyStatus = new BoolFeedbackOr(); + } + + /// + /// Adds an IOccupancyStatusProvider device + /// + /// + public void AddOccupancyStatusProvider(IOccupancyStatusProvider statusProvider) + { + AggregatedOccupancyStatus.AddOutputIn(statusProvider.RoomIsOccupiedFeedback); + } + } +} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Occupancy/GlsOirCsmExBatt.cs b/Essentials Devices Common/Essentials Devices Common/Occupancy/GlsOirCsmExBatt.cs deleted file mode 100644 index c2aa7ed9..00000000 --- a/Essentials Devices Common/Essentials Devices Common/Occupancy/GlsOirCsmExBatt.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.GeneralIO; - -namespace PepperDash.Essentials.Devices.Common.Occupancy -{ - public class EssentialsGlsOirCsmExBatt : GlsOccupancySensorBase, IOccupancyStatusProvider - { - public GlsOirCsmExBatt OccSensor { get; set; } - - - } -} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs b/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs index 8f019fd6..37ca74d6 100644 --- a/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs +++ b/Essentials Devices Common/Essentials Devices Common/Occupancy/iOccupancyStatusProvider.cs @@ -4,10 +4,12 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using PepperDash.Essentials.Core; + namespace PepperDash.Essentials.Devices.Common.Occupancy { public interface IOccupancyStatusProvider { - // Need to define a common interface that can be applied to Crestron Occ sensor as well as 3rd party devices. How to accomplish? + BoolFeedback RoomIsOccupiedFeedback { get; } } } \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs index 16bf5f38..bd4c5505 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoCodec.cs @@ -15,13 +15,14 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.Occupancy; using PepperDash.Essentials.Devices.Common.VideoCodec; namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco { enum eCommandType { SessionStart, SessionEnd, Command, GetStatus, GetConfiguration }; - public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory, IHasScheduleAwareness + public class CiscoCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory, IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayouts, IHasCodecSelfview { public event EventHandler DirectoryResultReturned; @@ -35,22 +36,51 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public BoolFeedback RoomIsOccupiedFeedback { get; private set; } - //public BoolOutputSig OccupancyDetectedFeedback { get; private set; } - public IntFeedback PeopleCountFeedback { get; private set; } public BoolFeedback SpeakerTrackIsOnFeedback { get; private set; } - //private CiscoOneButtonToPush CodecObtp; + public BoolFeedback SelfviewIsOnFeedback { get; private set; } - //private Corporate_Phone_Book PhoneBook; + public StringFeedback SelfviewPipPositionFeedback { get; private set; } + public StringFeedback LocalLayoutFeedback { get; private set; } + + private CodecCommandWithLabel CurrentSelfviewPipPosition; + + private CodecCommandWithLabel CurrentLocalLayout; + + /// + /// List the available positions for the selfview PIP window + /// + public List SelfviewPipPositions = new List() + { + new CodecCommandWithLabel("CenterLeft", "Center Left"), + new CodecCommandWithLabel("CenterRight", "Center Right"), + new CodecCommandWithLabel("LowerLeft", "Lower Left"), + new CodecCommandWithLabel("LowerRight", "Lower Right"), + new CodecCommandWithLabel("UpperCenter", "Upper Center"), + new CodecCommandWithLabel("UpperLeft", "Upper Left"), + new CodecCommandWithLabel("UpperRight", "Upper Right"), + }; + + /// + /// Lists the available options for local layout + /// + public List LocalLayouts = new List() + { + new CodecCommandWithLabel("auto", "Auto"), + //new CiscoCodecLocalLayout("custom", "Custom"), // Left out for now + new CodecCommandWithLabel("equal","Equal"), + new CodecCommandWithLabel("overlay","Overlay"), + new CodecCommandWithLabel("prominent","Prominent"), + new CodecCommandWithLabel("single","Single") + }; + private CiscoCodecConfiguration.RootObject CodecConfiguration; private CiscoCodecStatus.RootObject CodecStatus; - //private CiscoCodecPhonebook.RootObject CodecPhonebook; - public CodecCallHistory CallHistory { get; private set; } public CodecCallFavorites CallFavorites { get; private set; } @@ -130,22 +160,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } } - //protected override Func ActiveCallCountFeedbackFunc - //{ - // get { return () => ActiveCalls.Count; } - //} + protected Func SelfViewIsOnFeedbackFunc + { + get + { + return () => CodecStatus.Status.Video.Selfview.Mode.BoolValue; + } + } - //private HttpsClient Client; + protected Func SelfviewPipPositionFeedbackFunc + { + get + { + return () => CurrentSelfviewPipPosition.Label; + } + } - //private HttpApiServer Server; - - //private int ServerPort; - - //private string CodecUrl; - - //private string HttpSessionId; - - //private string FeedbackRegistrationExpression; + protected Func LocalLayoutFeedbackFunc + { + get + { + return () => CurrentLocalLayout.Label; + } + } private string CliFeedbackRegistrationExpression; @@ -184,6 +221,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc); PeopleCountFeedback = new IntFeedback(PeopleCountFeedbackFunc); SpeakerTrackIsOnFeedback = new BoolFeedback(SpeakerTrackIsOnFeedbackFunc); + SelfviewIsOnFeedback = new BoolFeedback(SelfViewIsOnFeedbackFunc); + SelfviewPipPositionFeedback = new StringFeedback(SelfviewPipPositionFeedbackFunc); + LocalLayoutFeedback = new StringFeedback(LocalLayoutFeedbackFunc); Communication = comm; @@ -223,8 +263,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CallHistory = new CodecCallHistory(); - CallFavorites = new CodecCallFavorites(); - CallFavorites.Favorites = props.Favorites; + if (props.Favorites != null) + { + CallFavorites = new CodecCallFavorites(); + CallFavorites.Favorites = props.Favorites; + } DirectoryRoot = new CodecDirectory(); @@ -238,6 +281,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CodecStatus.Status.RoomAnalytics.PeoplePresence.ValueChangedAction = RoomIsOccupiedFeedback.FireUpdate; CodecStatus.Status.RoomAnalytics.PeopleCount.Current.ValueChangedAction = PeopleCountFeedback.FireUpdate; CodecStatus.Status.Cameras.SpeakerTrack.Status.ValueChangedAction = SpeakerTrackIsOnFeedback.FireUpdate; + CodecStatus.Status.Video.Selfview.Mode.ValueChangedAction = SelfviewIsOnFeedback.FireUpdate; + CodecStatus.Status.Video.Selfview.PIPPosition.ValueChangedAction = ComputeSelfviewPipStatus; + CodecStatus.Status.Video.Layout.LayoutFamily.Local.ValueChangedAction = ComputeLocalLayout; } /// @@ -944,6 +990,109 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SendText("xCommand SystemUnit Boot Action: Restart"); } + /// + /// Turns on Selfview Mode + /// + public void SelfviewModeOn() + { + SendText("xCommand Video Selfview Set Mode: On"); + } + + /// + /// Turns off Selfview Mode + /// + public void SelfviewModeOff() + { + SendText("xCommand Video Selfview Set Mode: Off"); + } + + /// + /// Toggles Selfview mode on/off + /// + public void SelfviewModeToggle() + { + string mode = string.Empty; + + if (CodecStatus.Status.Video.Selfview.Mode.BoolValue) + mode = "Off"; + else + mode = "On"; + + SendText(string.Format("xCommand Video Selfview Set Mode: {0}", mode)); + } + + /// + /// Sets a specified position for the selfview PIP window + /// + /// + public void SelfviewPipPositionSet(CodecCommandWithLabel position) + { + SendText(string.Format("xCommand Video Selfview Set Mode: On PIPPosition: {0}", position.Command)); + } + + /// + /// Toggles to the next selfview PIP position + /// + public void SelfviewPipPositionToggle() + { + if (CurrentSelfviewPipPosition != null) + { + var nextPipPositionIndex = SelfviewPipPositions.IndexOf(CurrentSelfviewPipPosition) + 1; + + if (nextPipPositionIndex >= SelfviewPipPositions.Count) // Check if we need to loop back to the first item in the list + nextPipPositionIndex = 0; + + SelfviewPipPositionSet(SelfviewPipPositions[nextPipPositionIndex]); + } + } + + /// + /// Sets a specific local layout + /// + /// + public void LocalLayoutSet(CodecCommandWithLabel layout) + { + SendText(string.Format("xCommand Video Layout LayoutFamily Set Target: local LayoutFamily: {0}", layout.Command)); + } + + /// + /// Toggles to the next local layout + /// + public void LocalLayoutToggle() + { + if(CurrentLocalLayout != null) + { + var nextLocalLayoutIndex = LocalLayouts.IndexOf(CurrentLocalLayout) + 1; + + if (nextLocalLayoutIndex >= LocalLayouts.Count) // Check if we need to loop back to the first item in the list + nextLocalLayoutIndex = 0; + + LocalLayoutSet(LocalLayouts[nextLocalLayoutIndex]); + } + } + + /// + /// Calculates the current selfview PIP position + /// + void ComputeSelfviewPipStatus() + { + CurrentSelfviewPipPosition = SelfviewPipPositions.FirstOrDefault(p => p.Command.ToLower().Equals(CodecStatus.Status.Video.Selfview.PIPPosition.Value.ToLower())); + + if(CurrentSelfviewPipPosition != null) + SelfviewIsOnFeedback.FireUpdate(); + } + + /// + /// Calculates the current local Layout + /// + void ComputeLocalLayout() + { + CurrentLocalLayout = LocalLayouts.FirstOrDefault(l => l.Command.ToLower().Equals(CodecStatus.Status.Video.Layout.LayoutFamily.Local.Value.ToLower())); + + if (CurrentLocalLayout != null) + LocalLayoutFeedback.FireUpdate(); + } + public void RemoveCallHistoryEntry(CodecCallHistory.CallHistoryEntry entry) { SendText(string.Format("xCommand CallHistory DeleteEntry CallHistoryId: {0} AcknowledgeConsecutiveDuplicates: True", entry.OccurrenceHistoryId)); @@ -1017,6 +1166,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco } } + /// + /// Represents a codec command that might need to have a friendly label applied for UI feedback purposes + /// + public class CodecCommandWithLabel + { + public string Command { get; set; } + public string Label { get; set; } + + public CodecCommandWithLabel(string command, string label) + { + Command = command; + Label = label; + } + } + /// /// Tracks the initial sycnronization state of the codec when making a connection /// diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs index ed04032f..8dafed19 100644 --- a/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/xStatus.cs @@ -1485,19 +1485,42 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public List Source { get; set; } } - public class Local + public class Local : ValueProperty { - public string Value { get; set; } + string _Value; + + public string Value // Valid values are On/Off + { + get + { + return _Value; + } + set + { + _Value = value; + OnValueChanged(); + } + } } public class LayoutFamily { public Local Local { get; set; } + + public LayoutFamily() + { + Local = new Local(); + } } public class Layout { public LayoutFamily LayoutFamily { get; set; } + + public Layout() + { + LayoutFamily = new LayoutFamily(); + } } public class Monitors @@ -1588,19 +1611,43 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public string Value { get; set; } } - public class Mode8 + public class Mode8 : ValueProperty { - public string Value { get; set; } + public bool BoolValue { get; private set; } + + public string Value // Valid values are On/Off + { + set + { + // If the incoming value is "On" it sets the BoolValue true, otherwise sets it false + BoolValue = value == "On"; + OnValueChanged(); + } + } } + public class OnMonitorRole { public string Value { get; set; } } - public class PIPPosition3 + public class PIPPosition3 : ValueProperty { - public string Value { get; set; } + string _Value; + + public string Value + { + get + { + return _Value; + } + set + { + _Value = value; + OnValueChanged(); + } + } } public class Selfview @@ -1609,6 +1656,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Mode8 Mode { get; set; } public OnMonitorRole OnMonitorRole { get; set; } public PIPPosition3 PIPPosition { get; set; } + + public Selfview() + { + Mode = new Mode8(); + PIPPosition = new PIPPosition3(); + } } public class Video @@ -1620,6 +1673,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public Output2 Output { get; set; } public Presentation2 Presentation { get; set; } public Selfview Selfview { get; set; } + + public Video() + { + Selfview = new Selfview(); + Layout = new Layout(); + } } public class AnswerState @@ -1751,6 +1810,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco RoomAnalytics = new RoomAnalytics(); Conference = new Conference2(); SystemUnit = new SystemUnit(); + Video = new Video(); } } diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecLayouts.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecLayouts.cs new file mode 100644 index 00000000..6246283a --- /dev/null +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecLayouts.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec +{ + /// + /// Defines the required elements for layout control + /// + public interface IHasCodecLayouts + { + StringFeedback LocalLayoutFeedback { get; } + + void LocalLayoutToggle(); + } +} \ No newline at end of file diff --git a/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecSelfview.cs b/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecSelfview.cs new file mode 100644 index 00000000..657d402e --- /dev/null +++ b/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecSelfview.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec +{ + /// + /// Defines the requred elements for selfview control + /// + public interface IHasCodecSelfview + { + BoolFeedback SelfviewIsOnFeedback { get; } + + void SelfviewModeOn(); + + void SelfviewModeOff(); + + void SelfviewModeToggle(); + } +} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/OTHER/Fusion/FusionSystemController.cs b/Essentials/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemController.cs similarity index 100% rename from Essentials/PepperDashEssentials/OTHER/Fusion/FusionSystemController.cs rename to Essentials/PepperDashEssentials/OTHER/Fusion/EssentialsHuddleSpaceFusionSystemController.cs diff --git a/Essentials/PepperDashEssentials/PepperDashEssentials.csproj b/Essentials/PepperDashEssentials/PepperDashEssentials.csproj index 693224e8..1fc86949 100644 --- a/Essentials/PepperDashEssentials/PepperDashEssentials.csproj +++ b/Essentials/PepperDashEssentials/PepperDashEssentials.csproj @@ -138,7 +138,7 @@ - + diff --git a/Essentials/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs b/Essentials/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs index c93ce06c..98662675 100644 --- a/Essentials/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs +++ b/Essentials/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs @@ -412,7 +412,12 @@ namespace PepperDash.Essentials dest.ReleaseAndMakeRoute(source, route.Type); } return true; - } + } + + public override void RoomVacatedForTimeoutPeriod(object o) + { + //Implement this + } /// /// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions diff --git a/Essentials/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/Essentials/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index 36adf58c..3ffad5ca 100644 --- a/Essentials/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/Essentials/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -451,7 +451,12 @@ namespace PepperDash.Essentials dest.ReleaseAndMakeRoute(source, route.Type); } return true; - } + } + + public override void RoomVacatedForTimeoutPeriod(object o) + { + //Implement this + } /// /// Does what it says diff --git a/Essentials/PepperDashEssentials/Room/Types/EssentialsPresentationRoom.cs b/Essentials/PepperDashEssentials/Room/Types/EssentialsPresentationRoom.cs index 00ec1c8f..adb35c8f 100644 --- a/Essentials/PepperDashEssentials/Room/Types/EssentialsPresentationRoom.cs +++ b/Essentials/PepperDashEssentials/Room/Types/EssentialsPresentationRoom.cs @@ -426,6 +426,12 @@ namespace PepperDash.Essentials dest.ReleaseAndMakeRoute(source, route.Type); } return true; - } + } + + public override void RoomVacatedForTimeoutPeriod(object o) + { + //Implement this + } + } } \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs b/Essentials/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs index 2652f99f..23eeed2b 100644 --- a/Essentials/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs +++ b/Essentials/PepperDashEssentials/Room/Types/EssentialsRoomBase.cs @@ -4,7 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; using PepperDash.Core; -using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Devices.Common.Occupancy; namespace PepperDash.Essentials { @@ -16,7 +17,6 @@ namespace PepperDash.Essentials event SourceInfoChangeHandler CurrentSingleSourceChange; } - /// /// /// @@ -28,7 +28,9 @@ namespace PepperDash.Essentials public BoolFeedback OnFeedback { get; private set; } public BoolFeedback IsWarmingUpFeedback { get; private set; } - public BoolFeedback IsCoolingDownFeedback { get; private set; } + public BoolFeedback IsCoolingDownFeedback { get; private set; } + + public IOccupancyStatusProvider RoomOccupancy { get; private set; } protected abstract Func IsWarmingFeedbackFunc { get; } protected abstract Func IsCoolingFeedbackFunc { get; } @@ -47,7 +49,11 @@ namespace PepperDash.Essentials public PepperDash.Essentials.Room.EssentialsRoomEmergencyBase Emergency { get; set; } - public string LogoUrl { get; set; } + public string LogoUrl { get; set; } + + protected CTimer RoomVacancyShutdownTimer; + + protected long RoomVacancyShutdownTimeout = 1800000; // 30 minutes by default /// /// @@ -103,9 +109,41 @@ namespace PepperDash.Essentials /// /// Override this to implement a default volume level(s) method /// - public abstract void SetDefaultLevels(); + 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) + { + RoomOccupancy = statusProvider; + + RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += new EventHandler(RoomIsOccupiedFeedback_OutputChange); + } + + void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e) + { + if ((sender as IOccupancyStatusProvider).RoomIsOccupiedFeedback.BoolValue == false) + { + // Trigger the timer when the room is vacant + RoomVacancyShutdownTimer = new CTimer(RoomVacatedForTimeoutPeriod, RoomVacancyShutdownTimeout); + } + else + { + // Reset the timer when the room is occupied + if(RoomVacancyShutdownTimer != null) + RoomVacancyShutdownTimer.Reset(RoomVacancyShutdownTimeout); + } + } + + /// + /// 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 ///