From 7de0251188e4a7e824dd4d079b6343b3b3192dd6 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Jun 2021 11:44:09 -0600 Subject: [PATCH 01/37] add ConvertType method to convert type This method should allow for using a string value in place of an enum as a parameter. Integers will still fail. --- .../Devices/DeviceJsonApi.cs | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceJsonApi.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceJsonApi.cs index a1930cf0..2dda0bf8 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceJsonApi.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceJsonApi.cs @@ -77,10 +77,9 @@ namespace PepperDash.Essentials.Core var mParams = method.GetParameters(); var convertedParams = mParams - .Select((p, i) => Convert.ChangeType(action.Params[i], p.ParameterType, - System.Globalization.CultureInfo.InvariantCulture)) + .Select((p, i) => ConvertType(action.Params[i], p.ParameterType)) .ToArray(); - var ret = method.Invoke(obj, convertedParams); + method.Invoke(obj, convertedParams); CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name, action.DeviceKey); @@ -91,6 +90,23 @@ namespace PepperDash.Essentials.Core ex.Message);} } + private static object ConvertType(object value, Type conversionType) + { + if (!conversionType.IsEnum) + { + return Convert.ChangeType(value, conversionType, System.Globalization.CultureInfo.InvariantCulture); + } + + var stringValue = Convert.ToString(value); + + if (String.IsNullOrEmpty(stringValue)) + { + throw new InvalidCastException( + String.Format("{0} cannot be converted to a string prior to conversion to enum")); + } + return Enum.Parse(conversionType, stringValue, true); + } + /// /// Gets the properties on a device /// @@ -275,6 +291,8 @@ namespace PepperDash.Essentials.Core //var props = t.GetProperties().Select(p => new PropertyNameType(p, obj)); //return JsonConvert.SerializeObject(props, Formatting.Indented); } + + } public class DeviceActionWrapper From 1ebacf3f0f50f5d248d9bd73979207bd7b502996 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Jun 2021 12:12:59 -0600 Subject: [PATCH 02/37] Fix formatting issue --- .../PepperDashEssentialsBase/Devices/DeviceManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs index cca16ec7..aac38dfa 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs @@ -435,7 +435,7 @@ namespace PepperDash.Essentials.Core var min = Convert.ToUInt32(timeout); device.StreamDebugging.SetDebuggingWithSpecificTimeout(debugSetting, min); - Debug.Console(0, "Device: '{0}' debug level set to {1) for {2} minutes", deviceKey, debugSetting, min); + Debug.Console(0, "Device: '{0}' debug level set to {1} for {2} minutes", deviceKey, debugSetting, min); } catch (Exception e) From a76f4c15dc81dae7789f5155d92e564ab5b27fe3 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 29 Jun 2021 09:47:56 -0600 Subject: [PATCH 03/37] Updates to IHasScheduleAwareness --- .../Codec/iHasScheduleAwareness.cs | 18 ++++++++++++++++++ .../VideoCodec/MockVC/MockVC.cs | 4 +++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs index 7d6acdc2..8799b33b 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Devices.Common.Codec { public enum eMeetingEventChangeType @@ -115,17 +117,24 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public class Meeting { + [JsonProperty("minutesBeforeMeeting")] public int MinutesBeforeMeeting; + [JsonProperty("id")] public string Id { get; set; } + [JsonProperty("organizer")] public string Organizer { get; set; } + [JsonProperty("title")] public string Title { get; set; } + [JsonProperty("agenda")] public string Agenda { get; set; } + [JsonProperty("meetingWarningMinutes")] public TimeSpan MeetingWarningMinutes { get { return TimeSpan.FromMinutes(MinutesBeforeMeeting); } } + [JsonProperty("timeToMeetingStart")] public TimeSpan TimeToMeetingStart { get @@ -133,6 +142,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec return StartTime - DateTime.Now; } } + [JsonProperty("timeToMeetingEnd")] public TimeSpan TimeToMeetingEnd { get @@ -140,8 +150,11 @@ namespace PepperDash.Essentials.Devices.Common.Codec return EndTime - DateTime.Now; } } + [JsonProperty("startTime")] public DateTime StartTime { get; set; } + [JsonProperty("endTime")] public DateTime EndTime { get; set; } + [JsonProperty("duration")] public TimeSpan Duration { get @@ -149,7 +162,9 @@ namespace PepperDash.Essentials.Devices.Common.Codec return EndTime - StartTime; } } + [JsonProperty("privacy")] public eMeetingPrivacy Privacy { get; set; } + [JsonProperty("joinable")] public bool Joinable { get @@ -159,9 +174,12 @@ namespace PepperDash.Essentials.Devices.Common.Codec } } //public string ConferenceNumberToDial { get; set; } + [JsonProperty("conferencePassword")] public string ConferencePassword { get; set; } + [JsonProperty("isOneButtonToPushMeeting")] public bool IsOneButtonToPushMeeting { get; set; } + [JsonProperty("calls")] public List Calls { get; private set; } public Meeting() diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs index c4bfa298..a947a1d1 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs @@ -396,10 +396,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec if (_CodecSchedule == null || _CodecSchedule.Meetings.Count == 0 || _CodecSchedule.Meetings[_CodecSchedule.Meetings.Count - 1].StartTime < DateTime.Now) { - _CodecSchedule = new CodecScheduleAwareness(); + _CodecSchedule = new CodecScheduleAwareness(10000); for (int i = 0; i < 5; i++) { var m = new Meeting(); + m.Id = i.ToString(); + m.Organizer = "Employee " + 1; m.StartTime = DateTime.Now.AddMinutes(3).AddHours(i); m.EndTime = DateTime.Now.AddHours(i).AddMinutes(30); m.Title = "Meeting " + i; From 840934502bb0f3b27e0c341a123d3f9782edc8fe Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 29 Jun 2021 17:35:22 -0600 Subject: [PATCH 04/37] Working on getting meeting change events to trigger properly --- .../UI/JoinConstants/UIBoolJoin.cs | 4 ++ .../Codec/iHasScheduleAwareness.cs | 45 ++++++++++++++----- .../VideoCodec/MockVC/MockVC.cs | 20 +++++++-- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/PepperDashEssentials/UI/JoinConstants/UIBoolJoin.cs b/PepperDashEssentials/UI/JoinConstants/UIBoolJoin.cs index 23ab797e..293fddd5 100644 --- a/PepperDashEssentials/UI/JoinConstants/UIBoolJoin.cs +++ b/PepperDashEssentials/UI/JoinConstants/UIBoolJoin.cs @@ -764,6 +764,10 @@ namespace PepperDash.Essentials /// public const uint NextMeetingModalVisible = 15049; /// + /// 15050 + /// + public const uint NextMeetingNotificationRibbonVisible = 15050; + /// /// 15051 /// public const uint Display1SelectPressAndFb = 15051; diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs index 8799b33b..5e2b1c23 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs @@ -4,13 +4,15 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using PepperDash.Core; + using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { public enum eMeetingEventChangeType { - Unkown = 0, + Unknown = 0, MeetingStartWarning, MeetingStart, MeetingEndWarning, @@ -34,6 +36,10 @@ namespace PepperDash.Essentials.Devices.Common.Codec private int _meetingWarningMinutes = 5; + private Meeting _previousChangedMeeting; + + private eMeetingEventChangeType _previousChangeType = eMeetingEventChangeType.Unknown; + public int MeetingWarningMinutes { get { return _meetingWarningMinutes; } @@ -90,24 +96,39 @@ namespace PepperDash.Essentials.Devices.Common.Codec { // Iterate the meeting list and check if any meeting need to do anythingk - const double meetingTimeEpsilon = 0.0001; + const double meetingTimeEpsilon = 0.05; foreach (var m in Meetings) { - var changeType = eMeetingEventChangeType.Unkown; + var changeType = eMeetingEventChangeType.Unknown; - if (m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to start + //Debug.Console(2, "Math.Abs(m.TimeToMeetingEnd.TotalMinutes) = {0}", Math.Abs(m.TimeToMeetingEnd.TotalMinutes)); + if (_previousChangeType != eMeetingEventChangeType.MeetingStartWarning && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start + { + Debug.Console(2, "MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds); changeType = eMeetingEventChangeType.MeetingStartWarning; - else if (Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start + } + else if (_previousChangeType != eMeetingEventChangeType.MeetingStart && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting Start + { + Debug.Console(2, "MeetingStart"); changeType = eMeetingEventChangeType.MeetingStart; - else if (m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes) // Meeting is about to end + } + else if (_previousChangeType != eMeetingEventChangeType.MeetingEndWarning && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end changeType = eMeetingEventChangeType.MeetingEndWarning; - else if (Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended + else if (_previousChangeType != eMeetingEventChangeType.MeetingEnd && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended changeType = eMeetingEventChangeType.MeetingEnd; - if (changeType != eMeetingEventChangeType.Unkown) - OnMeetingChange(changeType, m); - } + if (changeType != eMeetingEventChangeType.Unknown) + { + // check to make sure this is not a redundant event for one that was fired last + if (_previousChangedMeeting == null || (_previousChangedMeeting != m && _previousChangeType != changeType)) + { + _previousChangeType = changeType; + _previousChangedMeeting = m; + OnMeetingChange(changeType, m); + } + } + } } } @@ -169,8 +190,10 @@ namespace PepperDash.Essentials.Devices.Common.Codec { get { - return StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now + var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now && DateTime.Now <= EndTime; //.AddMinutes(-5); + Debug.Console(2, "Meeting Id: {0} joinable: {1}", Id, joinable); + return joinable; } } //public string ConferenceNumberToDial { get; set; } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs index a947a1d1..b87f1fa8 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs @@ -139,7 +139,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public override void Dial(Meeting meeting) { - throw new NotImplementedException(); + Debug.Console(1, this, "Dial Meeting: {0}", meeting.Id); + var call = new CodecActiveCallItem() { Name = meeting.Title, Number = meeting.Id, Id = meeting.Id, Status = eCodecCallStatus.Dialing, Direction = eCodecCallDirection.Outgoing, Type = eCodecCallType.Video }; + ActiveCalls.Add(call); + OnCallStatusChange(call); + + //ActiveCallCountFeedback.FireUpdate(); + // Simulate 2-second ring, then connecting, then connected + new CTimer(o => + { + call.Type = eCodecCallType.Video; + SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connecting, call); + new CTimer(oo => SetNewCallStatusAndFireCallStatusChange(eCodecCallStatus.Connected, call), 1000); + }, 2000); + } /// @@ -396,14 +409,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec if (_CodecSchedule == null || _CodecSchedule.Meetings.Count == 0 || _CodecSchedule.Meetings[_CodecSchedule.Meetings.Count - 1].StartTime < DateTime.Now) { - _CodecSchedule = new CodecScheduleAwareness(10000); + _CodecSchedule = new CodecScheduleAwareness(1000); for (int i = 0; i < 5; i++) { var m = new Meeting(); + m.MinutesBeforeMeeting = 5; m.Id = i.ToString(); m.Organizer = "Employee " + 1; m.StartTime = DateTime.Now.AddMinutes(3).AddHours(i); - m.EndTime = DateTime.Now.AddHours(i).AddMinutes(30); + m.EndTime = DateTime.Now.AddHours(i).AddMinutes(55); m.Title = "Meeting " + i; m.Calls.Add(new Call() { Number = i + "meeting@fake.com"}); _CodecSchedule.Meetings.Add(m); From e964172200d777bd940d698145a343a6ef703e5f Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 2 Jul 2021 15:01:17 -0600 Subject: [PATCH 05/37] #729 Updates to get CheckSchedule method working as designed --- .../Display/MockDisplay.cs | 3 + .../Codec/iHasScheduleAwareness.cs | 76 +++++++++++++------ .../VideoCodec/MockVC/MockVC.cs | 4 +- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/MockDisplay.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/MockDisplay.cs index dcdba6d8..eb529376 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/MockDisplay.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/MockDisplay.cs @@ -59,6 +59,9 @@ namespace PepperDash.Essentials.Core VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; }); MuteFeedback = new BoolFeedback("MuteOn", () => _IsMuted); + + WarmupTime = 10000; + CooldownTime = 5000; } public override void PowerOn() diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs index 5e2b1c23..24f1968b 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasScheduleAwareness.cs @@ -10,13 +10,14 @@ using Newtonsoft.Json; namespace PepperDash.Essentials.Devices.Common.Codec { + [Flags] public enum eMeetingEventChangeType { Unknown = 0, - MeetingStartWarning, - MeetingStart, - MeetingEndWarning, - MeetingEnd + MeetingStartWarning = 1, + MeetingStart = 2, + MeetingEndWarning = 4, + MeetingEnd = 8 } public interface IHasScheduleAwareness @@ -83,50 +84,69 @@ namespace PepperDash.Essentials.Devices.Common.Codec _scheduleChecker = new CTimer(CheckSchedule, null, pollTime, pollTime); } + /// + /// Helper method to fire MeetingEventChange. Should only fire once for each changeType on each meeting + /// + /// + /// private void OnMeetingChange(eMeetingEventChangeType changeType, Meeting meeting) { - var handler = MeetingEventChange; - if (handler != null) + Debug.Console(2, "*****************OnMeetingChange. id: {0} changeType: {1}**********************", meeting.Id, changeType); + if (changeType != (changeType & meeting.NotifiedChangeTypes)) { - handler(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting }); + // Add this change type to the NotifiedChangeTypes + meeting.NotifiedChangeTypes |= changeType; + + var handler = MeetingEventChange; + if (handler != null) + { + handler(this, new MeetingEventArgs() { ChangeType = changeType, Meeting = meeting }); + } + } + else + { + Debug.Console(2, "Meeting: {0} already notified of changeType: {1}", meeting.Id, changeType); } } + + /// + /// Checks the schedule to see if any MeetingEventChange updates should be fired + /// + /// private void CheckSchedule(object o) { - // Iterate the meeting list and check if any meeting need to do anythingk + // Iterate the meeting list and check if any meeting need to do anything const double meetingTimeEpsilon = 0.05; foreach (var m in Meetings) { var changeType = eMeetingEventChangeType.Unknown; - //Debug.Console(2, "Math.Abs(m.TimeToMeetingEnd.TotalMinutes) = {0}", Math.Abs(m.TimeToMeetingEnd.TotalMinutes)); - if (_previousChangeType != eMeetingEventChangeType.MeetingStartWarning && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start + if (eMeetingEventChangeType.MeetingStartWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStartWarning) && m.TimeToMeetingStart.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingStart.Seconds > 0) // Meeting is about to start { - Debug.Console(2, "MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds); + Debug.Console(2, "********************* MeetingStartWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingStart.TotalMinutes, m.TimeToMeetingStart.Seconds); changeType = eMeetingEventChangeType.MeetingStartWarning; } - else if (_previousChangeType != eMeetingEventChangeType.MeetingStart && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting Start + else if (eMeetingEventChangeType.MeetingStart != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingStart) && Math.Abs(m.TimeToMeetingStart.TotalMinutes) < meetingTimeEpsilon) // Meeting Start { - Debug.Console(2, "MeetingStart"); + Debug.Console(2, "********************* MeetingStart"); changeType = eMeetingEventChangeType.MeetingStart; } - else if (_previousChangeType != eMeetingEventChangeType.MeetingEndWarning && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end + else if (eMeetingEventChangeType.MeetingEndWarning != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEndWarning) && m.TimeToMeetingEnd.TotalMinutes <= m.MeetingWarningMinutes.TotalMinutes && m.TimeToMeetingEnd.Seconds > 0) // Meeting is about to end + { + Debug.Console(2, "********************* MeetingEndWarning. TotalMinutes: {0} Seconds: {1}", m.TimeToMeetingEnd.TotalMinutes, m.TimeToMeetingEnd.Seconds); changeType = eMeetingEventChangeType.MeetingEndWarning; - else if (_previousChangeType != eMeetingEventChangeType.MeetingEnd && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended + } + else if (eMeetingEventChangeType.MeetingEnd != (m.NotifiedChangeTypes & eMeetingEventChangeType.MeetingEnd) && Math.Abs(m.TimeToMeetingEnd.TotalMinutes) < meetingTimeEpsilon) // Meeting has ended + { + Debug.Console(2, "********************* MeetingEnd"); changeType = eMeetingEventChangeType.MeetingEnd; + } if (changeType != eMeetingEventChangeType.Unknown) { - // check to make sure this is not a redundant event for one that was fired last - if (_previousChangedMeeting == null || (_previousChangedMeeting != m && _previousChangeType != changeType)) - { - _previousChangeType = changeType; - _previousChangedMeeting = m; - - OnMeetingChange(changeType, m); - } + OnMeetingChange(changeType, m); } } @@ -191,8 +211,8 @@ namespace PepperDash.Essentials.Devices.Common.Codec get { var joinable = StartTime.AddMinutes(-MinutesBeforeMeeting) <= DateTime.Now - && DateTime.Now <= EndTime; //.AddMinutes(-5); - Debug.Console(2, "Meeting Id: {0} joinable: {1}", Id, joinable); + && DateTime.Now <= EndTime.AddMinutes(-5); + //Debug.Console(2, "Meeting Id: {0} joinable: {1}", Id, joinable); return joinable; } } @@ -205,6 +225,12 @@ namespace PepperDash.Essentials.Devices.Common.Codec [JsonProperty("calls")] public List Calls { get; private set; } + /// + /// Tracks the change types that have already been notified for + /// + [JsonIgnore] + public eMeetingEventChangeType NotifiedChangeTypes { get; set; } + public Meeting() { Calls = new List(); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs index b87f1fa8..ca199957 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/MockVC/MockVC.cs @@ -416,8 +416,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec m.MinutesBeforeMeeting = 5; m.Id = i.ToString(); m.Organizer = "Employee " + 1; - m.StartTime = DateTime.Now.AddMinutes(3).AddHours(i); - m.EndTime = DateTime.Now.AddHours(i).AddMinutes(55); + m.StartTime = DateTime.Now.AddMinutes(6).AddHours(i); + m.EndTime = DateTime.Now.AddHours(i).AddMinutes(16); m.Title = "Meeting " + i; m.Calls.Add(new Call() { Number = i + "meeting@fake.com"}); _CodecSchedule.Meetings.Add(m); From d95ee27979219fc1df0470ca28b415371549b493 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 2 Jul 2021 15:01:51 -0600 Subject: [PATCH 06/37] #728 corrects casing of folder name in Global.FilePathPrefix at startup --- PepperDashEssentials/ControlSystem.cs | 35 ++++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index a8002f7e..e4c521b5 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -131,29 +131,46 @@ namespace PepperDash.Essentials if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows CE OS { - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on {1} Appliance", Global.AssemblyVersion, Global.ProcessorSeries.ToString()); + string userFolder; + string nvramFolder; + bool is4series = false; + + if (eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4)) // Handle 4-series + { + is4series = true; + // Set path to user/ + userFolder = "user"; + nvramFolder = "nvram"; + } + else + { + userFolder = "User"; + nvramFolder = "Nvram"; + } + + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on {1} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series"); // Check if User/ProgramX exists - if (Directory.Exists(Global.ApplicationDirectoryPathPrefix + dirSeparator + "User" + if (Directory.Exists(Global.ApplicationDirectoryPathPrefix + dirSeparator + userFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber))) { - Debug.Console(0, @"User/program{0} directory found", InitialParametersClass.ApplicationNumber); - filePathPrefix = directoryPrefix + dirSeparator + "User" + Debug.Console(0, @"{0}/program{1} directory found", userFolder, InitialParametersClass.ApplicationNumber); + filePathPrefix = directoryPrefix + dirSeparator + userFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; } // Check if Nvram/Programx exists - else if (Directory.Exists(directoryPrefix + dirSeparator + "Nvram" + else if (Directory.Exists(directoryPrefix + dirSeparator + nvramFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber))) { - Debug.Console(0, @"Nvram/program{0} directory found", InitialParametersClass.ApplicationNumber); - filePathPrefix = directoryPrefix + dirSeparator + "Nvram" + Debug.Console(0, @"{0}/program{1} directory found", nvramFolder, InitialParametersClass.ApplicationNumber); + filePathPrefix = directoryPrefix + dirSeparator + nvramFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; } // If neither exists, set path to User/ProgramX else { - Debug.Console(0, @"No previous directory found. Using User/program{0}", InitialParametersClass.ApplicationNumber); - filePathPrefix = directoryPrefix + dirSeparator + "User" + Debug.Console(0, @"No previous directory found. Using {0}/program{1}", userFolder, InitialParametersClass.ApplicationNumber); + filePathPrefix = directoryPrefix + dirSeparator + userFolder + dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator; } } From 2181410927cc69b0b9ca24b87eb4640539ec923d Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 12 Jul 2021 17:22:36 -0600 Subject: [PATCH 07/37] #736 Adds IEssentialsRoom and IEssentialsHuddleSpaceRoom interfaces Refactors all references to EssentialsRoomBase and EssentialsHuddleSpaceRoom to use the new interfaces instead --- PepperDashEssentials/ControlSystem.cs | 6 +- .../PepperDashEssentials.csproj | 1 + .../Room/Config/EssentialsRoomConfig.cs | 4 +- .../EsentialsRoomEmergencyContactClosure.cs | 4 +- .../Room/Types/EssentialsDualDisplayRoom.cs | 4 +- .../Room/Types/EssentialsHuddleSpaceRoom.cs | 2 +- .../Room/Types/EssentialsHuddleVtc1Room.cs | 6 +- .../Room/Types/IEssentialsHuddleSpaceRoom.cs | 28 +++ .../UI/EssentialsTouchpanelController.cs | 4 +- .../UIDrivers/DualDisplayRouting.cs | 6 +- .../Essentials/EssentialsHeaderDriver.cs | 6 +- ...tialsPresentationPanelAvFunctionsDriver.cs | 6 +- .../EssentialsHuddlePanelAvFunctionsDriver.cs | 14 +- .../UIDrivers/SmartObjectRoomsList.cs | 6 +- .../UIDrivers/SourceChangeArgs.cs | 2 +- .../DeviceTypeInterfaces/IMobileControl.cs | 2 +- .../Devices/EssentialsDevice.cs | 222 +++++++++--------- .../Devices/IProjectorInterfaces.cs | 8 +- .../Devices/IReconfigurableDevice.cs | 19 ++ .../Devices/ReconfigurableDevice.cs | 2 +- ...lsHuddleSpaceFusionSystemControllerBase.cs | 4 +- .../Fusion/FusionCustomPropertiesBridge.cs | 2 +- .../PepperDash_Essentials_Core.csproj | 2 + .../RoomOnToDefaultSourceWhenOccupied.cs | 4 +- .../Room/EssentialsRoomBase.cs | 2 +- .../Room/IEssentialsRoom.cs | 66 ++++++ .../Room/Interfaces.cs | 5 +- 27 files changed, 278 insertions(+), 159 deletions(-) create mode 100644 PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IReconfigurableDevice.cs create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/IEssentialsRoom.cs diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index e4c521b5..6d3ca5c6 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -452,7 +452,7 @@ namespace PepperDash.Essentials foreach (var roomConfig in ConfigReader.ConfigObject.Rooms) { - var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as EssentialsRoomBase; + var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as IEssentialsRoom; if (room != null) { // default IPID @@ -474,7 +474,7 @@ namespace PepperDash.Essentials } } - if (room is EssentialsHuddleSpaceRoom) + if (room is IEssentialsHuddleSpaceRoom) { DeviceManager.AddDevice(room); @@ -524,7 +524,7 @@ namespace PepperDash.Essentials } - private static void CreateMobileControlBridge(EssentialsRoomBase room) + private static void CreateMobileControlBridge(IEssentialsRoom room) { var mobileControl = GetMobileControlDevice(); diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 7b548dd5..14bd450a 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -149,6 +149,7 @@ + diff --git a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs index 6a59cc56..5ec0565d 100644 --- a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs @@ -47,7 +47,7 @@ namespace PepperDash.Essentials.Room.Config /// Gets and operating, standalone emergegncy object that can be plugged into a room. /// Returns null if there is no emergency defined /// - public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, EssentialsRoomBase room) + public static EssentialsRoomEmergencyBase GetEmergency(EssentialsRoomPropertiesConfig props, IEssentialsRoom room) { // This emergency var emergency = props.Emergency; @@ -96,7 +96,7 @@ namespace PepperDash.Essentials.Room.Config if (behaviour == "trackroomstate") { // Tie LED enable to room power state - var essRoom = room as EssentialsRoomBase; + var essRoom = room as IEssentialsRoom; essRoom.OnFeedback.OutputChange += (o, a) => { if (essRoom.OnFeedback.BoolValue) diff --git a/PepperDashEssentials/Room/Emergency/EsentialsRoomEmergencyContactClosure.cs b/PepperDashEssentials/Room/Emergency/EsentialsRoomEmergencyContactClosure.cs index ab40d2fe..c40ed496 100644 --- a/PepperDashEssentials/Room/Emergency/EsentialsRoomEmergencyContactClosure.cs +++ b/PepperDashEssentials/Room/Emergency/EsentialsRoomEmergencyContactClosure.cs @@ -17,11 +17,11 @@ namespace PepperDash.Essentials.Room public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase { - EssentialsRoomBase Room; + IEssentialsRoom Room; string Behavior; bool TriggerOnClose; - public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, EssentialsRoomBase room) : + public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, IEssentialsRoom room) : base(key) { Room = room; diff --git a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs index ccce0af5..d58f6ac7 100644 --- a/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsDualDisplayRoom.cs @@ -645,9 +645,9 @@ namespace PepperDash.Essentials public static void AllRoomsOff() { var allRooms = DeviceManager.AllDevices.Where(d => - d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions); + d is IEssentialsHuddleSpaceRoom && !(d as IEssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions); foreach (var room in allRooms) - (room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff", (room as EssentialsHuddleSpaceRoom).SourceListKey); + (room as IEssentialsHuddleSpaceRoom).RunRouteAction("roomOff", (room as IEssentialsHuddleSpaceRoom).SourceListKey); } #region IPrivacy Members diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs index 9f388252..7a57e9c1 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs @@ -13,7 +13,7 @@ using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials { - public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasCurrentVolumeControls, IHasDefaultDisplay + public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IEssentialsHuddleSpaceRoom { public event EventHandler CurrentVolumeDeviceChange; public event SourceInfoChangeHandler CurrentSourceChange; diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index 85cfe90f..e6b12f4e 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -733,10 +733,10 @@ namespace PepperDash.Essentials /// public static void AllRoomsOff() { - var allRooms = DeviceManager.AllDevices.Where(d => - d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions); + var allRooms = DeviceManager.AllDevices.Where(d => + d is IEssentialsRoom && !(d as IEssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions); foreach (var room in allRooms) - (room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff"); + (room as IEssentialsHuddleSpaceRoom).RunRouteAction("roomOff"); } diff --git a/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs new file mode 100644 index 00000000..6feff235 --- /dev/null +++ b/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Room.Config; +using PepperDash.Essentials.Core.Devices; + +using PepperDash.Core; + +namespace PepperDash.Essentials +{ + public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay + { + bool ExcludeFromGlobalFunctions { get; } + + void RunRouteAction(string routeKey); + + EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } + + IBasicVolumeControls CurrentVolumeControls { get; } + + event EventHandler CurrentVolumeDeviceChange; + } +} \ No newline at end of file diff --git a/PepperDashEssentials/UI/EssentialsTouchpanelController.cs b/PepperDashEssentials/UI/EssentialsTouchpanelController.cs index 65039872..5c4349fd 100644 --- a/PepperDashEssentials/UI/EssentialsTouchpanelController.cs +++ b/PepperDashEssentials/UI/EssentialsTouchpanelController.cs @@ -222,7 +222,7 @@ namespace PepperDash.Essentials // spin up different room drivers depending on room type var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey); - if (room is EssentialsHuddleSpaceRoom) + if (room is IEssentialsHuddleSpaceRoom) { // Screen Saver Driver mainDriver.ScreenSaverController = new ScreenSaverController(mainDriver, props); @@ -236,7 +236,7 @@ namespace PepperDash.Essentials var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, props); avDriver.DefaultRoomKey = props.DefaultRoomKey; mainDriver.AvDriver = avDriver; - avDriver.CurrentRoom = room as EssentialsHuddleSpaceRoom; + avDriver.CurrentRoom = room as IEssentialsHuddleSpaceRoom; // Environment Driver if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0) diff --git a/PepperDashEssentials/UIDrivers/DualDisplayRouting.cs b/PepperDashEssentials/UIDrivers/DualDisplayRouting.cs index 1aeb7a3c..4b29061d 100644 --- a/PepperDashEssentials/UIDrivers/DualDisplayRouting.cs +++ b/PepperDashEssentials/UIDrivers/DualDisplayRouting.cs @@ -146,18 +146,18 @@ // } -// void CurrentRoom_CurrentSourceInfoChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) +// void CurrentRoom_CurrentSourceInfoChange(IEssentialsRoom room, SourceListItem info, ChangeType type) // { // } -// void CurrentRoom_CurrentDisplay1SourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) +// void CurrentRoom_CurrentDisplay1SourceChange(IEssentialsRoom room, SourceListItem info, ChangeType type) // { // TriList.StringInput[UIStringJoin.Display1SourceLabel].StringValue = PendingSource.PreferredName; // } -// void CurrentRoom_CurrentDisplay2SourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) +// void CurrentRoom_CurrentDisplay2SourceChange(IEssentialsRoom room, SourceListItem info, ChangeType type) // { // TriList.StringInput[UIStringJoin.Display2SourceLabel].StringValue = PendingSource.PreferredName; // } diff --git a/PepperDashEssentials/UIDrivers/Essentials/EssentialsHeaderDriver.cs b/PepperDashEssentials/UIDrivers/Essentials/EssentialsHeaderDriver.cs index ccaedd9c..df87c8f4 100644 --- a/PepperDashEssentials/UIDrivers/Essentials/EssentialsHeaderDriver.cs +++ b/PepperDashEssentials/UIDrivers/Essentials/EssentialsHeaderDriver.cs @@ -52,7 +52,7 @@ namespace PepperDash.Essentials CaretInterlock = new JoinedSigInterlock(TriList); } - void SetUpGear(IAVDriver avDriver, EssentialsRoomBase currentRoom) + void SetUpGear(IAVDriver avDriver, IEssentialsRoom currentRoom) { // Gear TriList.SetString(UIStringJoin.HeaderButtonIcon5, "Gear"); @@ -105,7 +105,7 @@ namespace PepperDash.Essentials { string message = null; var room = DeviceManager.GetDeviceForKey(Config.DefaultRoomKey) - as EssentialsHuddleSpaceRoom; + as IEssentialsHuddleSpaceRoom; if (room != null) message = room.PropertiesConfig.HelpMessage; else @@ -283,7 +283,7 @@ namespace PepperDash.Essentials /// /// Sets up Header Buttons for the EssentialsHuddleSpaceRoom type /// - public void SetupHeaderButtons(EssentialsHuddlePanelAvFunctionsDriver avDriver, EssentialsHuddleSpaceRoom currentRoom) + public void SetupHeaderButtons(EssentialsHuddlePanelAvFunctionsDriver avDriver, IEssentialsHuddleSpaceRoom currentRoom) { HeaderButtonsAreSetUp = false; diff --git a/PepperDashEssentials/UIDrivers/Essentials/EssentialsPresentationPanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/Essentials/EssentialsPresentationPanelAvFunctionsDriver.cs index 4a8cb53c..9c8514ea 100644 --- a/PepperDashEssentials/UIDrivers/Essentials/EssentialsPresentationPanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/Essentials/EssentialsPresentationPanelAvFunctionsDriver.cs @@ -983,7 +983,7 @@ // /// // /// Handles source change // /// -// void _CurrentRoom_SourceInfoChange(EssentialsRoomBase room, +// void _CurrentRoom_SourceInfoChange(IEssentialsRoom room, // SourceListItem info, ChangeType change) // { // if (change == ChangeType.WillChange) @@ -995,7 +995,7 @@ // /// // /// // /// -// void _CurrentRoom_CurrentDisplay1SourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) +// void _CurrentRoom_CurrentDisplay1SourceChange(IEssentialsRoom room, SourceListItem info, ChangeType type) // { // if (type == ChangeType.DidChange) // { @@ -1021,7 +1021,7 @@ // /// // /// // /// -// void _CurrentRoom_CurrentDisplay2SourceChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) +// void _CurrentRoom_CurrentDisplay2SourceChange(IEssentialsRoom room, SourceListItem info, ChangeType type) // { // if (type == ChangeType.DidChange) // { diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs index f22565e5..a0d5947c 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs @@ -78,7 +78,7 @@ namespace PepperDash.Essentials /// /// /// - public EssentialsHuddleSpaceRoom CurrentRoom + public IEssentialsHuddleSpaceRoom CurrentRoom { get { return _CurrentRoom; } set @@ -86,7 +86,7 @@ namespace PepperDash.Essentials SetCurrentRoom(value); } } - EssentialsHuddleSpaceRoom _CurrentRoom; + IEssentialsHuddleSpaceRoom _CurrentRoom; /// /// @@ -498,7 +498,7 @@ namespace PepperDash.Essentials TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true; // Run default source when room is off and share is pressed if (!CurrentRoom.OnFeedback.BoolValue) - CurrentRoom.RunDefaultPresentRoute(); + (CurrentRoom as IRunDefaultPresentRoute).RunDefaultPresentRoute(); } @@ -583,7 +583,7 @@ namespace PepperDash.Essentials void UiSelectSource(string key) { // Run the route and when it calls back, show the source - CurrentRoom.RunRouteAction(key, new Action(() => { })); + CurrentRoom.RunRouteAction(key); } /// @@ -745,7 +745,7 @@ namespace PepperDash.Essentials /// /// Helper for property setter. Sets the panel to the given room, latching up all functionality /// - public void RefreshCurrentRoom(EssentialsHuddleSpaceRoom room) + public void RefreshCurrentRoom(IEssentialsHuddleSpaceRoom room) { if (_CurrentRoom != null) { @@ -836,7 +836,7 @@ namespace PepperDash.Essentials } } - void SetCurrentRoom(EssentialsHuddleSpaceRoom room) + void SetCurrentRoom(IEssentialsHuddleSpaceRoom room) { if (_CurrentRoom == room) return; // Disconnect current (probably never called) @@ -871,7 +871,7 @@ namespace PepperDash.Essentials UpdateMCJoins(_CurrentRoom); } - void UpdateMCJoins(EssentialsHuddleSpaceRoom room) + void UpdateMCJoins(IEssentialsHuddleSpaceRoom room) { TriList.SetString(UIStringJoin.RoomMcUrl, room.MobileControlRoomBridge.McServerUrl); TriList.SetString(UIStringJoin.RoomMcQrCodeUrl, room.MobileControlRoomBridge.QrCodeUrl); diff --git a/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs b/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs index e43abc09..2543e664 100644 --- a/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs +++ b/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs @@ -38,7 +38,7 @@ namespace PepperDash.Essentials /// /// Sets feedback for the given room /// - public void SetFeedbackForRoom(EssentialsHuddleSpaceRoom room) + public void SetFeedbackForRoom(IEssentialsHuddleSpaceRoom room) { var itemToSet = Items.FirstOrDefault(i => i.Room == room); if (itemToSet != null) @@ -48,11 +48,11 @@ namespace PepperDash.Essentials public class SmartObjectRoomsListItem { - public EssentialsHuddleSpaceRoom Room { get; private set; } + public IEssentialsHuddleSpaceRoom Room { get; private set; } SmartObjectRoomsList Parent; public uint Index { get; private set; } - public SmartObjectRoomsListItem(EssentialsHuddleSpaceRoom room, uint index, SmartObjectRoomsList parent, + public SmartObjectRoomsListItem(IEssentialsHuddleSpaceRoom room, uint index, SmartObjectRoomsList parent, Action buttonAction) { Room = room; diff --git a/PepperDashEssentials/UIDrivers/SourceChangeArgs.cs b/PepperDashEssentials/UIDrivers/SourceChangeArgs.cs index c777c08e..5c034084 100644 --- a/PepperDashEssentials/UIDrivers/SourceChangeArgs.cs +++ b/PepperDashEssentials/UIDrivers/SourceChangeArgs.cs @@ -12,5 +12,5 @@ namespace PepperDash.Essentials ///// ///// The handler type for a Room's SourceInfoChange ///// - //public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type); + //public delegate void SourceInfoChangeHandler(IEssentialsRoom room, SourceListItem info, ChangeType type); } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IMobileControl.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IMobileControl.cs index c87e7865..a2dda43a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IMobileControl.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/IMobileControl.cs @@ -8,7 +8,7 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces /// public interface IMobileControl : IKeyed { - void CreateMobileControlRoomBridge(EssentialsRoomBase room, IMobileControl parent); + void CreateMobileControlRoomBridge(IEssentialsRoom room, IMobileControl parent); void LinkSystemMonitorToAppServer(); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs index 8d7f2c8d..781101d4 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs @@ -1,113 +1,113 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharp.Reflection; - -using PepperDash.Core; -using PepperDash.Essentials.Core.Config; - -namespace PepperDash.Essentials.Core -{ - /// - /// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class - /// - [Description("The base Essentials Device Class")] - public abstract class EssentialsDevice : Device - { - protected EssentialsDevice(string key) - : base(key) - { - - } - - protected EssentialsDevice(string key, string name) - : base(key, name) - { - - } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] - public class DescriptionAttribute : Attribute - { - private string _Description; - - public DescriptionAttribute(string description) - { - Debug.Console(2, "Setting Description: {0}", description); - _Description = description; - } - - public string Description - { - get { return _Description; } - } - } - - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] - public class ConfigSnippetAttribute : Attribute - { - private string _ConfigSnippet; - - public ConfigSnippetAttribute(string configSnippet) - { - Debug.Console(2, "Setting Config Snippet {0}", configSnippet); - _ConfigSnippet = configSnippet; - } - - public string ConfigSnippet - { - get { return _ConfigSnippet; } - } - } - - /// - /// Devices the basic needs for a Device Factory - /// - public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice - { - #region IDeviceFactory Members - - /// - /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device - /// - public List TypeNames { get; protected set; } - - /// - /// Loads an item to the DeviceFactory.FactoryMethods dictionary for each entry in the TypeNames list - /// - public void LoadTypeFactories() - { - foreach (var typeName in TypeNames) - { - Debug.Console(2, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); - var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[]; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharp.Reflection; + +using PepperDash.Core; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials.Core +{ + /// + /// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class + /// + [Description("The base Essentials Device Class")] + public abstract class EssentialsDevice : Device + { + protected EssentialsDevice(string key) + : base(key) + { + + } + + protected EssentialsDevice(string key, string name) + : base(key, name) + { + + } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] + public class DescriptionAttribute : Attribute + { + private string _Description; + + public DescriptionAttribute(string description) + { + Debug.Console(2, "Setting Description: {0}", description); + _Description = description; + } + + public string Description + { + get { return _Description; } + } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] + public class ConfigSnippetAttribute : Attribute + { + private string _ConfigSnippet; + + public ConfigSnippetAttribute(string configSnippet) + { + Debug.Console(2, "Setting Config Snippet {0}", configSnippet); + _ConfigSnippet = configSnippet; + } + + public string ConfigSnippet + { + get { return _ConfigSnippet; } + } + } + + /// + /// Devices the basic needs for a Device Factory + /// + public abstract class EssentialsDeviceFactory : IDeviceFactory where T:EssentialsDevice + { + #region IDeviceFactory Members + + /// + /// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device + /// + public List TypeNames { get; protected set; } + + /// + /// Loads an item to the DeviceFactory.FactoryMethods dictionary for each entry in the TypeNames list + /// + public void LoadTypeFactories() + { + foreach (var typeName in TypeNames) + { + Debug.Console(2, "Getting Description Attribute from class: '{0}'", typeof(T).FullName); + var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[]; string description = descriptionAttribute[0].Description; - var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[]; - DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice); - } - } - - /// - /// The method that will build the device - /// - /// The device config - /// An instance of the device - public abstract EssentialsDevice BuildDevice(DeviceConfig dc); - - #endregion - } - - /// - /// Devices the basic needs for a Device Factory - /// - public abstract class EssentialsPluginDeviceFactory : EssentialsDeviceFactory, IPluginDeviceFactory where T : EssentialsDevice - { - /// - /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33") - /// - public string MinimumEssentialsFrameworkVersion { get; protected set; } - } + var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[]; + DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice); + } + } + + /// + /// The method that will build the device + /// + /// The device config + /// An instance of the device + public abstract EssentialsDevice BuildDevice(DeviceConfig dc); + + #endregion + } + + /// + /// Devices the basic needs for a Device Factory + /// + public abstract class EssentialsPluginDeviceFactory : EssentialsDeviceFactory, IPluginDeviceFactory where T : EssentialsDevice + { + /// + /// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33") + /// + public string MinimumEssentialsFrameworkVersion { get; protected set; } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IProjectorInterfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IProjectorInterfaces.cs index 6efb7776..70e2e215 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IProjectorInterfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IProjectorInterfaces.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; using Crestron.SimplSharp; namespace PepperDash.Essentials.Core diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IReconfigurableDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IReconfigurableDevice.cs new file mode 100644 index 00000000..ab0e37c3 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/IReconfigurableDevice.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using PepperDash.Essentials.Core.Config; + + +namespace PepperDash.Essentials.Core.Devices +{ + public interface IReconfigurableDevice + { + event EventHandler ConfigChanged; + + DeviceConfig Config { get; } + + void SetConfig(DeviceConfig config); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/ReconfigurableDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/ReconfigurableDevice.cs index 81988199..3239e192 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/ReconfigurableDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/ReconfigurableDevice.cs @@ -15,7 +15,7 @@ namespace PepperDash.Essentials.Core.Devices /// /// /// - public abstract class ReconfigurableDevice : EssentialsDevice + public abstract class ReconfigurableDevice : EssentialsDevice, IReconfigurableDevice { public event EventHandler ConfigChanged; diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index b26b1980..a172ab49 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -33,7 +33,7 @@ namespace PepperDash.Essentials.Core.Fusion protected FusionRoom FusionRoom; protected Dictionary FusionStaticAssets; public long PushNotificationTimeout = 5000; - protected EssentialsRoomBase Room; + protected IEssentialsRoom Room; public long SchedulePollInterval = 300000; private Event _currentMeeting; @@ -86,7 +86,7 @@ namespace PepperDash.Essentials.Core.Fusion #endregion - public EssentialsHuddleSpaceFusionSystemControllerBase(EssentialsRoomBase room, uint ipId, string joinMapKey) + public EssentialsHuddleSpaceFusionSystemControllerBase(IEssentialsRoom room, uint ipId, string joinMapKey) : base(room.Key + "-fusion") { try diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs index 01b230f9..89b9fcdb 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs @@ -82,7 +82,7 @@ namespace PepperDash.Essentials.Core.Fusion deviceConfig.Properties = JToken.FromObject(devProps); } - else if (device is EssentialsRoomBase) + else if (device is IEssentialsRoom) { // Set the room name if (!string.IsNullOrEmpty(roomInfo.Name)) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index e65b081b..6e48fd66 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -197,6 +197,7 @@ + @@ -288,6 +289,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs index f24daf82..81cbff9e 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs @@ -38,7 +38,7 @@ namespace PepperDash.Essentials.Core ScheduledEventGroup FeatureEventGroup; - public EssentialsRoomBase Room { get; private set; } + public IEssentialsRoom Room { get; private set; } private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom; @@ -84,7 +84,7 @@ namespace PepperDash.Essentials.Core /// void SetUpDevice() { - Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as EssentialsRoomBase; + Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as IEssentialsRoom; if (Room != null) { diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs index cae027f5..0d8e9803 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs @@ -16,7 +16,7 @@ namespace PepperDash.Essentials.Core /// /// /// - public abstract class EssentialsRoomBase : ReconfigurableDevice + public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom { /// /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/IEssentialsRoom.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/IEssentialsRoom.cs new file mode 100644 index 00000000..e83c4b2f --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/IEssentialsRoom.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using PepperDash.Essentials.Room.Config; +using PepperDash.Essentials.Core.Devices; + +using PepperDash.Core; + +namespace PepperDash.Essentials.Core +{ + /// + /// Describes the basic functionality of an EssentialsRoom + /// + public interface IEssentialsRoom : IKeyName, IReconfigurableDevice + { + BoolFeedback OnFeedback { get; } + + event EventHandler RoomOccupancyIsSet; + + BoolFeedback IsWarmingUpFeedback { get; } + BoolFeedback IsCoolingDownFeedback { get; } + + IOccupancyStatusProvider RoomOccupancy { get; } + bool OccupancyStatusProviderIsRemote { get; } + + bool IsMobileControlEnabled { get; } + IMobileControlRoomBridge MobileControlRoomBridge { get; } + + string SourceListKey { get; } + + SecondsCountdownTimer ShutdownPromptTimer { get; } + int ShutdownPromptSeconds { get; } + int ShutdownVacancySeconds { get; } + eShutdownType ShutdownType { get; } + + EssentialsRoomEmergencyBase Emergency { get; } + + Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; } + + string LogoUrlLightBkgnd { get; } + string LogoUrlDarkBkgnd { get; } + + eVacancyMode VacancyMode { get; } + + bool ZeroVolumeWhenSwtichingVolumeDevices { get; } + + void StartShutdown(eShutdownType type); + void StartRoomVacancyTimer(eVacancyMode mode); + + void Shutdown(); + + void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes); + + void PowerOnToDefaultOrLastSource(); + bool RunDefaultPresentRoute(); + + void SetDefaultLevels(); + + void RoomVacatedForTimeoutPeriod(object o); + } + +} \ 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 index 82871228..592b0bd9 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; + namespace PepperDash.Essentials.Core { /// @@ -64,5 +65,7 @@ namespace PepperDash.Essentials.Core { bool RunDefaultCallRoute(); } - + + + } \ No newline at end of file From a37814ab3c01c3370ab57a148bc90083491a7292 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 12 Jul 2021 21:49:54 -0600 Subject: [PATCH 08/37] #736 adds IEssentialsHuddleVtc1Room and refactors to use interface rather than EssentialsHudleVtc1Room --- PepperDashEssentials/ControlSystem.cs | 4 ++-- .../EssentialsHuddleVtc1FusionController.cs | 22 +++++++++---------- .../Room/Types/EssentialsHuddleVtc1Room.cs | 3 +-- .../Room/Types/IEssentialsHuddleSpaceRoom.cs | 20 +++++++++++++++++ .../UI/EssentialsTouchpanelController.cs | 6 ++--- .../Essentials/EssentialsHeaderDriver.cs | 2 +- ...entialsHuddleVtc1PanelAvFunctionsDriver.cs | 16 +++++++------- 7 files changed, 46 insertions(+), 27 deletions(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 6d3ca5c6..033d82fe 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -486,12 +486,12 @@ namespace PepperDash.Essentials CreateMobileControlBridge(room); } - else if (room is EssentialsHuddleVtc1Room) + else if (room is IEssentialsHuddleVtc1Room) { DeviceManager.AddDevice(room); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion"); - DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((EssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey)); + DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey)); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge..."); diff --git a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs index c4a68d4e..54d936f0 100644 --- a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs +++ b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs @@ -16,7 +16,7 @@ namespace PepperDash.Essentials.Fusion { BooleanSigData CodecIsInCall; - public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId, string joinMapKey) + public EssentialsHuddleVtc1FusionController(IEssentialsHuddleVtc1Room room, uint ipId, string joinMapKey) : base(room, ipId, joinMapKey) { @@ -37,7 +37,7 @@ namespace PepperDash.Essentials.Fusion { try { - var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec; + var codec = (Room as IEssentialsHuddleVtc1Room).VideoCodec; if (codec == null) { @@ -141,7 +141,7 @@ namespace PepperDash.Essentials.Fusion void codec_CallStatusChange(object sender, PepperDash.Essentials.Devices.Common.Codec.CodecCallStatusItemChangeEventArgs e) { - var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec; + var codec = (Room as IEssentialsHuddleVtc1Room).VideoCodec; CodecIsInCall.InputSig.BoolValue = codec.IsInCall; } @@ -174,11 +174,11 @@ namespace PepperDash.Essentials.Fusion // Moved to CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(JoinMap.Display1CurrentSourceName.JoinNumber, JoinMap.Display1CurrentSourceName.AttributeName, eSigIoMask.InputSigOnly); // Don't think we need to get current status of this as nothing should be alive yet. - (Room as EssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange; + (Room as IEssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange; - FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource); - FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey)); + FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as IEssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource); + FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as IEssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey)); CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; @@ -187,7 +187,7 @@ namespace PepperDash.Essentials.Fusion protected override void SetUpSources() { // Sources - var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsHuddleVtc1Room).SourceListKey); + var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as IEssentialsHuddleVtc1Room).SourceListKey); if (dict != null) { // NEW PROCESS: @@ -238,7 +238,7 @@ namespace PepperDash.Essentials.Fusion else { Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'", - (Room as EssentialsHuddleVtc1Room).SourceListKey, Room.Key); + (Room as IEssentialsHuddleVtc1Room).SourceListKey, Room.Key); } } @@ -259,7 +259,7 @@ namespace PepperDash.Essentials.Fusion display.UsageTracker.DeviceUsageEnded += new EventHandler(UsageTracker_DeviceUsageEnded); } - var defaultDisplay = (Room as EssentialsHuddleVtc1Room).DefaultDisplay as DisplayBase; + var defaultDisplay = (Room as IEssentialsHuddleVtc1Room).DefaultDisplay as DisplayBase; if (defaultDisplay == null) { Debug.Console(1, this, "Cannot link null display to Fusion because default display is null"); @@ -332,7 +332,7 @@ namespace PepperDash.Essentials.Fusion string displayName = string.Format("Display {0} - ", displayIndex); - if (display == (Room as EssentialsHuddleVtc1Room).DefaultDisplay) + if (display == (Room as IEssentialsHuddleVtc1Room).DefaultDisplay) { // Power on var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig); @@ -351,7 +351,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 EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ; + defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as IEssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ; } } } diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index e6b12f4e..5e7b5c37 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -17,8 +17,7 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces; namespace PepperDash.Essentials { - public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IHasCurrentSourceInfoChange, - IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback + public class EssentialsHuddleVtc1Room : EssentialsRoomBase, IEssentialsHuddleVtc1Room { private bool _codecExternalSourceChange; public event EventHandler CurrentVolumeDeviceChange; diff --git a/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs index 6feff235..efc126f6 100644 --- a/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs +++ b/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs @@ -8,6 +8,10 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Room.Config; using PepperDash.Essentials.Core.Devices; +using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.VideoCodec; +using PepperDash.Essentials.Devices.Common.AudioCodec; + using PepperDash.Core; @@ -25,4 +29,20 @@ namespace PepperDash.Essentials event EventHandler CurrentVolumeDeviceChange; } + + public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, + IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback + { + EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } + + void RunRouteAction(string routeKey); + + IHasScheduleAwareness ScheduleSource { get; } + + BoolFeedback InCallFeedback { get; } + + BoolFeedback PrivacyModeIsOnFeedback { get; } + + string DefaultCodecRouteString { get; } + } } \ No newline at end of file diff --git a/PepperDashEssentials/UI/EssentialsTouchpanelController.cs b/PepperDashEssentials/UI/EssentialsTouchpanelController.cs index 5c4349fd..7873bf42 100644 --- a/PepperDashEssentials/UI/EssentialsTouchpanelController.cs +++ b/PepperDashEssentials/UI/EssentialsTouchpanelController.cs @@ -270,7 +270,7 @@ namespace PepperDash.Essentials tsw.Down.UserObject = new Action(avDriver.VolumeDownPress); } } - else if (room is EssentialsHuddleVtc1Room) + else if (room is IEssentialsHuddleVtc1Room) { Debug.Console(0, panelController, "Adding huddle space VTC AV driver"); @@ -284,11 +284,11 @@ namespace PepperDash.Essentials var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, props); var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(panelController.Panel, avDriver, - (room as EssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver); + (room as IEssentialsHuddleVtc1Room).VideoCodec, mainDriver.HeaderDriver); avDriver.SetVideoCodecDriver(codecDriver); avDriver.DefaultRoomKey = props.DefaultRoomKey; mainDriver.AvDriver = avDriver; - avDriver.CurrentRoom = room as EssentialsHuddleVtc1Room; + avDriver.CurrentRoom = room as IEssentialsHuddleVtc1Room; // Environment Driver if (avDriver.CurrentRoom.PropertiesConfig.Environment != null && avDriver.CurrentRoom.PropertiesConfig.Environment.DeviceKeys.Count > 0) diff --git a/PepperDashEssentials/UIDrivers/Essentials/EssentialsHeaderDriver.cs b/PepperDashEssentials/UIDrivers/Essentials/EssentialsHeaderDriver.cs index df87c8f4..fa6f67d5 100644 --- a/PepperDashEssentials/UIDrivers/Essentials/EssentialsHeaderDriver.cs +++ b/PepperDashEssentials/UIDrivers/Essentials/EssentialsHeaderDriver.cs @@ -221,7 +221,7 @@ namespace PepperDash.Essentials /// /// Sets up Header Buttons for the EssentialsHuddleVtc1Room type /// - public void SetupHeaderButtons(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, EssentialsHuddleVtc1Room currentRoom) + public void SetupHeaderButtons(EssentialsHuddleVtc1PanelAvFunctionsDriver avDriver, IEssentialsHuddleVtc1Room currentRoom) { HeaderButtonsAreSetUp = false; diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs index a4e88e7e..6280f54e 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddleVTC/EssentialsHuddleVtc1PanelAvFunctionsDriver.cs @@ -50,7 +50,7 @@ namespace PepperDash.Essentials /// /// /// - public EssentialsHuddleVtc1Room CurrentRoom + public IEssentialsHuddleVtc1Room CurrentRoom { get { return _CurrentRoom; } set @@ -58,7 +58,7 @@ namespace PepperDash.Essentials SetCurrentRoom(value); } } - EssentialsHuddleVtc1Room _CurrentRoom; + IEssentialsHuddleVtc1Room _CurrentRoom; /// /// For hitting feedbacks @@ -652,7 +652,7 @@ namespace PepperDash.Essentials if (!CurrentRoom.OnFeedback.BoolValue) { // If there's no default, show UI elements - if (!CurrentRoom.RunDefaultPresentRoute()) + if (!(CurrentRoom as IRunDefaultPresentRoute).RunDefaultPresentRoute()) TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); } } @@ -743,7 +743,7 @@ namespace PepperDash.Essentials void UiSelectSource(string key) { // Run the route and when it calls back, show the source - CurrentRoom.RunRouteAction(key, new Action(() => { })); + CurrentRoom.RunRouteAction(key); } /// @@ -894,7 +894,7 @@ namespace PepperDash.Essentials /// /// Helper for property setter. Sets the panel to the given room, latching up all functionality /// - void RefreshCurrentRoom(EssentialsHuddleVtc1Room room) + void RefreshCurrentRoom(IEssentialsHuddleVtc1Room room) { if (_CurrentRoom != null) @@ -969,7 +969,7 @@ namespace PepperDash.Essentials } } - void SetCurrentRoom(EssentialsHuddleVtc1Room room) + void SetCurrentRoom(IEssentialsHuddleVtc1Room room) { if (_CurrentRoom == room) return; // Disconnect current (probably never called) @@ -1004,7 +1004,7 @@ namespace PepperDash.Essentials UpdateMCJoins(_CurrentRoom); } - void UpdateMCJoins(EssentialsHuddleVtc1Room room) + void UpdateMCJoins(IEssentialsHuddleVtc1Room room) { TriList.SetString(UIStringJoin.RoomMcUrl, room.MobileControlRoomBridge.McServerUrl); TriList.SetString(UIStringJoin.RoomMcQrCodeUrl, room.MobileControlRoomBridge.QrCodeUrl); @@ -1443,7 +1443,7 @@ namespace PepperDash.Essentials /// public interface IAVWithVCDriver : IAVDriver { - EssentialsHuddleVtc1Room CurrentRoom { get; } + IEssentialsHuddleVtc1Room CurrentRoom { get; } PepperDash.Essentials.Core.Touchpanels.Keyboards.HabaneroKeyboardController Keyboard { get; } /// From 4c50d6980fbbe86c53bbf45e7c4ec55f0b02c4c8 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 14 Jul 2021 14:38:18 -0600 Subject: [PATCH 09/37] #740 Adds IPartitionStateProvider interface and adds to GlsParitionSensorController --- .../GlsPartitionSensorController.cs | 2 +- .../PartitionSensor/IPartitionStateProvider.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index b0b58f34..768e476b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -13,7 +13,7 @@ using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { [Description("Wrapper class for GLS Cresnet Partition Sensor")] - public class GlsPartitionSensorController : CrestronGenericBridgeableBaseDevice + public class GlsPartitionSensorController : CrestronGenericBridgeableBaseDevice, IPartitionStateProvider { private GlsPartCn _partitionSensor; diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs new file mode 100644 index 00000000..0080e472 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + /// + /// Describes the functionality of a device that senses and provides partition state + /// + public interface IPartitionStateProvider + { + BoolFeedback PartitionSensedFeedback { get; } + } +} \ No newline at end of file From d97ca6d5a437b8be80b8cca25518de7f16476670 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 14 Jul 2021 14:42:13 -0600 Subject: [PATCH 10/37] #741 Adds EssentialsRoomCombinerPropertiesConfig --- .../PepperDash_Essentials_Core.csproj | 2 + .../EssentialsRoomCombinerPropertiesConfig.cs | 72 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 6e48fd66..7e18606f 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -233,6 +233,7 @@ + @@ -287,6 +288,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs new file mode 100644 index 00000000..5f1adcfa --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core.Room +{ + /// + /// Config properties for an EssentialsRoomCombiner device + /// + public class EssentialsRoomCombinerPropertiesConfig + { + [JsonProperty("partitions")] + public List Partitions {get; set;} + + [JsonProperty("scenarios")] + public List Scenarios { get; set; } + + [JsonProperty("rooms")] + public List Rooms {get; set;} + } + + /// + /// Config properties for a partition that separates rooms + /// + public class PartitionConfig : IKeyName + { + /// + /// Key of the device that implements IPartitionStateProvider to provide the state of the partition + /// + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + /// + /// Keys of the rooms that this partion would be located between + /// + [JsonProperty("roomKeys")] + public List RoomKeys { get; set; } + } + + /// + /// Config propeties for a room combination scenario + /// + public class RoomCombinationScenario : IKeyName + { + [JsonProperty("partitionStates")] + public List PartitionStates { get; set; } + + [JsonProperty("enabledRoomKeys")] + public List EnabledRoomKeys { get; set; } + + [JsonProperty("actions")] + public List Actions { get; set; } + } + + /// + /// Config properties to represent the state of a partition sensor in a RoomCombinationScenario + /// + public class PartitionState + { + [JsonProperty("partitionKey")] + public string PartitionKey { get; set; } + + [JsonProperty("partitionSensedState")] + public bool PartitionSensedState { get; set; } + } +} \ No newline at end of file From 06a3dda2e47983d40d8a278dff60ff7e3f8872e3 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 14 Jul 2021 22:12:41 -0600 Subject: [PATCH 11/37] Starts on interfaces for room combination --- .../IPartitionStateProvider.cs | 13 +++++- .../PepperDash_Essentials_Core.csproj | 2 + .../EssentialsRoomCombinerPropertiesConfig.cs | 21 +++++++--- .../Room/Combining/IEssentialsRoomCombiner.cs | 41 +++++++++++++++++++ .../Room/Combining/RoomCombinationScenario.cs | 17 ++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs index 0080e472..08b8012b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs @@ -4,13 +4,24 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using PepperDash.Core; + namespace PepperDash.Essentials.Core { /// /// Describes the functionality of a device that senses and provides partition state /// - public interface IPartitionStateProvider + public interface IPartitionStateProvider : IKeyName { BoolFeedback PartitionSensedFeedback { get; } } + + public interface IManualPartitionSensor : IPartitionStateProvider + { + void SetPartitionStatePresent(); + + void SetPartitionStateNotPresent(); + + void ToggglePartitionState(); + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 7e18606f..b65cfd62 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -289,6 +289,8 @@ + + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 5f1adcfa..74d5ebda 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -8,21 +8,30 @@ using PepperDash.Core; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.Room +namespace PepperDash.Essentials.Core { /// /// Config properties for an EssentialsRoomCombiner device /// public class EssentialsRoomCombinerPropertiesConfig { + /// + /// The list of partitions that device the rooms + /// [JsonProperty("partitions")] public List Partitions {get; set;} + /// + /// The list of combinations scenarios for the rooms + /// [JsonProperty("scenarios")] - public List Scenarios { get; set; } + public List Scenarios { get; set; } - [JsonProperty("rooms")] - public List Rooms {get; set;} + /// + /// The list of rooms that can be combined + /// + [JsonProperty("roomMap")] + public Dictionary RoomMap {get; set;} } /// @@ -46,7 +55,7 @@ namespace PepperDash.Essentials.Core.Room /// /// Config propeties for a room combination scenario /// - public class RoomCombinationScenario : IKeyName + public class RoomCombinationScenarioConfig : IKeyName { [JsonProperty("partitionStates")] public List PartitionStates { get; set; } @@ -67,6 +76,6 @@ namespace PepperDash.Essentials.Core.Room public string PartitionKey { get; set; } [JsonProperty("partitionSensedState")] - public bool PartitionSensedState { get; set; } + public bool PartitionPresent { get; set; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs new file mode 100644 index 00000000..894dd098 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; + +namespace PepperDash.Essentials.Core +{ + /// + /// Describes the functionality for an EssentailsRoomCombiner device + /// + public interface IEssentialsRoomCombiner + { + // TODO: Update the EventArgs class as needed to specify scenario change + event EventHandler RoomCombinationScenarioChanged; + + BoolFeedback IsInAutoModeFeedback {get;} + + void SetAutoMode(); + + void SetManualMode(); + + void ToggleMode(); + + List Scenarios { get; } + + List Partitions { get; } + + void TogglePartitionState(string partitionKey); + } + + public interface IRoomCombinationScenario : IKeyName + { + BoolFeedback IsActive { get; } + + void Activate(); + } + +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs new file mode 100644 index 00000000..965428cb --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + /// + /// Represents a room combination scenario + /// + public class RoomCombinationScenario: IRoomCombinationScenario + { + + } + +} \ No newline at end of file From 7fd52814a012efb10cfdab442836571a247f0797 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 15 Jul 2021 10:11:27 -0600 Subject: [PATCH 12/37] implements IKeyName as required on config classes --- .../EssentialsRoomCombinerPropertiesConfig.cs | 12 ++++++++++++ .../Room/Combining/RoomCombinationScenario.cs | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 74d5ebda..4576ac4d 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -39,6 +39,12 @@ namespace PepperDash.Essentials.Core /// public class PartitionConfig : IKeyName { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + /// /// Key of the device that implements IPartitionStateProvider to provide the state of the partition /// @@ -57,6 +63,12 @@ namespace PepperDash.Essentials.Core /// public class RoomCombinationScenarioConfig : IKeyName { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("partitionStates")] public List PartitionStates { get; set; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs index 965428cb..94e2ed0a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Core { /// @@ -11,6 +13,18 @@ namespace PepperDash.Essentials.Core /// public class RoomCombinationScenario: IRoomCombinationScenario { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + public BoolFeedback IsActive { get; private set; } + + public void Activate() + { + + } } From c2e5bd290a01675cee4488266f00ef8c90416572 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 15 Jul 2021 16:40:25 -0600 Subject: [PATCH 13/37] #742 Adding EssentialsRoomCombiner device (in progress) --- .../PepperDash_Essentials_Core.csproj | 1 + .../Room/Combining/EssentialsRoomCombiner.cs | 133 ++++++++++++++++++ .../EssentialsRoomCombinerPropertiesConfig.cs | 31 ++-- .../Room/Combining/IEssentialsRoomCombiner.cs | 49 ++++++- .../Room/Combining/RoomCombinationScenario.cs | 58 +++++++- 5 files changed, 257 insertions(+), 15 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index b65cfd62..38a532ba 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -288,6 +288,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs new file mode 100644 index 00000000..6e9a0afb --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner + { + private EssentialsRoomCombinerPropertiesConfig _propertiesConfig; + + private IRoomCombinationScenario _currentScenario; + + private List _rooms; + + private bool isInAutoMode; + + public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props) + : base(key) + { + _propertiesConfig = props; + + IsInAutoModeFeedback = new BoolFeedback(() => isInAutoMode); + + // default to auto mode + isInAutoMode = true; + + if (_propertiesConfig.defaultToManualMode) + { + isInAutoMode = false; + } + + IsInAutoModeFeedback.FireUpdate(); + + CreateScenarios(); + + SetupPartitionStateProviders(); + + SetRooms(); + } + + void CreateScenarios() + { + foreach (var scenarioConfig in _propertiesConfig.Scenarios) + { + var scenario = new RoomCombinationScenario(scenarioConfig); + } + } + + void SetRooms() + { + foreach (var roomKey in _propertiesConfig.RoomKeys) + { + var room = DeviceManager.GetDeviceForKey(roomKey) as IEssentialsRoom; + if (room != null) + { + _rooms.Add(room); + } + } + } + + void SetupPartitionStateProviders() + { + + } + + #region IEssentialsRoomCombiner Members + + public event EventHandler RoomCombinationScenarioChanged; + + public IRoomCombinationScenario CurrentScenario + { + get + { + return _currentScenario; + } + set + { + if (value != _currentScenario) + { + _currentScenario = value; + var handler = RoomCombinationScenarioChanged; + if (handler != null) + { + handler(this, new EventArgs()); + } + } + } + } + + public BoolFeedback IsInAutoModeFeedback { get; private set; } + + public void SetAutoMode() + { + isInAutoMode = true; + IsInAutoModeFeedback.FireUpdate(); + } + + public void SetManualMode() + { + isInAutoMode = false; + IsInAutoModeFeedback.FireUpdate(); + } + + public void ToggleMode() + { + isInAutoMode = !isInAutoMode; + IsInAutoModeFeedback.FireUpdate(); + } + + public List RoomCombinationScenarios { get; private set; } + + public List PartitionStateProviders { get; private set; } + + public void TogglePartitionState(string partitionKey) + { + var partition = PartitionStateProviders.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IManualPartitionSensor; + + if (partition != null) + { + partition.ToggglePartitionState(); + } + } + + public void SetRoomCombinationScenario(string scenarioKey) + { + + } + + #endregion + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 4576ac4d..95b97c35 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -28,10 +28,22 @@ namespace PepperDash.Essentials.Core public List Scenarios { get; set; } /// - /// The list of rooms that can be combined + /// The list of rooms keys that can be combined /// [JsonProperty("roomMap")] - public Dictionary RoomMap {get; set;} + public List RoomKeys {get; set;} + + /// + /// Set to true to default to manual mode + /// + [JsonProperty("defaultToManualMode")] + public bool defaultToManualMode { get; set; } + + /// + /// The key of the scenario to default to at system startup if in manual mode + /// + [JsonProperty("defaultScenarioKey")] + public string defaultScenarioKey { get; set; } } /// @@ -54,8 +66,8 @@ namespace PepperDash.Essentials.Core /// /// Keys of the rooms that this partion would be located between /// - [JsonProperty("roomKeys")] - public List RoomKeys { get; set; } + [JsonProperty("adjacentRoomKeys")] + public List AdjacentRoomKeys { get; set; } } /// @@ -72,11 +84,14 @@ namespace PepperDash.Essentials.Core [JsonProperty("partitionStates")] public List PartitionStates { get; set; } - [JsonProperty("enabledRoomKeys")] - public List EnabledRoomKeys { get; set; } + [JsonProperty("roomMap")] + public Dictionary RoomMap { get; set; } - [JsonProperty("actions")] - public List Actions { get; set; } + [JsonProperty("activationActions")] + public List ActivationActions { get; set; } + + [JsonProperty("deactivationActions")] + public List DeactivationActions { get; set; } } /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs index 894dd098..142e066c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs @@ -13,28 +13,69 @@ namespace PepperDash.Essentials.Core /// public interface IEssentialsRoomCombiner { - // TODO: Update the EventArgs class as needed to specify scenario change + /// + /// Indicates that the room combination scenario has changed + /// event EventHandler RoomCombinationScenarioChanged; + /// + /// The current room combination scenario + /// + IRoomCombinationScenario CurrentScenario { get; } + + /// + /// When true, indicates the current mode is auto mode + /// BoolFeedback IsInAutoModeFeedback {get;} + /// + /// Sets auto mode + /// void SetAutoMode(); + /// + /// Sets manual mode + /// void SetManualMode(); + /// + /// Toggles the current mode between auto and manual + /// void ToggleMode(); - List Scenarios { get; } + /// + /// The available room combinatino scenarios + /// + List RoomCombinationScenarios { get; } - List Partitions { get; } + /// + /// The partition + /// + List PartitionStateProviders { get; } + /// + /// Toggles the state of a manual partition sensor + /// + /// void TogglePartitionState(string partitionKey); + + /// + /// Sets the room combination scenario (if in manual mode) + /// + /// + void SetRoomCombinationScenario(string scenarioKey); } public interface IRoomCombinationScenario : IKeyName { - BoolFeedback IsActive { get; } + /// + /// When true, indicates that this room combination scenario is active + /// + BoolFeedback IsActiveFeedback { get; } + /// + /// Activates this room combination scenario + /// void Activate(); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs index 94e2ed0a..c1d75c3e 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs @@ -13,17 +13,69 @@ namespace PepperDash.Essentials.Core /// public class RoomCombinationScenario: IRoomCombinationScenario { - [JsonProperty("key")] + private RoomCombinationScenarioConfig _config; + public string Key { get; set; } - [JsonProperty("name")] public string Name { get; set; } - public BoolFeedback IsActive { get; private set; } + public List PartitionStates { get; private set; } + + public Dictionary EnabledRoomMap { get; set; } + + private bool _isActive; + + public BoolFeedback IsActiveFeedback { get; private set; } + + List activationActions; + + List deactivationActions; + + public RoomCombinationScenario(RoomCombinationScenarioConfig config) + { + Key = config.Key; + + Name = config.Name; + + PartitionStates = config.PartitionStates; + + EnabledRoomMap = config.RoomMap; + + activationActions = config.ActivationActions; + + deactivationActions = config.DeactivationActions; + + _config = config; + + IsActiveFeedback = new BoolFeedback(() => _isActive); + } public void Activate() { + if (activationActions != null) + { + foreach (var action in activationActions) + { + DeviceJsonApi.DoDeviceAction(action); + } + } + _isActive = true; + IsActiveFeedback.FireUpdate(); + } + + public void Deactivate() + { + if (deactivationActions != null) + { + foreach (var action in deactivationActions) + { + DeviceJsonApi.DoDeviceAction(action); + } + } + + _isActive = false; + IsActiveFeedback.FireUpdate(); } } From e3920132bfa5acbd0b6c00ba9fd7458dc3d32f73 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 14:11:27 -0600 Subject: [PATCH 14/37] #743 Adds SetValueFunc() to all Feedback types --- .../PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs | 5 +++++ .../PepperDashEssentialsBase/Feedbacks/IntFeedback.cs | 6 ++++++ .../PepperDashEssentialsBase/Feedbacks/StringFeedback.cs | 5 ++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs index f46b4767..055ed5b6 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs @@ -62,6 +62,11 @@ namespace PepperDash.Essentials.Core ValueFunc = valueFunc; } + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } + public override void FireUpdate() { bool newValue = InTestMode ? TestValue : ValueFunc.Invoke(); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/IntFeedback.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/IntFeedback.cs index 25390c2c..53bae09a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/IntFeedback.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/IntFeedback.cs @@ -51,6 +51,12 @@ namespace PepperDash.Essentials.Core ValueFunc = valueFunc; } + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } + + public override void FireUpdate() { var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/StringFeedback.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/StringFeedback.cs index 56251a2e..fb5cccb5 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/StringFeedback.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/StringFeedback.cs @@ -52,7 +52,10 @@ namespace PepperDash.Essentials.Core ValueFunc = valueFunc; } - + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } public override void FireUpdate() { From 7b7ec533558ee74d93b13f6b035ffa65d2ecce9e Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 15:35:52 -0600 Subject: [PATCH 15/37] #742 Updates to room combination interfaces and EssentialsRoomCombiner and EssentialsPartitionController --- .../EssentialsPartitionController.cs | 149 ++++++++++++++++++ .../GlsPartitionSensorController.cs | 10 +- .../IPartitionStateProvider.cs | 13 +- .../PepperDash_Essentials_Core.csproj | 1 + .../Room/Combining/EssentialsRoomCombiner.cs | 38 ++++- .../EssentialsRoomCombinerPropertiesConfig.cs | 4 +- .../Room/Combining/IEssentialsRoomCombiner.cs | 14 +- .../Room/Combining/RoomCombinationScenario.cs | 4 +- 8 files changed, 218 insertions(+), 15 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/EssentialsPartitionController.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/EssentialsPartitionController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/EssentialsPartitionController.cs new file mode 100644 index 00000000..7066be0e --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/EssentialsPartitionController.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + /// + /// Represents an abstract controller device for a partition dividing rooms that are combinable + /// + /// In Auto mode, it can use a partition sensor to automatically determine whether the partition is present. + /// + /// In Manual mode it accepts user input to tell it whether the partition is present. + /// + public class EssentialsPartitionController : IPartitionController + { + private IPartitionStateProvider _partitionSensor; + + private bool isInAutoMode; + + private bool partitionPresent; + + public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List adjacentRoomKeys) + { + Key = key; + + Name = name; + + AdjacentRoomKeys = adjacentRoomKeys; + + if (sensor != null) + { + _partitionSensor = sensor; + + if (!defaultToManualMode) + { + SetAutoMode(); + } + else + { + SetManualMode(); + } + } + else + { + SetManualMode(); + } + + PartitionPresentFeedback.FireUpdate(); + } + + void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + if (isInAutoMode) + { + PartitionPresentFeedback.FireUpdate(); + } + } + + #region IPartitionController Members + + public List AdjacentRoomKeys { get; private set; } + + public void SetAutoMode() + { + isInAutoMode = true; + if (PartitionPresentFeedback != null) + { + PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue); + } + else + { + PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionPresentFeedback.BoolValue); + } + + if (_partitionSensor != null) + { + _partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; + } + } + + public void SetManualMode() + { + isInAutoMode = false; + if (PartitionPresentFeedback != null) + { + PartitionPresentFeedback.SetValueFunc(() => partitionPresent); + } + else + { + PartitionPresentFeedback = new BoolFeedback(() => partitionPresent); + } + + if (_partitionSensor != null) + { + _partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange; + } + } + + + public void SetPartitionStatePresent() + { + if (!isInAutoMode) + { + partitionPresent = true; + PartitionPresentFeedback.FireUpdate(); + } + } + + public void SetPartitionStateNotPresent() + { + if (!isInAutoMode) + { + partitionPresent = false; + PartitionPresentFeedback.FireUpdate(); + } + } + + public void ToggglePartitionState() + { + if (!isInAutoMode) + { + partitionPresent = !partitionPresent; + PartitionPresentFeedback.FireUpdate(); + } + } + + #endregion + + #region IPartitionStateProvider Members + + public BoolFeedback PartitionPresentFeedback { get; private set; } + + #endregion + + #region IKeyName Members + + public string Name { get; private set; } + + #endregion + + #region IKeyed Members + + public string Key { get; private set; } + + #endregion + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index 768e476b..752a7107 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Core public StringFeedback NameFeedback { get; private set; } public BoolFeedback EnableFeedback { get; private set; } - public BoolFeedback PartitionSensedFeedback { get; private set; } + public BoolFeedback PartitionPresentFeedback { get; private set; } public BoolFeedback PartitionNotSensedFeedback { get; private set; } public IntFeedback SensitivityFeedback { get; private set; } @@ -40,7 +40,7 @@ namespace PepperDash.Essentials.Core NameFeedback = new StringFeedback(() => Name); EnableFeedback = new BoolFeedback(() => _partitionSensor.EnableFeedback.BoolValue); - PartitionSensedFeedback = new BoolFeedback(() => _partitionSensor.PartitionSensedFeedback.BoolValue); + PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionSensedFeedback.BoolValue); PartitionNotSensedFeedback = new BoolFeedback(() => _partitionSensor.PartitionNotSensedFeedback.BoolValue); SensitivityFeedback = new IntFeedback(() => _partitionSensor.SensitivityFeedback.UShortValue); @@ -61,7 +61,7 @@ namespace PepperDash.Essentials.Core } case (GlsPartCn.PartitionSensedFeedbackEventId): { - PartitionSensedFeedback.FireUpdate(); + PartitionPresentFeedback.FireUpdate(); break; } case (GlsPartCn.PartitionNotSensedFeedbackEventId): @@ -186,7 +186,7 @@ namespace PepperDash.Essentials.Core // link output to simpl IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); EnableFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Enable.JoinNumber]); - PartitionSensedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionSensed.JoinNumber]); + PartitionPresentFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionSensed.JoinNumber]); PartitionNotSensedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionNotSensed.JoinNumber]); SensitivityFeedback.LinkInputSig(trilist.UShortInput[joinMap.Sensitivity.JoinNumber]); @@ -216,7 +216,7 @@ namespace PepperDash.Essentials.Core IsOnline.FireUpdate(); NameFeedback.FireUpdate(); EnableFeedback.FireUpdate(); - PartitionSensedFeedback.FireUpdate(); + PartitionPresentFeedback.FireUpdate(); PartitionNotSensedFeedback.FireUpdate(); SensitivityFeedback.FireUpdate(); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs index 08b8012b..faf84015 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs @@ -13,15 +13,24 @@ namespace PepperDash.Essentials.Core /// public interface IPartitionStateProvider : IKeyName { - BoolFeedback PartitionSensedFeedback { get; } + BoolFeedback PartitionPresentFeedback { get; } } - public interface IManualPartitionSensor : IPartitionStateProvider + /// + /// Describes the functionality of a device that can provide partition state either manually via user input or optionally via a sensor state + /// + public interface IPartitionController : IPartitionStateProvider { + List AdjacentRoomKeys { get; set; } + void SetPartitionStatePresent(); void SetPartitionStateNotPresent(); void ToggglePartitionState(); + + void SetManualMode(); + + void SetAutoMode(); } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 38a532ba..53779a0d 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -233,6 +233,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs index 6e9a0afb..bb3040ff 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -42,14 +42,19 @@ namespace PepperDash.Essentials.Core void CreateScenarios() { + RoomCombinationScenarios = new List(); + foreach (var scenarioConfig in _propertiesConfig.Scenarios) { var scenario = new RoomCombinationScenario(scenarioConfig); + RoomCombinationScenarios.Add(scenario); } } void SetRooms() { + _rooms = new List(); + foreach (var roomKey in _propertiesConfig.RoomKeys) { var room = DeviceManager.GetDeviceForKey(roomKey) as IEssentialsRoom; @@ -62,7 +67,36 @@ namespace PepperDash.Essentials.Core void SetupPartitionStateProviders() { + foreach (var pConfig in _propertiesConfig.Partitions) + { + var sensor = DeviceManager.GetDeviceForKey(pConfig.DeviceKey) as IPartitionStateProvider; + var partition = new EssentialsPartitionController(pConfig.Key, pConfig.Name, sensor, _propertiesConfig.defaultToManualMode, pConfig.AdjacentRoomKeys); + + partition.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; + + Partitions.Add(partition); + } + } + + void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + DetermineRoomCombinationScenario(); + } + + + /// + /// Determines the current room combination scenario based on the state of the partition sensors + /// + void DetermineRoomCombinationScenario() + { + //RoomCombinationScenarios.FirstOrDefault((s) => + //{ + // foreach (var partitionState in s.PartitionStates) + // { + // var partition = Partitions.FirstOrDefault( + // } + //}); } #region IEssentialsRoomCombiner Members @@ -111,11 +145,11 @@ namespace PepperDash.Essentials.Core public List RoomCombinationScenarios { get; private set; } - public List PartitionStateProviders { get; private set; } + public List Partitions { get; private set; } public void TogglePartitionState(string partitionKey) { - var partition = PartitionStateProviders.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IManualPartitionSensor; + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IPartitionController; if (partition != null) { diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 95b97c35..7fa215d5 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -84,8 +84,8 @@ namespace PepperDash.Essentials.Core [JsonProperty("partitionStates")] public List PartitionStates { get; set; } - [JsonProperty("roomMap")] - public Dictionary RoomMap { get; set; } + [JsonProperty("uiMap")] + public Dictionary UiMap { get; set; } [JsonProperty("activationActions")] public List ActivationActions { get; set; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs index 142e066c..c5fa0c50 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs @@ -11,7 +11,7 @@ namespace PepperDash.Essentials.Core /// /// Describes the functionality for an EssentailsRoomCombiner device /// - public interface IEssentialsRoomCombiner + public interface IEssentialsRoomCombiner : IKeyed { /// /// Indicates that the room combination scenario has changed @@ -51,7 +51,7 @@ namespace PepperDash.Essentials.Core /// /// The partition /// - List PartitionStateProviders { get; } + List Partitions { get; } /// /// Toggles the state of a manual partition sensor @@ -77,6 +77,16 @@ namespace PepperDash.Essentials.Core /// Activates this room combination scenario /// void Activate(); + + /// + /// The state of the partitions that would activate this scenario + /// + List PartitionStates { get; } + + /// + /// The mapping of UIs by key to rooms by key + /// + Dictionary UiMap { get; set; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs index c1d75c3e..a5534edc 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs @@ -21,7 +21,7 @@ namespace PepperDash.Essentials.Core public List PartitionStates { get; private set; } - public Dictionary EnabledRoomMap { get; set; } + public Dictionary UiMap { get; set; } private bool _isActive; @@ -39,7 +39,7 @@ namespace PepperDash.Essentials.Core PartitionStates = config.PartitionStates; - EnabledRoomMap = config.RoomMap; + UiMap = config.UiMap; activationActions = config.ActivationActions; From 6f6ca50c373e2e3327f7ad48f30f7b188575f454 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 15:36:59 -0600 Subject: [PATCH 16/37] Removes set from interface --- .../PartitionSensor/IPartitionStateProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs index faf84015..adb420b7 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs @@ -21,7 +21,7 @@ namespace PepperDash.Essentials.Core /// public interface IPartitionController : IPartitionStateProvider { - List AdjacentRoomKeys { get; set; } + List AdjacentRoomKeys { get; } void SetPartitionStatePresent(); From 9795637d755a80a16ee6b0ce55029d84e88b6b9a Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 16:09:38 -0600 Subject: [PATCH 17/37] #742 EssentialsRoomCombiner substantially complete. Adds debounce timer when changing scenarios --- .../Room/Combining/EssentialsRoomCombiner.cs | 97 +++++++++++++++++-- .../EssentialsRoomCombinerPropertiesConfig.cs | 3 + 2 files changed, 91 insertions(+), 9 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs index bb3040ff..cbbb58d1 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using PepperDash.Core; + namespace PepperDash.Essentials.Core { public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner @@ -16,11 +18,20 @@ namespace PepperDash.Essentials.Core private bool isInAutoMode; + private CTimer _scenarioChangeDebounceTimer; + + private int _scenarioChangeDebounceTimeSeconds = 10; // default to 10s + public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props) : base(key) { _propertiesConfig = props; + if (_propertiesConfig.ScenarioChangeDebounceTimeSeconds > 0) + { + _scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds; + } + IsInAutoModeFeedback = new BoolFeedback(() => isInAutoMode); // default to auto mode @@ -81,22 +92,61 @@ namespace PepperDash.Essentials.Core void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) { - DetermineRoomCombinationScenario(); + StartDebounceTimer(); } + void StartDebounceTimer() + { + var time = _scenarioChangeDebounceTimeSeconds * 1000; + + if (_scenarioChangeDebounceTimer == null) + { + _scenarioChangeDebounceTimer = new CTimer((o) => DetermineRoomCombinationScenario(), time); + } + else + { + _scenarioChangeDebounceTimer.Reset(time); + } + } /// /// Determines the current room combination scenario based on the state of the partition sensors /// void DetermineRoomCombinationScenario() { - //RoomCombinationScenarios.FirstOrDefault((s) => - //{ - // foreach (var partitionState in s.PartitionStates) - // { - // var partition = Partitions.FirstOrDefault( - // } - //}); + if (_scenarioChangeDebounceTimer != null) + { + _scenarioChangeDebounceTimer.Dispose(); + _scenarioChangeDebounceTimer = null; + } + + var currentScenario = RoomCombinationScenarios.FirstOrDefault((s) => + { + // iterate the partition states + foreach (var partitionState in s.PartitionStates) + { + // get the partition by key + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); + + if (partition != null && partitionState.PartitionPresent != partition.PartitionPresentFeedback.BoolValue) + { + // the partition can't be found or the state doesn't match + return false; + } + else + { + // check the next partition state + continue; + } + } + // if it hasn't returned false by now we have the matching scenario + return true; + }); + + if (currentScenario != null) + { + CurrentScenario = currentScenario; + } } #region IEssentialsRoomCombiner Members @@ -114,6 +164,7 @@ namespace PepperDash.Essentials.Core if (value != _currentScenario) { _currentScenario = value; + Debug.Console(1, this, "Current Scenario: {0}", _currentScenario.Name); var handler = RoomCombinationScenarioChanged; if (handler != null) { @@ -145,7 +196,7 @@ namespace PepperDash.Essentials.Core public List RoomCombinationScenarios { get; private set; } - public List Partitions { get; private set; } + public List Partitions { get; private set; } public void TogglePartitionState(string partitionKey) { @@ -159,7 +210,35 @@ namespace PepperDash.Essentials.Core public void SetRoomCombinationScenario(string scenarioKey) { + if (isInAutoMode) + { + Debug.Console(0, this, "Cannot set room combination scenario when in auto mode. Set to auto mode first."); + return; + } + // Get the scenario + var scenario = RoomCombinationScenarios.FirstOrDefault((s) => s.Key.Equals(scenarioKey)); + + // Set the parition states from the scenario manually + if (scenario != null) + { + foreach (var partitionState in scenario.PartitionStates) + { + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); + + if (partition != null) + { + if (partitionState.PartitionPresent) + { + partition.SetPartitionStatePresent(); + } + else + { + partition.SetPartitionStateNotPresent(); + } + } + } + } } #endregion diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 7fa215d5..05295f42 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -44,6 +44,9 @@ namespace PepperDash.Essentials.Core /// [JsonProperty("defaultScenarioKey")] public string defaultScenarioKey { get; set; } + + [JsonProperty("scenarioChangeDebounceTimeSeconds")] + public int ScenarioChangeDebounceTimeSeconds { get; set; } } /// From 377cccf912e9dd963545df32e1a02afcbe0bd8af Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 16:10:06 -0600 Subject: [PATCH 18/37] Updates type for Partitions on IEssentialsRoomController --- .../Room/Combining/IEssentialsRoomCombiner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs index c5fa0c50..c0c8101b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs @@ -51,7 +51,7 @@ namespace PepperDash.Essentials.Core /// /// The partition /// - List Partitions { get; } + List Partitions { get; } /// /// Toggles the state of a manual partition sensor From 990090e1dec396f22fc10bc23f5d30d26f1d4c2a Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 19 Jul 2021 10:29:30 -0600 Subject: [PATCH 19/37] feat: Add support for C2N-IO --- .../Crestron IO/C2nIo/C2nIoController.cs | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/C2nIo/C2nIoController.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/C2nIo/C2nIoController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/C2nIo/C2nIoController.cs new file mode 100644 index 00000000..0b70288f --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/C2nIo/C2nIoController.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.GeneralIO; +using PepperDash.Core; +using PepperDash.Essentials.Core.Bridges; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials.Core.CrestronIO +{ + public class C2NIoController:CrestronGenericBaseDevice, IComPorts, IIROutputPorts, IRelayPorts + { + private C2nIo _device; + + public C2NIoController(string key, Func preActivationFunc, DeviceConfig config):base(key, config.Name) + { + AddPreActivationAction(() => + { + _device = preActivationFunc(config); + + RegisterCrestronGenericBase(_device); + }); + } + + #region Implementation of IComPorts + + public CrestronCollection ComPorts + { + get { return _device.ComPorts; } + } + + public int NumberOfComPorts + { + get { return _device.NumberOfComPorts; } + } + + #endregion + + #region Implementation of IIROutputPorts + + public CrestronCollection IROutputPorts + { + get { return _device.IROutputPorts; } + } + + public int NumberOfIROutputPorts + { + get { return _device.NumberOfIROutputPorts; } + } + + #endregion + + #region Implementation of IRelayPorts + + public CrestronCollection RelayPorts + { + get { return _device.RelayPorts; } + } + + public int NumberOfRelayPorts + { + get { return _device.NumberOfRelayPorts; } + } + + #endregion + } + + public class C2NIoControllerFactory : EssentialsDeviceFactory + { + public C2NIoControllerFactory() + { + TypeNames = new List() { "c2nio" }; + } + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new C2N-IO Device"); + + return new C2NIoController(dc.Key, GetC2NIoDevice, dc); + } + + static C2nIo GetC2NIoDevice(DeviceConfig dc) + { + var control = CommFactory.GetControlPropertiesConfig(dc); + var cresnetId = control.CresnetIdInt; + var branchId = control.ControlPortNumber; + var parentKey = string.IsNullOrEmpty(control.ControlPortDevKey) ? "processor" : control.ControlPortDevKey; + + if (parentKey.Equals("processor", StringComparison.CurrentCultureIgnoreCase)) + { + Debug.Console(0, "Device {0} is a valid cresnet master - creating new C2nIo", parentKey); + return new C2nIo(cresnetId, Global.ControlSystem); + } + var cresnetBridge = DeviceManager.GetDeviceForKey(parentKey) as IHasCresnetBranches; + + if (cresnetBridge != null) + { + Debug.Console(0, "Device {0} is a valid cresnet master - creating new C2nIo", parentKey); + return new C2nIo(cresnetId, cresnetBridge.CresnetBranches[branchId]); + } + Debug.Console(0, "Device {0} is not a valid cresnet master", parentKey); + return null; + } + } +} \ No newline at end of file From 6946946c12e3b23710b85996fd267b54c7171481 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 19 Jul 2021 13:47:17 -0600 Subject: [PATCH 20/37] chore: Add c2nIoController to csproj --- .../PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 6e48fd66..3919d331 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -162,6 +162,7 @@ + From 760ec8be924285a39398fef908bd8b681b7495bb Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 19 Jul 2021 14:08:23 -0600 Subject: [PATCH 21/37] feat: Add occupancy aggregator factory and config --- .../IOccupancyStatusProviderAggregator.cs | 44 ++++++++++++++++--- .../Occupancy/OccupancyAggregatorConfig.cs | 15 +++++++ .../PepperDash_Essentials_Core.csproj | 1 + 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs index c321dcad..601edf67 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs @@ -2,17 +2,18 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Crestron.SimplSharp; - +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.GeneralIO; using PepperDash.Core; using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { /// /// Aggregates the RoomIsOccupied feedbacks of one or more IOccupancyStatusProvider objects /// - public class IOccupancyStatusProviderAggregator : Device, IOccupancyStatusProvider + public class IOccupancyStatusProviderAggregator : EssentialsDevice, IOccupancyStatusProvider { /// /// Aggregated feedback of all linked IOccupancyStatusProvider devices @@ -21,16 +22,22 @@ namespace PepperDash.Essentials.Core { get { - return AggregatedOccupancyStatus.Output; + return _aggregatedOccupancyStatus.Output; } } - private BoolFeedbackOr AggregatedOccupancyStatus; + private readonly BoolFeedbackOr _aggregatedOccupancyStatus; public IOccupancyStatusProviderAggregator(string key, string name) : base(key, name) { - AggregatedOccupancyStatus = new BoolFeedbackOr(); + _aggregatedOccupancyStatus = new BoolFeedbackOr(); + } + + public IOccupancyStatusProviderAggregator(string key, string name, OccupancyAggregatorConfig config) + : this(dc.Key, dc.Name) + { + } /// @@ -39,7 +46,30 @@ namespace PepperDash.Essentials.Core /// public void AddOccupancyStatusProvider(IOccupancyStatusProvider statusProvider) { - AggregatedOccupancyStatus.AddOutputIn(statusProvider.RoomIsOccupiedFeedback); + _aggregatedOccupancyStatus.AddOutputIn(statusProvider.RoomIsOccupiedFeedback); + } + + public void RemoveOccupancyStatusProvider(IOccupancyStatusProvider statusProvider) + { + _aggregatedOccupancyStatus.RemoveOutputIn(statusProvider.RoomIsOccupiedFeedback); } + } + + public class OccupancyAggregatorFactory : EssentialsDeviceFactory + { + public OccupancyAggregatorFactory() + { + TypeNames = new List { "glsodtccn" }; + } + + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new GlsOccupancySensorBaseController Device"); + + var config = dc.Properties.ToObject(); + + return new IOccupancyStatusProviderAggregator(dc.Key, dc.Name, config); + } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs new file mode 100644 index 00000000..7909de04 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core +{ + public class OccupancyAggregatorConfig + { + [JsonProperty("deviceKeys")] public List DeviceKeys { get; set; } + + OccupancyAggregatorConfig() + { + DeviceKeys = new List(); + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 3919d331..36992629 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -234,6 +234,7 @@ + From 9128e108f78eb671756228108e2b67fb3449744d Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 19 Jul 2021 15:09:03 -0600 Subject: [PATCH 22/37] feat: Add clear method to BoolOutputLogical and do a bit of refactoring --- .../Feedbacks/BoolOutputLogicals.cs | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolOutputLogicals.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolOutputLogicals.cs index 3074254e..a8dae7b8 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolOutputLogicals.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolOutputLogicals.cs @@ -23,7 +23,7 @@ namespace PepperDash.Essentials.Core protected bool ComputedValue; - public BoolFeedbackLogic() + protected BoolFeedbackLogic() { Output = new BoolFeedback(() => ComputedValue); } @@ -40,21 +40,18 @@ namespace PepperDash.Essentials.Core public void AddOutputsIn(List outputs) { - foreach (var o in outputs) - { - // skip existing - if (OutputsIn.Contains(o)) continue; - - OutputsIn.Add(o); - o.OutputChange += AnyInput_OutputChange; - } - Evaluate(); + foreach (var o in outputs.Where(o => !OutputsIn.Contains(o))) + { + OutputsIn.Add(o); + o.OutputChange += AnyInput_OutputChange; + } + Evaluate(); } - public void RemoveOutputIn(BoolFeedback output) + public void RemoveOutputIn(BoolFeedback output) { // Don't double up outputs - if (OutputsIn.Contains(output)) return; + if (!OutputsIn.Contains(output)) return; OutputsIn.Remove(output); output.OutputChange -= AnyInput_OutputChange; @@ -71,6 +68,12 @@ namespace PepperDash.Essentials.Core Evaluate(); } + public void ClearOutputs() + { + OutputsIn.Clear(); + Evaluate(); + } + void AnyInput_OutputChange(object sender, EventArgs e) { Evaluate(); @@ -85,11 +88,12 @@ namespace PepperDash.Essentials.Core { var prevValue = ComputedValue; var newValue = OutputsIn.All(o => o.BoolValue); - if (newValue != prevValue) - { - ComputedValue = newValue; - Output.FireUpdate(); - } + if (newValue == prevValue) + { + return; + } + ComputedValue = newValue; + Output.FireUpdate(); } } @@ -99,33 +103,35 @@ namespace PepperDash.Essentials.Core { var prevValue = ComputedValue; var newValue = OutputsIn.Any(o => o.BoolValue); - if (newValue != prevValue) - { - ComputedValue = newValue; - Output.FireUpdate(); - } + if (newValue == prevValue) + { + return; + } + ComputedValue = newValue; + Output.FireUpdate(); } } public class BoolFeedbackLinq : BoolFeedbackLogic { - Func, bool> Predicate; + readonly Func, bool> _predicate; public BoolFeedbackLinq(Func, bool> predicate) : base() { - Predicate = predicate; + _predicate = predicate; } protected override void Evaluate() { var prevValue = ComputedValue; - var newValue = Predicate(OutputsIn); - if (newValue != prevValue) - { - ComputedValue = newValue; - Output.FireUpdate(); - } + var newValue = _predicate(OutputsIn); + if (newValue == prevValue) + { + return; + } + ComputedValue = newValue; + Output.FireUpdate(); } } } \ No newline at end of file From 10129b81782513de98f5cd8ab271c01affc4b25c Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 19 Jul 2021 15:09:37 -0600 Subject: [PATCH 23/37] feat: Add post activation action for aggregator --- .../IOccupancyStatusProviderAggregator.cs | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs index 601edf67..3da9c0dc 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs @@ -35,9 +35,38 @@ namespace PepperDash.Essentials.Core } public IOccupancyStatusProviderAggregator(string key, string name, OccupancyAggregatorConfig config) - : this(dc.Key, dc.Name) + : this(key, name) { - + AddPostActivationAction(() => + { + if (config.DeviceKeys.Count == 0) + { + return; + } + + foreach (var deviceKey in config.DeviceKeys) + { + var device = DeviceManager.GetDeviceForKey(deviceKey); + + if (device == null) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, + "Unable to retrieve Occupancy provider with key {0}", deviceKey); + continue; + } + + var provider = device as IOccupancyStatusProvider; + + if (provider == null) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, + "Device with key {0} does NOT implement IOccupancyStatusProvider. Please check configuration."); + continue; + } + + AddOccupancyStatusProvider(provider); + } + }); } /// @@ -52,6 +81,11 @@ namespace PepperDash.Essentials.Core public void RemoveOccupancyStatusProvider(IOccupancyStatusProvider statusProvider) { _aggregatedOccupancyStatus.RemoveOutputIn(statusProvider.RoomIsOccupiedFeedback); + } + + public void ClearOccupancyStatusProviders() + { + _aggregatedOccupancyStatus.ClearOutputs(); } } @@ -59,7 +93,7 @@ namespace PepperDash.Essentials.Core { public OccupancyAggregatorFactory() { - TypeNames = new List { "glsodtccn" }; + TypeNames = new List { "occupancyAggregator", "occAggregate" }; } From 45e6dff26d71e1b560845d3ba58e62b631bd52ee Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 19 Jul 2021 15:10:03 -0600 Subject: [PATCH 24/37] fix: update access level for config constructor --- .../Occupancy/OccupancyAggregatorConfig.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs index 7909de04..ef237e72 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs @@ -7,7 +7,7 @@ namespace PepperDash.Essentials.Core { [JsonProperty("deviceKeys")] public List DeviceKeys { get; set; } - OccupancyAggregatorConfig() + public OccupancyAggregatorConfig() { DeviceKeys = new List(); } From dfaaa3f6bc68b89b6e7711b68ca8149b74546123 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 19 Jul 2021 15:41:10 -0600 Subject: [PATCH 25/37] #742 Adds factory for EssentialsRoomCombiner --- .../PepperDashEssentials.csproj | 3 +- .../Room/Types/IEssentialsHuddleSpaceRoom.cs | 48 -- .../Interfaces/IEssentialsHuddleSpaceRoom.cs | 24 + .../Interfaces/IEssentialsHuddleVtc1Room.cs | 25 + .../EssentialsHuddleTechPageDriver.cs | 648 +++++++++--------- .../GlsPartitionSensorController.cs | 2 +- .../Room/Combining/EssentialsRoomCombiner.cs | 24 +- 7 files changed, 398 insertions(+), 376 deletions(-) delete mode 100644 PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs create mode 100644 PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleSpaceRoom.cs create mode 100644 PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 14bd450a..d172076a 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -149,7 +149,8 @@ - + + diff --git a/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs deleted file mode 100644 index efc126f6..00000000 --- a/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using PepperDash.Essentials.Room.Config; -using PepperDash.Essentials.Core.Devices; -using PepperDash.Essentials.Devices.Common.Codec; -using PepperDash.Essentials.Devices.Common.VideoCodec; -using PepperDash.Essentials.Devices.Common.AudioCodec; - - -using PepperDash.Core; - -namespace PepperDash.Essentials -{ - public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay - { - bool ExcludeFromGlobalFunctions { get; } - - void RunRouteAction(string routeKey); - - EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } - - IBasicVolumeControls CurrentVolumeControls { get; } - - event EventHandler CurrentVolumeDeviceChange; - } - - public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, - IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback - { - EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } - - void RunRouteAction(string routeKey); - - IHasScheduleAwareness ScheduleSource { get; } - - BoolFeedback InCallFeedback { get; } - - BoolFeedback PrivacyModeIsOnFeedback { get; } - - string DefaultCodecRouteString { get; } - } -} \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleSpaceRoom.cs new file mode 100644 index 00000000..c7f68e8b --- /dev/null +++ b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleSpaceRoom.cs @@ -0,0 +1,24 @@ +using System; + +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Room.Config; + + + +namespace PepperDash.Essentials +{ + public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay + { + bool ExcludeFromGlobalFunctions { get; } + + void RunRouteAction(string routeKey); + + EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } + + IBasicVolumeControls CurrentVolumeControls { get; } + + event EventHandler CurrentVolumeDeviceChange; + } + + +} \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs new file mode 100644 index 00000000..662988a1 --- /dev/null +++ b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs @@ -0,0 +1,25 @@ + +using PepperDash.Essentials.Core; +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 +{ + public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, + IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback + { + EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } + + void RunRouteAction(string routeKey); + + IHasScheduleAwareness ScheduleSource { get; } + + BoolFeedback InCallFeedback { get; } + + BoolFeedback PrivacyModeIsOnFeedback { get; } + + string DefaultCodecRouteString { get; } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddleTechPageDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddleTechPageDriver.cs index b8e1dfd6..776e1034 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddleTechPageDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddleTechPageDriver.cs @@ -1,326 +1,326 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.DeviceSupport; - -using PepperDash.Core; -using PepperDash.Essentials; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.DeviceSupport; + +using PepperDash.Core; +using PepperDash.Essentials; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.SmartObjects; -using PepperDash.Essentials.Core.Touchpanels.Keyboards; -using PepperDash.Essentials.Devices.Displays; -using PepperDash.Essentials.Room.Config; - -namespace PepperDash.Essentials.UIDrivers -{ - public class EssentialsHuddleTechPageDriver : PanelDriverBase - { - /// - /// - /// - SmartObjectDynamicList MenuList; - /// - /// - /// - SubpageReferenceList StatusList; - /// - /// The list of display controls - /// - SubpageReferenceList DisplayList; - /// - /// References lines in the list against device instances - /// - Dictionary StatusListDeviceIndexes; - /// - /// - /// - JoinedSigInterlock PagesInterlock; - - /// - /// 1 - /// - public const uint JoinText = 1; - - CTimer PinAuthorizedTimer; - - EssentialsRoomTechConfig Config; - - StringBuilder PinEntryBuilder = new StringBuilder(4); - - bool IsAuthorized; - - SmartObjectNumeric PinKeypad; - - /// - /// - /// - /// - /// - public EssentialsHuddleTechPageDriver(BasicTriListWithSmartObject trilist, EssentialsRoomTechConfig config) - : base(trilist) - { - Config = config; - - PagesInterlock = new JoinedSigInterlock(trilist); - PagesInterlock.SetButDontShow(UIBoolJoin.TechSystemStatusVisible); - - trilist.SetSigFalseAction(UIBoolJoin.TechExitButton, Hide); - - MenuList = new SmartObjectDynamicList(trilist.SmartObjects[UISmartObjectJoin.TechMenuList], - true, 3100); - - MenuList.SetFeedback(1, true); // initial fb - ushort count = 0; - - MenuList.SetItemMainText(1, "System Status"); - MenuList.SetItemButtonAction(1, b => { - if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechSystemStatusVisible); - MenuList.SetFeedback(1, true); - }); - - MenuList.SetItemMainText(2, "Display Controls"); - MenuList.SetItemButtonAction(2, b => { - if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechDisplayControlsVisible); - MenuList.SetFeedback(2, true); - }); - - count = 2; - - // Don't show panel setup on iPad or xpanel - if (TriList is Crestron.SimplSharpPro.DeviceSupport.TswFt5Button) - { - count++; - MenuList.SetItemMainText(count, "Panel Setup"); - MenuList.SetItemButtonAction(count, b => - { - if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechPanelSetupVisible); - MenuList.SetFeedback(count, true); - }); - } - - MenuList.Count = count; - BuildStatusList(); - BuildDisplayList(); - SetupPinModal(); - } - - /// - /// - /// - public override void Show() - { - // divert to PIN if we need auth - if (IsAuthorized) - { - // Cancel the auth timer so we don't deauth after coming back in - if (PinAuthorizedTimer != null) - PinAuthorizedTimer.Stop(); - - TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, true); - PagesInterlock.Show(); - base.Show(); - } - else - { - TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, true); - } - } - - /// - /// - /// - public override void Hide() - { - // Leave it authorized for 60 seconds. - if (IsAuthorized) - PinAuthorizedTimer = new CTimer(o => { - IsAuthorized = false; - PinAuthorizedTimer = null; - }, 60000); - TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, false); - PagesInterlock.Hide(); - base.Hide(); - } - - /// - /// Wire up the keypad and buttons - /// - void SetupPinModal() - { - TriList.SetSigFalseAction(UIBoolJoin.PinDialogCancelPress, CancelPinDialog); - PinKeypad = new SmartObjectNumeric(TriList.SmartObjects[UISmartObjectJoin.TechPinDialogKeypad], true); - PinKeypad.Digit0.UserObject = new Action(b => { if (b)DialPinDigit('0'); }); - PinKeypad.Digit1.UserObject = new Action(b => { if (b)DialPinDigit('1'); }); - PinKeypad.Digit2.UserObject = new Action(b => { if (b)DialPinDigit('2'); }); - PinKeypad.Digit3.UserObject = new Action(b => { if (b)DialPinDigit('3'); }); - PinKeypad.Digit4.UserObject = new Action(b => { if (b)DialPinDigit('4'); }); - PinKeypad.Digit5.UserObject = new Action(b => { if (b)DialPinDigit('5'); }); - PinKeypad.Digit6.UserObject = new Action(b => { if (b)DialPinDigit('6'); }); - PinKeypad.Digit7.UserObject = new Action(b => { if (b)DialPinDigit('7'); }); - PinKeypad.Digit8.UserObject = new Action(b => { if (b)DialPinDigit('8'); }); - PinKeypad.Digit9.UserObject = new Action(b => { if (b)DialPinDigit('9'); }); - } - - /// - /// - /// - /// - void DialPinDigit(char d) - { - PinEntryBuilder.Append(d); - var len = PinEntryBuilder.Length; - SetPinDotsFeedback(len); - - // check it! - if (len == 4) - { - if (Config.Password == PinEntryBuilder.ToString()) - { - IsAuthorized = true; - SetPinDotsFeedback(0); - TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false); - Show(); - } - else - { - SetPinDotsFeedback(0); - TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, true); - new CTimer(o => - { - TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, false); - }, 1500); - } - - PinEntryBuilder.Remove(0, len); // clear it either way - } - } - - /// - /// Draws the dots as pin is entered - /// - /// - void SetPinDotsFeedback(int len) - { - TriList.SetBool(UIBoolJoin.PinDialogDot1, len >= 1); - TriList.SetBool(UIBoolJoin.PinDialogDot2, len >= 2); - TriList.SetBool(UIBoolJoin.PinDialogDot3, len >= 3); - TriList.SetBool(UIBoolJoin.PinDialogDot4, len == 4); - - } - - /// - /// Does what it says - /// - void CancelPinDialog() - { - PinEntryBuilder.Remove(0, PinEntryBuilder.Length); - TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false); - } - - - /// - /// - /// - void BuildStatusList() - { - StatusList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechStatusList, 3, 3, 3); - StatusListDeviceIndexes = new Dictionary(); - uint i = 0; - foreach (var d in DeviceManager.AllDevices) - { - // make sure it is both ICommunicationMonitor and a Device - var sd = d as ICommunicationMonitor; - if (sd == null) - continue; - var dd = sd as Device; - if(dd == null) - continue; - i++; - StatusList.StringInputSig(i, 1).StringValue = dd.Name; - StatusList.UShortInputSig(i, 1).UShortValue = (ushort)sd.CommunicationMonitor.Status; - StatusListDeviceIndexes.Add(sd, i); - sd.CommunicationMonitor.StatusChange += CommunicationMonitor_StatusChange ; - } - StatusList.Count = (ushort)i; - } - - /// - /// Builds the list of display controls - /// - void BuildDisplayList() - { - DisplayList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechDisplayControlsList, 10, 3, 3); - - var devKeys = ConfigReader.ConfigObject.Devices.Where(d => - d.Group.Equals("display", StringComparison.OrdinalIgnoreCase) - || d.Group.Equals("projector", StringComparison.OrdinalIgnoreCase)) - .Select(dd => dd.Key); - var disps = DeviceManager.AllDevices.Where(d => - devKeys.Contains(d.Key)); - ushort i = 0; - foreach (var disp in disps) - { - var display = disp as DisplayBase; - if (display != null) - { - i++; - DisplayList.StringInputSig(i, 1).StringValue = display.Name; - DisplayList.GetBoolFeedbackSig(i, 1).SetSigFalseAction(display.PowerOn); - DisplayList.GetBoolFeedbackSig(i, 2).SetSigFalseAction(display.PowerOff); - if (display is TwoWayDisplayBase) - { - var powerOnSig = DisplayList.BoolInputSig(i, 1); - (display as TwoWayDisplayBase).PowerIsOnFeedback.LinkInputSig(powerOnSig); - - var powerOffSig = DisplayList.BoolInputSig(1, 2); - (display as TwoWayDisplayBase).PowerIsOnFeedback.LinkComplementInputSig(powerOffSig); - } - DisplayList.GetBoolFeedbackSig(i, 3).SetSigFalseAction(() => - { if (display is IInputHdmi1) (display as IInputHdmi1).InputHdmi1(); }); - DisplayList.GetBoolFeedbackSig(i, 4).SetSigFalseAction(() => - { if (display is IInputHdmi2) (display as IInputHdmi2).InputHdmi2(); }); - DisplayList.GetBoolFeedbackSig(i, 5).SetSigFalseAction(() => - { if (display is IInputHdmi3) (display as IInputHdmi3).InputHdmi3(); }); - //DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() => - //{ if (display is IInputHdmi4) (display as IInputHdmi4).InputHdmi4(); }); - DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() => - { if (display is IInputDisplayPort1) (display as IInputDisplayPort1).InputDisplayPort1(); }); - - - // Figure out some way to provide current input feedback - if (display is TwoWayDisplayBase) - { - (display as TwoWayDisplayBase).CurrentInputFeedback.OutputChange += CurrentInputFeedback_OutputChange; - } - } - - - } - - DisplayList.Count = i; - } - - - void CurrentInputFeedback_OutputChange(object sender, EventArgs e) - { - - } - - /// - /// - /// - void CommunicationMonitor_StatusChange(object sender, MonitorStatusChangeEventArgs e) - { - var c = sender as ICommunicationMonitor; - if (StatusListDeviceIndexes.ContainsKey(c)) - { - var i = StatusListDeviceIndexes[c]; - StatusList.UShortInputSig(i, 1).UShortValue = (ushort)e.Status; - } - } - } +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.SmartObjects; +using PepperDash.Essentials.Core.Touchpanels.Keyboards; +using PepperDash.Essentials.Devices.Displays; +using PepperDash.Essentials.Room.Config; + +namespace PepperDash.Essentials.UIDrivers +{ + public class EssentialsHuddleTechPageDriver : PanelDriverBase + { + /// + /// + /// + SmartObjectDynamicList MenuList; + /// + /// + /// + SubpageReferenceList StatusList; + /// + /// The list of display controls + /// + SubpageReferenceList DisplayList; + /// + /// References lines in the list against device instances + /// + Dictionary StatusListDeviceIndexes; + /// + /// + /// + JoinedSigInterlock PagesInterlock; + + /// + /// 1 + /// + public const uint JoinText = 1; + + CTimer PinAuthorizedTimer; + + EssentialsRoomTechConfig Config; + + StringBuilder PinEntryBuilder = new StringBuilder(4); + + bool IsAuthorized; + + SmartObjectNumeric PinKeypad; + + /// + /// + /// + /// + /// + public EssentialsHuddleTechPageDriver(BasicTriListWithSmartObject trilist, EssentialsRoomTechConfig config) + : base(trilist) + { + Config = config; + + PagesInterlock = new JoinedSigInterlock(trilist); + PagesInterlock.SetButDontShow(UIBoolJoin.TechSystemStatusVisible); + + trilist.SetSigFalseAction(UIBoolJoin.TechExitButton, Hide); + + MenuList = new SmartObjectDynamicList(trilist.SmartObjects[UISmartObjectJoin.TechMenuList], + true, 3100); + + MenuList.SetFeedback(1, true); // initial fb + ushort count = 0; + + MenuList.SetItemMainText(1, "System Status"); + MenuList.SetItemButtonAction(1, b => { + if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechSystemStatusVisible); + MenuList.SetFeedback(1, true); + }); + + MenuList.SetItemMainText(2, "Display Controls"); + MenuList.SetItemButtonAction(2, b => { + if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechDisplayControlsVisible); + MenuList.SetFeedback(2, true); + }); + + count = 2; + + // Don't show panel setup on iPad or xpanel + if (TriList is Crestron.SimplSharpPro.DeviceSupport.TswFt5Button) + { + count++; + MenuList.SetItemMainText(count, "Panel Setup"); + MenuList.SetItemButtonAction(count, b => + { + if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechPanelSetupVisible); + MenuList.SetFeedback(count, true); + }); + } + + MenuList.Count = count; + BuildStatusList(); + BuildDisplayList(); + SetupPinModal(); + } + + /// + /// + /// + public override void Show() + { + // divert to PIN if we need auth + if (IsAuthorized) + { + // Cancel the auth timer so we don't deauth after coming back in + if (PinAuthorizedTimer != null) + PinAuthorizedTimer.Stop(); + + TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, true); + PagesInterlock.Show(); + base.Show(); + } + else + { + TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, true); + } + } + + /// + /// + /// + public override void Hide() + { + // Leave it authorized for 60 seconds. + if (IsAuthorized) + PinAuthorizedTimer = new CTimer(o => { + IsAuthorized = false; + PinAuthorizedTimer = null; + }, 60000); + TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, false); + PagesInterlock.Hide(); + base.Hide(); + } + + /// + /// Wire up the keypad and buttons + /// + void SetupPinModal() + { + TriList.SetSigFalseAction(UIBoolJoin.PinDialogCancelPress, CancelPinDialog); + PinKeypad = new SmartObjectNumeric(TriList.SmartObjects[UISmartObjectJoin.TechPinDialogKeypad], true); + PinKeypad.Digit0.UserObject = new Action(b => { if (b)DialPinDigit('0'); }); + PinKeypad.Digit1.UserObject = new Action(b => { if (b)DialPinDigit('1'); }); + PinKeypad.Digit2.UserObject = new Action(b => { if (b)DialPinDigit('2'); }); + PinKeypad.Digit3.UserObject = new Action(b => { if (b)DialPinDigit('3'); }); + PinKeypad.Digit4.UserObject = new Action(b => { if (b)DialPinDigit('4'); }); + PinKeypad.Digit5.UserObject = new Action(b => { if (b)DialPinDigit('5'); }); + PinKeypad.Digit6.UserObject = new Action(b => { if (b)DialPinDigit('6'); }); + PinKeypad.Digit7.UserObject = new Action(b => { if (b)DialPinDigit('7'); }); + PinKeypad.Digit8.UserObject = new Action(b => { if (b)DialPinDigit('8'); }); + PinKeypad.Digit9.UserObject = new Action(b => { if (b)DialPinDigit('9'); }); + } + + /// + /// + /// + /// + void DialPinDigit(char d) + { + PinEntryBuilder.Append(d); + var len = PinEntryBuilder.Length; + SetPinDotsFeedback(len); + + // check it! + if (len == 4) + { + if (Config.Password == PinEntryBuilder.ToString()) + { + IsAuthorized = true; + SetPinDotsFeedback(0); + TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false); + Show(); + } + else + { + SetPinDotsFeedback(0); + TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, true); + new CTimer(o => + { + TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, false); + }, 1500); + } + + PinEntryBuilder.Remove(0, len); // clear it either way + } + } + + /// + /// Draws the dots as pin is entered + /// + /// + void SetPinDotsFeedback(int len) + { + TriList.SetBool(UIBoolJoin.PinDialogDot1, len >= 1); + TriList.SetBool(UIBoolJoin.PinDialogDot2, len >= 2); + TriList.SetBool(UIBoolJoin.PinDialogDot3, len >= 3); + TriList.SetBool(UIBoolJoin.PinDialogDot4, len == 4); + + } + + /// + /// Does what it says + /// + void CancelPinDialog() + { + PinEntryBuilder.Remove(0, PinEntryBuilder.Length); + TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false); + } + + + /// + /// + /// + void BuildStatusList() + { + StatusList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechStatusList, 3, 3, 3); + StatusListDeviceIndexes = new Dictionary(); + uint i = 0; + foreach (var d in DeviceManager.AllDevices) + { + // make sure it is both ICommunicationMonitor and a Device + var sd = d as ICommunicationMonitor; + if (sd == null) + continue; + var dd = sd as Device; + if(dd == null) + continue; + i++; + StatusList.StringInputSig(i, 1).StringValue = dd.Name; + StatusList.UShortInputSig(i, 1).UShortValue = (ushort)sd.CommunicationMonitor.Status; + StatusListDeviceIndexes.Add(sd, i); + sd.CommunicationMonitor.StatusChange += CommunicationMonitor_StatusChange ; + } + StatusList.Count = (ushort)i; + } + + /// + /// Builds the list of display controls + /// + void BuildDisplayList() + { + DisplayList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechDisplayControlsList, 10, 3, 3); + + var devKeys = ConfigReader.ConfigObject.Devices.Where(d => + d.Group.Equals("display", StringComparison.OrdinalIgnoreCase) + || d.Group.Equals("projector", StringComparison.OrdinalIgnoreCase)) + .Select(dd => dd.Key); + var disps = DeviceManager.AllDevices.Where(d => + devKeys.Contains(d.Key)); + ushort i = 0; + foreach (var disp in disps) + { + var display = disp as DisplayBase; + if (display != null) + { + i++; + DisplayList.StringInputSig(i, 1).StringValue = display.Name; + DisplayList.GetBoolFeedbackSig(i, 1).SetSigFalseAction(display.PowerOn); + DisplayList.GetBoolFeedbackSig(i, 2).SetSigFalseAction(display.PowerOff); + if (display is TwoWayDisplayBase) + { + var powerOnSig = DisplayList.BoolInputSig(i, 1); + (display as TwoWayDisplayBase).PowerIsOnFeedback.LinkInputSig(powerOnSig); + + var powerOffSig = DisplayList.BoolInputSig(1, 2); + (display as TwoWayDisplayBase).PowerIsOnFeedback.LinkComplementInputSig(powerOffSig); + } + DisplayList.GetBoolFeedbackSig(i, 3).SetSigFalseAction(() => + { if (display is IInputHdmi1) (display as IInputHdmi1).InputHdmi1(); }); + DisplayList.GetBoolFeedbackSig(i, 4).SetSigFalseAction(() => + { if (display is IInputHdmi2) (display as IInputHdmi2).InputHdmi2(); }); + DisplayList.GetBoolFeedbackSig(i, 5).SetSigFalseAction(() => + { if (display is IInputHdmi3) (display as IInputHdmi3).InputHdmi3(); }); + //DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() => + //{ if (display is IInputHdmi4) (display as IInputHdmi4).InputHdmi4(); }); + DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() => + { if (display is IInputDisplayPort1) (display as IInputDisplayPort1).InputDisplayPort1(); }); + + + // Figure out some way to provide current input feedback + if (display is TwoWayDisplayBase) + { + (display as TwoWayDisplayBase).CurrentInputFeedback.OutputChange += CurrentInputFeedback_OutputChange; + } + } + + + } + + DisplayList.Count = i; + } + + + void CurrentInputFeedback_OutputChange(object sender, EventArgs e) + { + + } + + /// + /// + /// + void CommunicationMonitor_StatusChange(object sender, MonitorStatusChangeEventArgs e) + { + var c = sender as ICommunicationMonitor; + if (StatusListDeviceIndexes.ContainsKey(c)) + { + var i = StatusListDeviceIndexes[c]; + StatusList.UShortInputSig(i, 1).UShortValue = (ushort)e.Status; + } + } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index 752a7107..114909c4 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -257,7 +257,7 @@ namespace PepperDash.Essentials.Core public override EssentialsDevice BuildDevice(DeviceConfig dc) { - Debug.Console(1, "Factory Attempting to create new C2N-RTHS Device"); + Debug.Console(1, "Factory Attempting to create new GlsPartitionSensorController Device"); return new GlsPartitionSensorController(dc.Key, GetGlsPartCnDevice, dc); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs index cbbb58d1..b68a4c04 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -46,9 +46,12 @@ namespace PepperDash.Essentials.Core CreateScenarios(); - SetupPartitionStateProviders(); + AddPostActivationAction(() => + { + SetupPartitionStateProviders(); - SetRooms(); + SetRooms(); + }); } void CreateScenarios() @@ -243,4 +246,21 @@ namespace PepperDash.Essentials.Core #endregion } + + public class EssentialsRoomCombinerFactory : EssentialsDeviceFactory + { + public EssentialsRoomCombinerFactory() + { + TypeNames = new List { "essentialsroomcombiner" }; + } + + public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new EssentialsRoomCombiner Device"); + + var props = dc.Properties.ToObject(); + + return new EssentialsRoomCombiner(dc.Key, props); + } + } } \ No newline at end of file From 5a4f7b6a2864e650ba343a7f7d71dc0d9bf935a4 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 19 Jul 2021 15:44:28 -0600 Subject: [PATCH 26/37] Adds new keyword to intentionally hide properties --- .../Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs index 662988a1..5a6e9f59 100644 --- a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs @@ -16,9 +16,9 @@ namespace PepperDash.Essentials IHasScheduleAwareness ScheduleSource { get; } - BoolFeedback InCallFeedback { get; } + new BoolFeedback InCallFeedback { get; } - BoolFeedback PrivacyModeIsOnFeedback { get; } + new BoolFeedback PrivacyModeIsOnFeedback { get; } string DefaultCodecRouteString { get; } } From 94c0e92f6bc912c172e79b5430d4f0347cb36b78 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 08:28:25 -0600 Subject: [PATCH 27/37] fix: Initialize lists for partitions and scenarios also removed unnecessary else --- .../Room/Combining/EssentialsRoomCombiner.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs index b68a4c04..6d80913f 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -27,6 +27,9 @@ namespace PepperDash.Essentials.Core { _propertiesConfig = props; + Partitions = new List(); + RoomCombinationScenarios = new List(); + if (_propertiesConfig.ScenarioChangeDebounceTimeSeconds > 0) { _scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds; @@ -136,11 +139,6 @@ namespace PepperDash.Essentials.Core // the partition can't be found or the state doesn't match return false; } - else - { - // check the next partition state - continue; - } } // if it hasn't returned false by now we have the matching scenario return true; From 5f6b650dba081b5eb0bfd860bb0402d1e09a99c7 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 11:15:37 -0600 Subject: [PATCH 28/37] fix: Update fusion IP-ID for multiple rooms --- PepperDashEssentials/ControlSystem.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 033d82fe..8c3399ae 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -450,14 +450,13 @@ namespace PepperDash.Essentials return; } + uint fusionIpId = 0xf1; + foreach (var roomConfig in ConfigReader.ConfigObject.Rooms) { var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as IEssentialsRoom; if (room != null) { - // default IPID - uint fusionIpId = 0xf1; - // default to no join map key string fusionJoinMapKey = string.Empty; @@ -515,9 +514,13 @@ namespace PepperDash.Essentials DeviceManager.AddDevice(room); } + fusionIpId += 1; } else + { Debug.Console(0, Debug.ErrorLogLevel.Notice, "Notice: Cannot create room from config, key '{0}' - Is this intentional? This may be a valid configuration.", roomConfig.Key); + + } } Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Rooms Loaded."); From 1415999d8653fbb1760908b3fc1ef0ad1cb5e30b Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 17:28:40 -0600 Subject: [PATCH 29/37] refactor: Update a debug message with IP-ID info --- .../Fusion/EssentialsHuddleVtc1FusionController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs index 54d936f0..c3877706 100644 --- a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs +++ b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs @@ -150,7 +150,7 @@ namespace PepperDash.Essentials.Fusion protected override void CreateSymbolAndBasicSigs(uint ipId) { - Debug.Console(1, this, "Creating Fusion Room symbol with GUID: {0}", RoomGuid); + Debug.Console(0, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId); FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use(); From 88e5c49663f7b0b9db35faec8480cec00ab0f627 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 17:29:02 -0600 Subject: [PATCH 30/37] refactor: Add Fusion IP-ID info to debug messages --- PepperDashEssentials/ControlSystem.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 8c3399ae..ba5529d9 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -477,7 +477,7 @@ namespace PepperDash.Essentials { DeviceManager.AddDevice(room); - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion"); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId); DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase(room, fusionIpId, fusionJoinMapKey)); @@ -489,7 +489,7 @@ namespace PepperDash.Essentials { DeviceManager.AddDevice(room); - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion"); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId); DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey)); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge..."); @@ -501,7 +501,7 @@ namespace PepperDash.Essentials DeviceManager.AddDevice(room); Debug.Console(0, Debug.ErrorLogLevel.Notice, - "Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion"); + "Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId); DeviceManager.AddDevice(new EssentialsTechRoomFusionSystemController((EssentialsTechRoom)room, fusionIpId, fusionJoinMapKey)); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge"); From de7a74eaffa5946f0330985d4de6ec979faefe37 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 17:30:45 -0600 Subject: [PATCH 31/37] feat: Update Fusion to create a GUID file per room This allows for multiple rooms to be designated and created without any issues. Also moved post Activation action to it's own method rather than a lambda. In the interest of backwards compatibility, the Fusion class will look for a GUID file with the old file name and migrate it to the new file name. --- ...lsHuddleSpaceFusionSystemControllerBase.cs | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index a172ab49..1bf925d6 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -119,9 +119,21 @@ namespace PepperDash.Essentials.Core.Fusion var slot = Global.ControlSystem.ProgramNumber; var guidFilePath = Global.FilePathPrefix + - string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); + string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _ipId); - _guidFileExists = File.Exists(guidFilePath); + var oldGuidFilePath = Global.FilePathPrefix + + string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); + + if (File.Exists(oldGuidFilePath)) + { + Debug.Console(0, this, "Migrating from old Fusion GUID file to new Fusion GUID File"); + + File.Copy(oldGuidFilePath, guidFilePath); + + File.Delete(oldGuidFilePath); + } + + _guidFileExists = File.Exists(guidFilePath); // Check if file exists if (!_guidFileExists) @@ -149,19 +161,7 @@ namespace PepperDash.Essentials.Core.Fusion } - AddPostActivationAction(() => - { - CreateSymbolAndBasicSigs(_ipId); - SetUpSources(); - SetUpCommunitcationMonitors(); - SetUpDisplay(); - SetUpError(); - ExecuteCustomSteps(); - - FusionRVI.GenerateFileForAllFusionDevices(); - - GenerateGuidFile(guidFilePath); - }); + AddPostActivationAction(() => PostActivate(guidFilePath)); } catch (Exception e) { @@ -169,6 +169,20 @@ namespace PepperDash.Essentials.Core.Fusion } } + private void PostActivate(string guidFilePath) + { + CreateSymbolAndBasicSigs(_ipId); + SetUpSources(); + SetUpCommunitcationMonitors(); + SetUpDisplay(); + SetUpError(); + ExecuteCustomSteps(); + + FusionRVI.GenerateFileForAllFusionDevices(); + + GenerateGuidFile(guidFilePath); + } + protected string RoomGuid { get { return _guiDs.RoomGuid; } @@ -314,7 +328,7 @@ namespace PepperDash.Essentials.Core.Fusion protected virtual void CreateSymbolAndBasicSigs(uint ipId) { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating Fusion Room symbol with GUID: {0}", RoomGuid); + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId); FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use(); From 290e887903d2d0f3ac84eede97aeda695680c5fd Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 17:32:00 -0600 Subject: [PATCH 32/37] refactor: Modify debug messages Exceptions now print the device key and the error message. To see stack traces, use `appdebug:XX 1`. There are also now debug messages indicating when the different activation cycles are complete. --- .../Devices/DeviceManager.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs index aac38dfa..df864550 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs @@ -60,6 +60,7 @@ namespace PepperDash.Essentials.Core DeviceCriticalSection.Enter(); AddDeviceEnabled = false; // PreActivate all devices + Debug.Console(0,"****PreActivation starting...****"); foreach (var d in Devices.Values) { try @@ -69,9 +70,12 @@ namespace PepperDash.Essentials.Core } catch (Exception e) { - Debug.Console(0, d, "ERROR: Device PreActivation failure:\r{0}", e); + Debug.Console(0, d, "ERROR: Device {1} PreActivation failure: {0}", e.Message, d.Key); + Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace); } } + Debug.Console(0, "****PreActivation complete****"); + Debug.Console(0, "****Activation starting...****"); // Activate all devices foreach (var d in Devices.Values) @@ -83,10 +87,14 @@ namespace PepperDash.Essentials.Core } catch (Exception e) { - Debug.Console(0, d, "ERROR: Device Activation failure:\r{0}", e); + Debug.Console(0, d, "ERROR: Device {1} Activation failure: {0}", e.Message, d.Key); + Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace); } } + Debug.Console(0, "****Activation complete****"); + Debug.Console(0, "****PostActivation starting...****"); + // PostActivate all devices foreach (var d in Devices.Values) { @@ -97,10 +105,13 @@ namespace PepperDash.Essentials.Core } catch (Exception e) { - Debug.Console(0, d, "ERROR: Device PostActivation failure:\r{0}", e); + Debug.Console(0, d, "ERROR: Device {1} PostActivation failure: {0}", e.Message, d.Key); + Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace); } } + Debug.Console(0, "****PostActivation complete****"); + OnAllDevicesActivated(); } finally From 085a64c87b14ce76ad0e955fc255c94cb1da9601 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 13:41:21 -0600 Subject: [PATCH 33/37] fix: Correct functioning while in test mode --- .../GlsPartitionSensorController.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index 114909c4..26cade95 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -39,10 +39,10 @@ namespace PepperDash.Essentials.Core RegisterCrestronGenericBase(_partitionSensor); NameFeedback = new StringFeedback(() => Name); - EnableFeedback = new BoolFeedback(() => _partitionSensor.EnableFeedback.BoolValue); - PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionSensedFeedback.BoolValue); - PartitionNotSensedFeedback = new BoolFeedback(() => _partitionSensor.PartitionNotSensedFeedback.BoolValue); - SensitivityFeedback = new IntFeedback(() => _partitionSensor.SensitivityFeedback.UShortValue); + EnableFeedback = new BoolFeedback(() => InTestMode ? TestEnableFeedback : _partitionSensor.EnableFeedback.BoolValue); + PartitionPresentFeedback = new BoolFeedback(() => InTestMode ? TestPartitionSensedFeedback : _partitionSensor.PartitionSensedFeedback.BoolValue); + PartitionNotSensedFeedback = new BoolFeedback(() => InTestMode ? !TestPartitionSensedFeedback : _partitionSensor.PartitionNotSensedFeedback.BoolValue); + SensitivityFeedback = new IntFeedback(() => InTestMode ? TestSensitivityFeedback : _partitionSensor.SensitivityFeedback.UShortValue); if (_partitionSensor != null) _partitionSensor.BaseEvent += PartitionSensor_BaseEvent; }); @@ -93,6 +93,9 @@ namespace PepperDash.Essentials.Core if (InTestMode) { TestEnableFeedback = state; + + EnableFeedback.FireUpdate(); + Debug.Console(1, this, "TestEnableFeedback: {0}", TestEnableFeedback.ToString()); return; } @@ -105,6 +108,10 @@ namespace PepperDash.Essentials.Core if (InTestMode) { TestPartitionSensedFeedback = state; + + PartitionPresentFeedback.FireUpdate(); + PartitionNotSensedFeedback.FireUpdate(); + Debug.Console(1, this, "TestPartitionSensedFeedback: {0}", TestPartitionSensedFeedback.ToString()); return; } @@ -117,6 +124,8 @@ namespace PepperDash.Essentials.Core if (InTestMode) { TestSensitivityFeedback = value; + + SensitivityFeedback.FireUpdate(); Debug.Console(1, this, "TestSensitivityFeedback: {0}", TestSensitivityFeedback); return; } From f607394ee724d9192d83d88db5f9c6ccb97748b3 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 16:53:11 -0600 Subject: [PATCH 34/37] chore: Update PD Core to 1.0.48 --- packages.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages.config b/packages.config index 3876040a..3494f2eb 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file From 4bd777f6b942b2da27ada6a163788ecff8bd1e33 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 16:53:36 -0600 Subject: [PATCH 35/37] feat: Update `Essentials Device` to call `Initialize` method --- .../Devices/EssentialsDevice.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs index 781101d4..00624007 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs @@ -27,6 +27,27 @@ namespace PepperDash.Essentials.Core { } + + private void SubscribeToActivateComplete() + { + DeviceManager.AllDevicesActivated += DeviceManagerOnAllDevicesActivated; + } + + private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs) + { + CrestronInvoke.BeginInvoke((o) => + { + try + { + Initialize(); + } + catch (Exception ex) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Exception initializing device: {0}", ex.Message); + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.StackTrace); + } + }); + } } [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] From 76e4d4a82d9994ec2e0c1b3c7dd76810cd29f724 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 19:44:41 -0600 Subject: [PATCH 36/37] feat: Add method call to constructor for EssentialsDevice --- .../PepperDashEssentialsBase/Devices/EssentialsDevice.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs index 00624007..46fa819b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs @@ -19,13 +19,13 @@ namespace PepperDash.Essentials.Core protected EssentialsDevice(string key) : base(key) { - + SubscribeToActivateComplete(); } protected EssentialsDevice(string key, string name) : base(key, name) { - + SubscribeToActivateComplete(); } private void SubscribeToActivateComplete() From ea254ef98333f754e12f411891613a2691f05d8a Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 19:56:29 -0600 Subject: [PATCH 37/37] feat: Update some internal Essentials devices to use Initialize method --- .../MicrophonePrivacyController.cs | 14 +++++++++----- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 19 +++++++++++++------ .../VideoCodec/ZoomRoom/ZoomRoom.cs | 17 +++++++++++++---- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs index 0f15a02d..55b458a7 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs @@ -88,11 +88,6 @@ namespace PepperDash.Essentials.Core.Privacy else Debug.Console(0, this, "Unable to add Red LED device"); - DeviceManager.AllDevicesActivated += (o, a) => - { - CheckPrivacyMode(); - }; - AddPostActivationAction(() => { PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange; PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; @@ -103,6 +98,15 @@ namespace PepperDash.Essentials.Core.Privacy return base.CustomActivate(); } + #region Overrides of Device + + public override void Initialize() + { + CheckPrivacyMode(); + } + + #endregion + public void SetPrivacyDevice(IPrivacy privacyDevice) { PrivacyDevice = privacyDevice; diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index a7be2443..7cfe82c0 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -550,6 +550,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CrestronConsole.AddNewConsoleCommand(GetPhonebook, "GetCodecPhonebook", "Triggers a refresh of the codec phonebook", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(GetBookings, "GetCodecBookings", "Triggers a refresh of the booking data for today", ConsoleAccessLevelEnum.AccessOperator); + return base.CustomActivate(); + } + + #region Overrides of Device + + public override void Initialize() + { var socket = Communication as ISocketStatus; if (socket != null) { @@ -558,9 +565,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco Communication.Connect(); - CommunicationMonitor.Start(); + CommunicationMonitor.Start(); - string prefix = "xFeedback register "; + const string prefix = "xFeedback register "; CliFeedbackRegistrationExpression = prefix + "/Configuration" + Delimiter + @@ -575,14 +582,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco prefix + "/Status/Video/Layout" + Delimiter + prefix + "/Status/Video/Input/MainVideoMute" + Delimiter + prefix + "/Bookings" + Delimiter + - prefix + "/Event/CallDisconnect" + Delimiter + + prefix + "/Event/CallDisconnect" + Delimiter + prefix + "/Event/Bookings" + Delimiter + prefix + "/Event/CameraPresetListUpdated" + Delimiter + - prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter; - - return base.CustomActivate(); + prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter; } + #endregion + /// /// Fires when initial codec sync is completed. Used to then send commands to get call history, phonebook, bookings, etc. /// diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index fc3f14a9..e838ceed 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -717,7 +717,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom CrestronConsole.AddNewConsoleCommand(s => GetBookings(), "GetZoomRoomBookings", "Triggers a refresh of the booking data for today", ConsoleAccessLevelEnum.AccessOperator); - var socket = Communication as ISocketStatus; + + + return base.CustomActivate(); + } + + #region Overrides of Device + + public override void Initialize() + { + var socket = Communication as ISocketStatus; if (socket != null) { socket.ConnectionChange += socket_ConnectionChange; @@ -728,11 +737,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Communication.Connect(); CommunicationMonitor.Start(); + } - return base.CustomActivate(); - } + #endregion - public void SetCommDebug(string s) + public void SetCommDebug(string s) { if (s == "1") {