From db6ab3ee9896774bee07e0ea5c4ea8a8f87717c4 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 18 Nov 2020 09:36:39 -0700 Subject: [PATCH 01/59] #497 Add logic to set checksum value --- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 ea39bb65..2501bf22 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 @@ -516,12 +516,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco SendText("xconfiguration userinterface custommessage: \"Scan the QR code with a mobile phone to get started\""); SendText("xconfiguration userinterface osd halfwakemessage: \"Tap the touch panel or scan the QR code with a mobile phone to get started\""); + var checksum = !String.IsNullOrEmpty(mcBridge.QrCodeChecksum) + ? String.Format("checksum: {0} ", mcBridge.QrCodeChecksum) + : String.Empty; + SendText(String.Format( - "xcommand userinterface branding fetch type: branding url: {0}", - mcBridge.QrCodeUrl)); + "xcommand userinterface branding fetch {1}type: branding url: {0}", + mcBridge.QrCodeUrl, checksum)); SendText(String.Format( - "xcommand userinterface branding fetch type: halfwakebranding url: {0}", - mcBridge.QrCodeUrl)); + "xcommand userinterface branding fetch {1}type: halfwakebranding url: {0}", + mcBridge.QrCodeUrl, checksum)); } private void SendBrandingUrl() From e22c71853f7ebc6f1ddc4e405b47058f6fdcba31 Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Wed, 2 Dec 2020 13:10:47 -0500 Subject: [PATCH 02/59] Starts adding support for starting and stopping dm stream cards via API bridge --- .../JoinMaps/DmChassisControllerJoinMap.cs | 12 + .../JoinMaps/DmChassisControllerJoinMap.cs | 8 + .../Chassis/DmChassisController.cs | 220 +++++++++++++++++- 3 files changed, 231 insertions(+), 9 deletions(-) diff --git a/PepperDashEssentials/Bridges/JoinMaps/DmChassisControllerJoinMap.cs b/PepperDashEssentials/Bridges/JoinMaps/DmChassisControllerJoinMap.cs index 2e1b8394..ba00306d 100644 --- a/PepperDashEssentials/Bridges/JoinMaps/DmChassisControllerJoinMap.cs +++ b/PepperDashEssentials/Bridges/JoinMaps/DmChassisControllerJoinMap.cs @@ -70,6 +70,14 @@ namespace PepperDash.Essentials.Bridges /// Range reports the highest supported HDCP state level for the corresponding input card /// public uint HdcpSupportCapability { get; set; } + /// + /// DM Chassis Stream Input Start (1), Stop (2), Pause (3) with Feedback + /// + public uint InputStreamCardStatus { get; set; } + /// + /// DM Chassis Stream Output Start (1), Stop (2), Pause (3) with Feedback + /// + public uint OutputStreamCardStatus { get; set; } #endregion #region Serials @@ -115,6 +123,8 @@ namespace PepperDash.Essentials.Bridges InputUsb = 700; //701-899 HdcpSupportState = 1000; //1001-1199 HdcpSupportCapability = 1200; //1201-1399 + InputStreamCardStatus = 1500; //1501-1532 + OutputStreamCardStatus = 1600; //1601-1632 //Serial @@ -145,6 +155,8 @@ namespace PepperDash.Essentials.Bridges OutputEndpointOnline = OutputEndpointOnline + joinOffset; HdcpSupportState = HdcpSupportState + joinOffset; HdcpSupportCapability = HdcpSupportCapability + joinOffset; + InputStreamCardStatus = InputStreamCardStatus + joinOffset; + OutputStreamCardStatus = OutputStreamCardStatus + joinOffset; OutputDisabledByHdcp = OutputDisabledByHdcp + joinOffset; TxAdvancedIsPresent = TxAdvancedIsPresent + joinOffset; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/DmChassisControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/DmChassisControllerJoinMap.cs index 54909d02..ee04bd45 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/DmChassisControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/DmChassisControllerJoinMap.cs @@ -76,6 +76,14 @@ namespace PepperDash.Essentials.Core.Bridges public JoinDataComplete HdcpSupportCapability = new JoinDataComplete(new JoinData { JoinNumber = 1201, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input HDCP Support Capability", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + [JoinName("InputStreamCardState")] + public JoinDataComplete InputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1501, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Stream Input Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + + [JoinName("OutputStreamCardState")] + public JoinDataComplete OutputStreamCardState = new JoinDataComplete(new JoinData { JoinNumber = 1601, JoinSpan = 32 }, + new JoinMetadata { Description = "DM Chassis Stream Output Start (1), Stop (2), Pause (3) with Feedback", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Analog }); + [JoinName("InputNames")] public JoinDataComplete InputNames = new JoinDataComplete(new JoinData { JoinNumber = 101, JoinSpan = 32 }, new JoinMetadata { Description = "DM Chassis Input Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial }); diff --git a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs index 09c7988a..db4e517f 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs @@ -49,7 +49,9 @@ namespace PepperDash.Essentials.DM public BoolFeedback EnableAudioBreakawayFeedback { get; private set; } public BoolFeedback EnableUsbBreakawayFeedback { get; private set; } - public Dictionary InputCardHdcpStateFeedbacks { get; private set; } + public Dictionary InputCardHdcpStateFeedbacks { get; private set; } + public Dictionary InputStreamCardStateFeedbacks { get; private set; } + public Dictionary OutputStreamCardStateFeedbacks { get; private set; } public Dictionary InputCardHdcpCapabilityTypes { get; private set; } @@ -223,7 +225,9 @@ namespace PepperDash.Essentials.DM EnableUsbBreakawayFeedback = new BoolFeedback(() => (Chassis as DmMDMnxn).EnableUSBBreakawayFeedback.BoolValue); - InputCardHdcpStateFeedbacks = new Dictionary(); + InputCardHdcpStateFeedbacks = new Dictionary(); + InputStreamCardStateFeedbacks = new Dictionary(); + OutputStreamCardStateFeedbacks = new Dictionary(); InputCardHdcpCapabilityTypes = new Dictionary(); for (uint x = 1; x <= Chassis.NumberOfOutputs; x++) @@ -307,6 +311,33 @@ namespace PepperDash.Essentials.DM // return hdMdNxMHdmiOutput.HdmiOutputPort.DisabledByHdcpFeedback.BoolValue; return false; + }); + OutputStreamCardStateFeedbacks[tempX] = new IntFeedback(() => + { + try + { + var outputCard = Chassis.Outputs[tempX]; + + if (outputCard.Card is DmcStroAV) + { + Debug.Console(0, "Found output stream card in slot: {0}.", tempX); + var streamCard = outputCard.Card as DmcStroAV; + if (streamCard.Control.StartFeedback.BoolValue == true) + return 1; + else if (streamCard.Control.StopFeedback.BoolValue == true) + return 2; + else if (streamCard.Control.PauseFeedback.BoolValue == true) + return 3; + else + return 0; + } + return 0; + } + catch (InvalidOperationException iopex) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "Error adding output stream card in slot: {0}. Error: {1}", tempX, iopex); + return 0; + } }); } @@ -406,6 +437,33 @@ namespace PepperDash.Essentials.DM Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "The Input Card in slot: {0} supports HDCP 2. Please update the configuration value in the inputCardSupportsHdcp2 object to true. Error: {1}", tempX, iopex); return 0; } + }); + InputStreamCardStateFeedbacks[tempX] = new IntFeedback(() => + { + try + { + var inputCard = Chassis.Inputs[tempX]; + + if (inputCard.Card is DmcStr) + { + Debug.Console(0, "Found input stream card in slot: {0}.", tempX); + var streamCard = inputCard.Card as DmcStr; + if (streamCard.Control.StartFeedback.BoolValue == true) + return 1; + else if (streamCard.Control.StopFeedback.BoolValue == true) + return 2; + else if (streamCard.Control.PauseFeedback.BoolValue == true) + return 3; + else + return 0; + } + return 0; + } + catch (InvalidOperationException iopex) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Warning, "Error adding input stream card in slot: {0}. Error: {1}", tempX, iopex); + return 0; + } }); } } @@ -915,6 +973,42 @@ namespace PepperDash.Essentials.DM else Debug.Console(1, this, "No index of {0} found in InputCardHdcpCapabilityFeedbacks"); break; + } + case DMInputEventIds.StartEventId: + case DMInputEventIds.StopEventId: + case DMInputEventIds.PauseEventId: + { + Debug.Console(2, this, "DM Input {0} Stream Status EventId", args.Number); + if (InputStreamCardStateFeedbacks[args.Number] != null) + { + var streamCard = Chassis.Inputs[args.Number].Card as DmcStr; + InputStreamCardStateFeedbacks[args.Number] = new IntFeedback(() => { + if (streamCard.Control.StartFeedback.BoolValue == true) + { + Debug.Console(1, this, "Found start feedback"); + return 1; + } + else if (streamCard.Control.StopFeedback.BoolValue == true) + { + Debug.Console(1, this, "Found stop feedback"); + return 2; + } + else if (streamCard.Control.PauseFeedback.BoolValue == true) + { + Debug.Console(1, this, "Found pause feedback"); + return 3; + } + else + { + Debug.Console(1, this, "Found no feedback"); + return 0; + } + }); + InputStreamCardStateFeedbacks[args.Number].FireUpdate(); + } + else + Debug.Console(1, this, "No index of {0} found in InputStreamCardStateFeedbacks"); + break; } default: { @@ -1043,6 +1137,31 @@ namespace PepperDash.Essentials.DM Debug.Console(2, this, "DM Output {0} DisabledByHdcpEventId", args.Number); OutputDisabledByHdcpFeedbacks[args.Number].FireUpdate(); break; + } + case DMOutputEventIds.StartEventId: + case DMOutputEventIds.StopEventId: + case DMOutputEventIds.PauseEventId: + { + Debug.Console(2, this, "DM Output {0} Stream Status EventId", args.Number); + if (OutputStreamCardStateFeedbacks[args.Number] != null) + { + var streamCard = Chassis.Outputs[args.Number].Card as DmcStroAV; + OutputStreamCardStateFeedbacks[args.Number] = new IntFeedback(() => + { + if (streamCard.Control.StartFeedback.BoolValue == true) + return 1; + else if (streamCard.Control.StopFeedback.BoolValue == true) + return 2; + else if (streamCard.Control.PauseFeedback.BoolValue == true) + return 3; + else + return 0; + }); + OutputStreamCardStateFeedbacks[args.Number].FireUpdate(); + } + else + Debug.Console(1, this, "No index of {0} found in OutputStreamCardStateFeedbacks"); + break; } default: { @@ -1242,13 +1361,16 @@ namespace PepperDash.Essentials.DM } else { - LinkHdmiInputToApi(trilist, ioSlot, joinMap, ioSlotJoin); - } - - if (RxDictionary.ContainsKey(ioSlot)) - { - LinkRxToApi(trilist, ioSlot, joinMap, ioSlotJoin); - } + LinkHdmiInputToApi(trilist, ioSlot, joinMap, ioSlotJoin); + LinkStreamInputToApi(trilist, ioSlot, joinMap, ioSlotJoin); + } + + if (RxDictionary.ContainsKey(ioSlot)) + { + LinkRxToApi(trilist, ioSlot, joinMap, ioSlotJoin); + } + else + LinkStreamOutputToApi(trilist, ioSlot, joinMap, ioSlotJoin); } } @@ -1295,6 +1417,86 @@ namespace PepperDash.Essentials.DM { trilist.UShortInput[joinMap.HdcpSupportCapability.JoinNumber + ioSlotJoin].UShortValue = 1; } + } + + private void LinkStreamInputToApi(BasicTriList trilist, uint ioSlot, DmChassisControllerJoinMap joinMap, uint ioSlotJoin) + { + var inputPort = InputPorts[string.Format("inputCard{0}--streamIn", ioSlot)]; + if (inputPort == null) + { + return; + } + var streamCard = Chassis.Inputs[ioSlot].Card as DmcStr; + var join = joinMap.InputStreamCardState.JoinNumber + ioSlotJoin; + + Debug.Console(1, "Port value for input card {0} is set as a stream card", ioSlot); + + trilist.SetUShortSigAction(join, s => + { + if (s == 1) + { + Debug.Console(2, this, "Join {0} value {1}: Setting stream state to start", join, s); + streamCard.Control.Start(); + } + else if (s == 2) + { + Debug.Console(2, this, "Join {0} value {1}: Setting stream state to stop", join, s); + streamCard.Control.Stop(); + } + else if (s == 3) + { + Debug.Console(2, this, "Join {0} value {1}: Setting stream state to pause", join, s); + streamCard.Control.Pause(); + } + else + { + Debug.Console(2, this, "Join {0} value {1}: Ignore stream state", join, s); + } + }); + + InputStreamCardStateFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[join]); + + trilist.UShortInput[join].UShortValue = InputStreamCardStateFeedbacks[ioSlot].UShortValue; + } + + private void LinkStreamOutputToApi(BasicTriList trilist, uint ioSlot, DmChassisControllerJoinMap joinMap, uint ioSlotJoin) + { + var outputPort = OutputPorts[string.Format("outputCard{0}--streamOut", ioSlot)]; + if (outputPort == null) + { + return; + } + var streamCard = Chassis.Outputs[ioSlot].Card as DmcStroAV; + var join = joinMap.OutputStreamCardState.JoinNumber + ioSlotJoin; + + Debug.Console(1, "Port value for output card {0} is set as a stream card", ioSlot); + + trilist.SetUShortSigAction(join, s => + { + if (s == 1) + { + Debug.Console(2, this, "Join {0} value {1}: Setting stream state to start", join, s); + streamCard.Control.Start(); + } + else if (s == 2) + { + Debug.Console(2, this, "Join {0} value {1}: Setting stream state to stop", join, s); + streamCard.Control.Stop(); + } + else if (s == 3) + { + Debug.Console(2, this, "Join {0} value {1}: Setting stream state to pause", join, s); + streamCard.Control.Pause(); + } + else + { + Debug.Console(2, this, "Join {0} value {1}: Ignore stream state", join, s); + } + }); + + OutputStreamCardStateFeedbacks[ioSlot].LinkInputSig(trilist.UShortInput[join]); + + trilist.UShortInput[join].UShortValue = OutputStreamCardStateFeedbacks[ioSlot].UShortValue; } private void LinkRxToApi(BasicTriList trilist, uint ioSlot, DmChassisControllerJoinMap joinMap, uint ioSlotJoin) From ab5dd5f7569eb6a4464df1ce587bd89577ae79ba Mon Sep 17 00:00:00 2001 From: Alex Johnson Date: Wed, 2 Dec 2020 13:51:44 -0500 Subject: [PATCH 03/59] Fixes streaming card feedback and removes excess debug --- .../Chassis/DmChassisController.cs | 43 ++----------------- 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs index db4e517f..3c5567c4 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs @@ -320,7 +320,7 @@ namespace PepperDash.Essentials.DM if (outputCard.Card is DmcStroAV) { - Debug.Console(0, "Found output stream card in slot: {0}.", tempX); + Debug.Console(2, "Found output stream card in slot: {0}.", tempX); var streamCard = outputCard.Card as DmcStroAV; if (streamCard.Control.StartFeedback.BoolValue == true) return 1; @@ -446,7 +446,7 @@ namespace PepperDash.Essentials.DM if (inputCard.Card is DmcStr) { - Debug.Console(0, "Found input stream card in slot: {0}.", tempX); + Debug.Console(2, "Found input stream card in slot: {0}.", tempX); var streamCard = inputCard.Card as DmcStr; if (streamCard.Control.StartFeedback.BoolValue == true) return 1; @@ -981,33 +981,10 @@ namespace PepperDash.Essentials.DM Debug.Console(2, this, "DM Input {0} Stream Status EventId", args.Number); if (InputStreamCardStateFeedbacks[args.Number] != null) { - var streamCard = Chassis.Inputs[args.Number].Card as DmcStr; - InputStreamCardStateFeedbacks[args.Number] = new IntFeedback(() => { - if (streamCard.Control.StartFeedback.BoolValue == true) - { - Debug.Console(1, this, "Found start feedback"); - return 1; - } - else if (streamCard.Control.StopFeedback.BoolValue == true) - { - Debug.Console(1, this, "Found stop feedback"); - return 2; - } - else if (streamCard.Control.PauseFeedback.BoolValue == true) - { - Debug.Console(1, this, "Found pause feedback"); - return 3; - } - else - { - Debug.Console(1, this, "Found no feedback"); - return 0; - } - }); InputStreamCardStateFeedbacks[args.Number].FireUpdate(); } else - Debug.Console(1, this, "No index of {0} found in InputStreamCardStateFeedbacks"); + Debug.Console(2, this, "No index of {0} found in InputStreamCardStateFeedbacks"); break; } default: @@ -1145,22 +1122,10 @@ namespace PepperDash.Essentials.DM Debug.Console(2, this, "DM Output {0} Stream Status EventId", args.Number); if (OutputStreamCardStateFeedbacks[args.Number] != null) { - var streamCard = Chassis.Outputs[args.Number].Card as DmcStroAV; - OutputStreamCardStateFeedbacks[args.Number] = new IntFeedback(() => - { - if (streamCard.Control.StartFeedback.BoolValue == true) - return 1; - else if (streamCard.Control.StopFeedback.BoolValue == true) - return 2; - else if (streamCard.Control.PauseFeedback.BoolValue == true) - return 3; - else - return 0; - }); OutputStreamCardStateFeedbacks[args.Number].FireUpdate(); } else - Debug.Console(1, this, "No index of {0} found in OutputStreamCardStateFeedbacks"); + Debug.Console(2, this, "No index of {0} found in OutputStreamCardStateFeedbacks"); break; } default: From 0e4edca08a31c558428599ef51e93eda4f6407ee Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Dec 2020 11:05:46 -0700 Subject: [PATCH 04/59] update plugin dependency check message --- .../PepperDashEssentialsBase/Plugins/PluginLoader.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs index f7275a66..3e8cbc38 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs @@ -402,13 +402,16 @@ namespace PepperDash.Essentials /// Loads a /// /// + /// static void LoadCustomPlugin(IPluginDeviceFactory plugin, LoadedAssembly loadedAssembly) { var passed = Global.IsRunningMinimumVersionOrHigher(plugin.MinimumEssentialsFrameworkVersion); if (!passed) { - Debug.Console(0, Debug.ErrorLogLevel.Error, "Plugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin", plugin.MinimumEssentialsFrameworkVersion); + Debug.Console(0, Debug.ErrorLogLevel.Error, + "**********/r/nPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}/r/n**********", + plugin.MinimumEssentialsFrameworkVersion, loadedAssembly.Name); return; } else From 93a5f2e3b2831f7ca1c65eaafc69e2e8a30a8271 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Dec 2020 12:18:08 -0700 Subject: [PATCH 05/59] fix slases --- .../PepperDashEssentialsBase/Plugins/PluginLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs index 3e8cbc38..f0a7aeeb 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs @@ -410,7 +410,7 @@ namespace PepperDash.Essentials if (!passed) { Debug.Console(0, Debug.ErrorLogLevel.Error, - "**********/r/nPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}/r/n**********", + "**********\r\nPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n**********", plugin.MinimumEssentialsFrameworkVersion, loadedAssembly.Name); return; } From 008a052045003b2667063fba0a6e1973c763bb45 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 1 Dec 2020 16:20:59 -0700 Subject: [PATCH 06/59] getting started with EssentialsTechRoom --- .../Room/Config/EssentialsRoomConfig.cs | 35 +- .../Room/Config/EssentialsTechRoomConfig.cs | 20 ++ .../Room/Types/EssentialsTechRoom.cs | 94 ++++++ .../Presets/DevicePresets.cs | 305 ++++++++++-------- 4 files changed, 291 insertions(+), 163 deletions(-) create mode 100644 PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs create mode 100644 PepperDashEssentials/Room/Types/EssentialsTechRoom.cs diff --git a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs index dfaa333d..3aee1e20 100644 --- a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs @@ -22,30 +22,25 @@ namespace PepperDash.Essentials.Room.Config public static Device GetRoomObject(DeviceConfig roomConfig) { var typeName = roomConfig.Type.ToLower(); + if (typeName == "huddle") { - var huddle = new EssentialsHuddleSpaceRoom(roomConfig); - - return huddle; + return new EssentialsHuddleSpaceRoom(roomConfig); } - else if (typeName == "huddlevtc1") - { - var rm = new EssentialsHuddleVtc1Room(roomConfig); - - return rm; - } - else if (typeName == "ddvc01Bridge") - { - return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing. - } - else if (typeName == "dualdisplay") - { - var rm = new EssentialsDualDisplayRoom(roomConfig); + if (typeName == "huddlevtc1") + { + return new EssentialsHuddleVtc1Room(roomConfig); + } + if (typeName == "ddvc01Bridge") + { + return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing. + } + if (typeName == "dualdisplay") + { + return new EssentialsDualDisplayRoom(roomConfig); + } - return rm; - } - - return null; + return typeName != "techRoom" ? null : new EssentialsTechRoom(roomConfig); } /// diff --git a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs new file mode 100644 index 00000000..8f35461b --- /dev/null +++ b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace PepperDash.Essentials.Room.Config +{ + public class EssentialsTechRoomConfig + { + public List Displays; + public List Tuners; + public string ScheduleProviderKey; + public string UserPin; + public string TechPin; + public string PresetsFileName; + + public EssentialsTechRoomConfig() + { + Displays = new List(); + Tuners = new List(); + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs new file mode 100644 index 00000000..ba87df5d --- /dev/null +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Presets; +using PepperDash.Essentials.Devices.Common; +using PepperDash.Essentials.Room.Config; + +namespace PepperDash.Essentials +{ + public class EssentialsTechRoom:EssentialsRoomBase + { + private Dictionary _tuners; + private Dictionary _displays; + + private DevicePresetsModel _tunerPresets; + + private readonly EssentialsTechRoomConfig _config; + + + public EssentialsTechRoom(DeviceConfig config) : base(config) + { + _config = config.Properties.ToObject(); + + _tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), _config.PresetsFileName); + + _tuners = GetDevices(_config.Tuners); + _displays = GetDevices(_config.Displays); + } + + private Dictionary GetDevices(ICollection config) where T:IKeyed + { + try + { + var returnValue = DeviceManager.AllDevices.OfType() + .Where(d => config.Contains(d.Key)) + .ToDictionary(d => d.Key, d => d); + + return returnValue; + } + catch + { + Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Error getting devices. Check Essentials Configuration"); + return null; + } + } + + #region Overrides of EssentialsRoomBase + + protected override Func IsWarmingFeedbackFunc + { + get { throw new NotImplementedException(); } + } + + protected override Func IsCoolingFeedbackFunc + { + get { throw new NotImplementedException(); } + } + + protected override Func OnFeedbackFunc + { + get { throw new NotImplementedException(); } + } + + protected override void EndShutdown() + { + throw new NotImplementedException(); + } + + public override void SetDefaultLevels() + { + throw new NotImplementedException(); + } + + public override void PowerOnToDefaultOrLastSource() + { + throw new NotImplementedException(); + } + + public override bool RunDefaultPresentRoute() + { + throw new NotImplementedException(); + } + + public override void RoomVacatedForTimeoutPeriod(object o) + { + throw new NotImplementedException(); + } + + #endregion + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index 4f79626f..f0378691 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -1,178 +1,197 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; - using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - using PepperDash.Core; //using SSMono.IO; namespace PepperDash.Essentials.Core.Presets { - /// - /// Class that represents the model behind presets display - /// - public class DevicePresetsModel : Device - { - public event EventHandler PresetsLoaded; + /// + /// Class that represents the model behind presets display + /// + public class DevicePresetsModel : Device + { + private readonly bool _initSuccess; - public int PulseTime { get; set; } - public int DigitSpacingMS { get; set; } - public bool PresetsAreLoaded { get; private set; } + /// + /// The methods on the STB device to call when dialing + /// + private Dictionary> _dialFunctions; - public List PresetsList { get { return _PresetsList.ToList(); } } - List _PresetsList; - public int Count { get { return PresetsList != null ? PresetsList.Count : 0; } } + private bool _dialIsRunning; + private Action _enterFunction; + private string _filePath; - public bool UseLocalImageStorage { get; set; } - public string ImagesLocalHostPrefix { get; set; } - public string ImagesPathPrefix { get; set; } - public string ListPathPrefix { get; set; } + public DevicePresetsModel(string key, ISetTopBoxNumericKeypad setTopBox, string fileName) + : this(key, fileName) + { + try + { + // Grab the digit functions from the device + // If any fail, the whole thing fails peacefully + _dialFunctions = new Dictionary>(10) + { + {'1', setTopBox.Digit1}, + {'2', setTopBox.Digit2}, + {'3', setTopBox.Digit3}, + {'4', setTopBox.Digit4}, + {'5', setTopBox.Digit5}, + {'6', setTopBox.Digit6}, + {'7', setTopBox.Digit7}, + {'8', setTopBox.Digit8}, + {'9', setTopBox.Digit9}, + {'0', setTopBox.Digit0}, + {'-', setTopBox.Dash} + }; + } + catch + { + Debug.Console(0, "DevicePresets '{0}', not attached to INumericKeypad device. Ignoring", key); + _dialFunctions = null; + return; + } - /// - /// The methods on the STB device to call when dialing - /// - Dictionary> DialFunctions; - Action EnterFunction; + _enterFunction = setTopBox.KeypadEnter; + } - bool DialIsRunning; - string FilePath; - bool InitSuccess; - //SSMono.IO.FileSystemWatcher ListWatcher; + public DevicePresetsModel(string key, string fileName) : base(key) + { + PulseTime = 150; + DigitSpacingMs = 150; - public DevicePresetsModel(string key, ISetTopBoxNumericKeypad setTopBox, string fileName) - : base(key) - { - PulseTime = 150; - DigitSpacingMS = 150; + UseLocalImageStorage = true; - try - { - // Grab the digit functions from the device - // If any fail, the whole thing fails peacefully - DialFunctions = new Dictionary>(10) - { - { '1', setTopBox.Digit1 }, - { '2', setTopBox.Digit2 }, - { '3', setTopBox.Digit3 }, - { '4', setTopBox.Digit4 }, - { '5', setTopBox.Digit5 }, - { '6', setTopBox.Digit6 }, - { '7', setTopBox.Digit7 }, - { '8', setTopBox.Digit8 }, - { '9', setTopBox.Digit9 }, - { '0', setTopBox.Digit0 }, - { '-', setTopBox.Dash } - }; - } - catch - { - Debug.Console(0, "DevicePresets '{0}', not attached to INumericKeypad device. Ignoring", key); - DialFunctions = null; - return; - } + ImagesLocalHostPrefix = "http://" + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); + ImagesPathPrefix = @"/presets/images.zip/"; + ListPathPrefix = @"/html/presets/lists/"; - EnterFunction = setTopBox.KeypadEnter; + SetFileName(fileName); - UseLocalImageStorage = true; + _initSuccess = true; + } - ImagesLocalHostPrefix = "http://" + CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS,0); - ImagesPathPrefix = @"/presets/images.zip/"; - ListPathPrefix = @"/html/presets/lists/"; + public int PulseTime { get; set; } + public int DigitSpacingMs { get; set; } + public bool PresetsAreLoaded { get; private set; } - SetFileName(fileName); + public List PresetsList { get; private set; } - //ListWatcher = new FileSystemWatcher(@"\HTML\presets\lists"); - //ListWatcher.NotifyFilter = NotifyFilters.LastWrite; - //ListWatcher.EnableRaisingEvents = true; - //ListWatcher.Changed += ListWatcher_Changed; - InitSuccess = true; - } + public int Count + { + get { return PresetsList != null ? PresetsList.Count : 0; } + } + + public bool UseLocalImageStorage { get; set; } + public string ImagesLocalHostPrefix { get; set; } + public string ImagesPathPrefix { get; set; } + public string ListPathPrefix { get; set; } + public event EventHandler PresetsLoaded; - public void SetFileName(string path) - { - FilePath = ListPathPrefix + path; - LoadChannels(); - } + public void SetFileName(string path) + { + _filePath = ListPathPrefix + path; + LoadChannels(); + } - public void LoadChannels() - { - PresetsAreLoaded = false; - try - { - var pl = JsonConvert.DeserializeObject(Crestron.SimplSharp.CrestronIO.File.ReadToEnd(FilePath, Encoding.ASCII)); - Name = pl.Name; - _PresetsList = pl.Channels; - } - catch (Exception e) - { - Debug.Console(2, this, "LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}", FilePath, e.Message); - // Just save a default empty list - _PresetsList = new List(); - } - PresetsAreLoaded = true; + public void LoadChannels() + { + PresetsAreLoaded = false; + try + { + var pl = JsonConvert.DeserializeObject(File.ReadToEnd(_filePath, Encoding.ASCII)); + Name = pl.Name; + PresetsList = pl.Channels; + } + catch (Exception e) + { + Debug.Console(2, this, + "LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}", + _filePath, e.Message); + // Just save a default empty list + PresetsList = new List(); + } + PresetsAreLoaded = true; - var handler = PresetsLoaded; - if (handler != null) - handler(this, EventArgs.Empty); - } + var handler = PresetsLoaded; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } - public void Dial(int presetNum) - { - if (presetNum <= _PresetsList.Count) - Dial(_PresetsList[presetNum - 1].Channel); - } + public void Dial(int presetNum) + { + if (presetNum <= PresetsList.Count) + { + Dial(PresetsList[presetNum - 1].Channel); + } + } - public void Dial(string chanNum) - { - if (DialIsRunning || !InitSuccess) return; - if (DialFunctions == null) - { - Debug.Console(1, "DevicePresets '{0}', not attached to keypad device. Ignoring channel", Key); - return; - } + public void Dial(string chanNum) + { + if (_dialIsRunning || !_initSuccess) + { + return; + } + if (_dialFunctions == null) + { + Debug.Console(1, "DevicePresets '{0}', not attached to keypad device. Ignoring channel", Key); + return; + } - DialIsRunning = true; - CrestronInvoke.BeginInvoke(o => - { - foreach (var c in chanNum.ToCharArray()) - { - if (DialFunctions.ContainsKey(c)) - Pulse(DialFunctions[c]); - CrestronEnvironment.Sleep(DigitSpacingMS); - } + _dialIsRunning = true; + CrestronInvoke.BeginInvoke(o => + { + foreach (var c in chanNum.ToCharArray()) + { + if (_dialFunctions.ContainsKey(c)) + { + Pulse(_dialFunctions[c]); + } + CrestronEnvironment.Sleep(DigitSpacingMs); + } - if (EnterFunction != null) - Pulse(EnterFunction); - DialIsRunning = false; - }); - } + if (_enterFunction != null) + { + Pulse(_enterFunction); + } + _dialIsRunning = false; + }); + } - void Pulse(Action act) - { - act(true); - CrestronEnvironment.Sleep(PulseTime); - act(false); - } + public void Dial(string chanNum, ISetTopBoxNumericKeypad setTopBox) + { + _dialFunctions = new Dictionary>(10) + { + {'1', setTopBox.Digit1}, + {'2', setTopBox.Digit2}, + {'3', setTopBox.Digit3}, + {'4', setTopBox.Digit4}, + {'5', setTopBox.Digit5}, + {'6', setTopBox.Digit6}, + {'7', setTopBox.Digit7}, + {'8', setTopBox.Digit8}, + {'9', setTopBox.Digit9}, + {'0', setTopBox.Digit0}, + {'-', setTopBox.Dash} + }; - /// - /// Event handler for filesystem watcher. When directory changes, this is called - /// - //void ListWatcher_Changed(object sender, FileSystemEventArgs e) - //{ - // Debug.Console(1, this, "folder modified: {0}", e.FullPath); - // if (e.FullPath.Equals(FilePath, StringComparison.OrdinalIgnoreCase)) - // { - // Debug.Console(1, this, "File changed: {0}", e.ChangeType); - // LoadChannels(); - // } - //} - } + _enterFunction = setTopBox.KeypadEnter; + + Dial(chanNum); + } + + private void Pulse(Action act) + { + act(true); + CrestronEnvironment.Sleep(PulseTime); + act(false); + } + } } \ No newline at end of file From 7a8c1f31656e035d75c3449bef88d3530e82a98d Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 2 Dec 2020 13:37:53 -0700 Subject: [PATCH 07/59] adding some overloads --- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 2 ++ .../PepperDashEssentialsBase/Presets/DevicePresets.cs | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index ba87df5d..079a2ff6 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -26,6 +26,8 @@ namespace PepperDash.Essentials _tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), _config.PresetsFileName); + _tunerPresets.LoadChannels(); + _tuners = GetDevices(_config.Tuners); _displays = GetDevices(_config.Displays); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index f0378691..43fdf59a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -165,6 +165,14 @@ namespace PepperDash.Essentials.Core.Presets }); } + public void Dial(int presetNum, ISetTopBoxNumericKeypad setTopBox) + { + if (presetNum <= PresetsList.Count) + { + Dial(PresetsList[presetNum - 1].Channel, setTopBox); + } + } + public void Dial(string chanNum, ISetTopBoxNumericKeypad setTopBox) { _dialFunctions = new Dictionary>(10) From 9171610e343ab072bc553d00b5049081f78e2e50 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 3 Dec 2020 13:26:55 -0700 Subject: [PATCH 08/59] getting files back in the project --- PepperDashEssentials/PepperDashEssentials.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 42d0e288..969c1f40 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -141,11 +141,13 @@ + + From 9888fbf047b6a2672895de256d2c13b892754553 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Dec 2020 13:24:00 -0700 Subject: [PATCH 09/59] added save presets method & expose some properties --- .../Room/Types/EssentialsTechRoom.cs | 60 +++++++++++++++++-- .../Presets/DevicePresets.cs | 22 +++++++ 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index 079a2ff6..0680f46b 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -12,13 +12,37 @@ namespace PepperDash.Essentials { public class EssentialsTechRoom:EssentialsRoomBase { - private Dictionary _tuners; - private Dictionary _displays; + private readonly Dictionary _tuners; + private readonly Dictionary _displays; - private DevicePresetsModel _tunerPresets; + private readonly DevicePresetsModel _tunerPresets; private readonly EssentialsTechRoomConfig _config; + public DevicePresetsModel TunerPresets + { + get + { + return _tunerPresets; + } + } + + public Dictionary Tuners + { + get { return _tuners; } + } + + public Dictionary Displays + { + get { return _displays; } + } + + public BoolFeedback RoomPowerIsOnFeedback { get; private set; } + + public bool RoomPowerIsOn + { + get { return _displays.All(kv => kv.Value.PowerIsOnFeedback.BoolValue); } + } public EssentialsTechRoom(DeviceConfig config) : base(config) { @@ -30,6 +54,32 @@ namespace PepperDash.Essentials _tuners = GetDevices(_config.Tuners); _displays = GetDevices(_config.Displays); + + RoomPowerIsOnFeedback = new BoolFeedback(() => RoomPowerIsOn); + } + + private void SubscribeToDisplayFeedbacks() + { + foreach (var display in _displays) + { + display.Value.PowerIsOnFeedback.OutputChange += (sender, args) => RoomPowerIsOnFeedback.InvokeFireUpdate(); + } + } + + public void RoomPowerOn() + { + foreach (var display in _displays) + { + display.Value.PowerOn(); + } + } + + public void RoomPowerOff() + { + foreach (var display in _displays) + { + display.Value.PowerOff(); + } } private Dictionary GetDevices(ICollection config) where T:IKeyed @@ -47,7 +97,9 @@ namespace PepperDash.Essentials Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Error getting devices. Check Essentials Configuration"); return null; } - } + } + + #region Overrides of EssentialsRoomBase diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index 43fdf59a..ccce6ea7 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -195,6 +195,28 @@ namespace PepperDash.Essentials.Core.Presets Dial(chanNum); } + public void UpdatePreset(int index, PresetChannel preset) + { + if (index >= PresetsList.Count) + { + return; + } + + PresetsList[index] = preset; + + SavePresets(); + } + + private void SavePresets() + { + var json = JsonConvert.SerializeObject(PresetsList); + + using (var file = File.Open(_filePath, FileMode.Truncate)) + { + file.Write(json, Encoding.UTF8); + } + } + private void Pulse(Action act) { act(true); From f11bdcfd539f9300fc6ebdd3c20f6e8170014689 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Dec 2020 16:21:48 -0700 Subject: [PATCH 10/59] add schedule config and schedule stuff --- .../Room/Config/EssentialsTechRoomConfig.cs | 2 + .../Room/Types/EssentialsTechRoom.cs | 68 +++++++++++++++++++ .../Global/Scheduler.cs | 36 ++++++++++ .../EssentialsRoomScheduledEventsConfig.cs | 37 ++++++++++ 4 files changed, 143 insertions(+) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs diff --git a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs index 8f35461b..3e4e0dc7 100644 --- a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs @@ -10,11 +10,13 @@ namespace PepperDash.Essentials.Room.Config public string UserPin; public string TechPin; public string PresetsFileName; + public EssentialsRoomScheduledEventsConfig RoomScheduledEvents; public EssentialsTechRoomConfig() { Displays = new List(); Tuners = new List(); + RoomScheduledEvents = new EssentialsRoomScheduledEventsConfig(); } } } \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index 0680f46b..7a6d9c7e 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using Crestron.SimplSharp; +using Crestron.SimplSharp.Scheduler; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; @@ -19,6 +21,8 @@ namespace PepperDash.Essentials private readonly EssentialsTechRoomConfig _config; + private ScheduledEventGroup _roomScheduledEventGroup; + public DevicePresetsModel TunerPresets { get @@ -56,6 +60,10 @@ namespace PepperDash.Essentials _displays = GetDevices(_config.Displays); RoomPowerIsOnFeedback = new BoolFeedback(() => RoomPowerIsOn); + + SubscribeToDisplayFeedbacks(); + + CreateScheduledEvents(); } private void SubscribeToDisplayFeedbacks() @@ -66,6 +74,66 @@ namespace PepperDash.Essentials } } + private void CreateScheduledEvents() + { + var eventsConfig = _config.RoomScheduledEvents; + + _roomScheduledEventGroup = new ScheduledEventGroup(Key); + + _roomScheduledEventGroup.RetrieveAllEvents(); + + Scheduler.AddEventGroup(_roomScheduledEventGroup); + + foreach (var eventConfig in eventsConfig.ScheduledEvents) + { + if (!_roomScheduledEventGroup.ScheduledEvents.ContainsKey(eventConfig.Name)) + { + SchedulerUtilities.CreateEventFromConfig(eventConfig, _roomScheduledEventGroup); + continue; + } + + var roomEvent = _roomScheduledEventGroup.ScheduledEvents[eventConfig.Key]; + + if (!SchedulerUtilities.CheckEventTimeForMatch(roomEvent, DateTime.Parse(eventConfig.Time)) && + !SchedulerUtilities.CheckEventRecurrenceForMatch(roomEvent, eventConfig.Days)) + { + continue; + } + Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", roomEvent.Name); + + _roomScheduledEventGroup.DeleteEvent(roomEvent); + + SchedulerUtilities.CreateEventFromConfig(eventConfig, _roomScheduledEventGroup); + } + + _roomScheduledEventGroup.UserGroupCallBack += HandleScheduledEvent; + } + + private void HandleScheduledEvent(ScheduledEvent schevent, ScheduledEventCommon.eCallbackReason type) + { + var eventConfig = _config.RoomScheduledEvents.ScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name); + + if (eventConfig == null) + { + Debug.Console(1, this, "Event with name {0} not found", schevent.Name); + return; + } + + if (eventConfig.Acknowledgeable) + { + schevent.Acknowledge(); + } + + CrestronInvoke.BeginInvoke((o) => + { + foreach (var a in eventConfig.Actions) + { + DeviceJsonApi.DoDeviceAction(a.Value); + } + }); + } + + public void RoomPowerOn() { foreach (var display in _displays) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs index a7b721ef..85832cba 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs @@ -6,6 +6,8 @@ using Crestron.SimplSharp; using Crestron.SimplSharp.Scheduler; using PepperDash.Core; +using PepperDash.Essentials.Core.Fusion; +using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Core { @@ -135,5 +137,39 @@ namespace PepperDash.Essentials.Core return isMatch; } + + public static bool CheckEventTimeForMatch(ScheduledEvent evnt, DateTime time) + { + return evnt.DateAndTime.Hour == time.Hour && evnt.DateAndTime.Minute == time.Minute; + } + + public static bool CheckEventRecurrenceForMatch(ScheduledEvent evnt, ScheduledEventCommon.eWeekDays days) + { + return evnt.Recurrence.RecurrenceDays == days; + } + + public static void CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group) + { + if (group == null) + { + Debug.Console(0, "Unable to create event. Group is null"); + return; + } + var scheduledEvent = new ScheduledEvent(config.Key, group) + { + Acknowledgeable = config.Acknowledgeable, + Persistent = config.Persistent + }; + + scheduledEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); + + scheduledEvent.Recurrence.Weekly(config.Days); + + var eventTime = DateTime.Parse(config.Time); + + if (DateTime.Now < eventTime) eventTime.AddDays(1); + + scheduledEvent.DateAndTime.SetAbsoluteEventTime(eventTime); + } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs new file mode 100644 index 00000000..50c77f1f --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Crestron.SimplSharp.Scheduler; +using Newtonsoft.Json; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.Room.Config +{ + public class EssentialsRoomScheduledEventsConfig + { + [JsonProperty("scheduledEvents")] + public List ScheduledEvents; + } + + public class ScheduledEventConfig + { + [JsonProperty("key")] + public string Key; + + [JsonProperty("name")] + public string Name; + + [JsonProperty("days")] + public ScheduledEventCommon.eWeekDays Days; + + [JsonProperty("time")] + public string Time; + + [JsonProperty("actions")] + public Dictionary Actions; + + [JsonProperty("persistent")] + public bool Persistent; + + [JsonProperty("acknowledgeable")] + public bool Acknowledgeable; + } +} \ No newline at end of file From 45c1e25e4fb50166e9cfc0ec95985f1dffe82b26 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Dec 2020 21:35:31 -0700 Subject: [PATCH 11/59] Change to list of actions instead of dictionary --- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 2 +- .../Room/Config/EssentialsRoomScheduledEventsConfig.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index 7a6d9c7e..f0521d64 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -128,7 +128,7 @@ namespace PepperDash.Essentials { foreach (var a in eventConfig.Actions) { - DeviceJsonApi.DoDeviceAction(a.Value); + DeviceJsonApi.DoDeviceAction(a); } }); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs index 50c77f1f..e16524ce 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs @@ -26,7 +26,7 @@ namespace PepperDash.Essentials.Room.Config public string Time; [JsonProperty("actions")] - public Dictionary Actions; + public List Actions; [JsonProperty("persistent")] public bool Persistent; From fc5d4f946d0c7438d56dd411178fee5eddfdbfd8 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 4 Dec 2020 21:36:07 -0700 Subject: [PATCH 12/59] added scheduled events config --- .../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 6d4def73..1a2fc594 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -278,6 +278,7 @@ + From 05e2422cb405be3a0df6c2c4ae04ea379d27f560 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 11:48:07 -0700 Subject: [PATCH 13/59] refactoring some methods add handling for Scheduled Events --- .../Room/Types/EssentialsTechRoom.cs | 167 ++++++++++++------ 1 file changed, 110 insertions(+), 57 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index f0521d64..cb8ebfa1 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.Scheduler; +using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; @@ -12,23 +13,37 @@ using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials { - public class EssentialsTechRoom:EssentialsRoomBase + public class EssentialsTechRoom : EssentialsRoomBase { - private readonly Dictionary _tuners; + private readonly EssentialsTechRoomConfig _config; private readonly Dictionary _displays; private readonly DevicePresetsModel _tunerPresets; - - private readonly EssentialsTechRoomConfig _config; + private readonly Dictionary _tuners; private ScheduledEventGroup _roomScheduledEventGroup; + public EssentialsTechRoom(DeviceConfig config) : base(config) + { + _config = config.Properties.ToObject(); + + _tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), _config.PresetsFileName); + + _tunerPresets.LoadChannels(); + + _tuners = GetDevices(_config.Tuners); + _displays = GetDevices(_config.Displays); + + RoomPowerIsOnFeedback = new BoolFeedback(() => RoomPowerIsOn); + + SubscribeToDisplayFeedbacks(); + + CreateOrUpdateScheduledEvents(); + } + public DevicePresetsModel TunerPresets { - get - { - return _tunerPresets; - } + get { return _tunerPresets; } } public Dictionary Tuners @@ -48,70 +63,104 @@ namespace PepperDash.Essentials get { return _displays.All(kv => kv.Value.PowerIsOnFeedback.BoolValue); } } - public EssentialsTechRoom(DeviceConfig config) : base(config) - { - _config = config.Properties.ToObject(); - - _tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), _config.PresetsFileName); - - _tunerPresets.LoadChannels(); - - _tuners = GetDevices(_config.Tuners); - _displays = GetDevices(_config.Displays); - - RoomPowerIsOnFeedback = new BoolFeedback(() => RoomPowerIsOn); - - SubscribeToDisplayFeedbacks(); - - CreateScheduledEvents(); - } - private void SubscribeToDisplayFeedbacks() { foreach (var display in _displays) { - display.Value.PowerIsOnFeedback.OutputChange += (sender, args) => RoomPowerIsOnFeedback.InvokeFireUpdate(); + display.Value.PowerIsOnFeedback.OutputChange += + (sender, args) => RoomPowerIsOnFeedback.InvokeFireUpdate(); } } - private void CreateScheduledEvents() + private void CreateOrUpdateScheduledEvents() { var eventsConfig = _config.RoomScheduledEvents; - _roomScheduledEventGroup = new ScheduledEventGroup(Key); + GetOrCreateScheduleGroup(); - _roomScheduledEventGroup.RetrieveAllEvents(); - - Scheduler.AddEventGroup(_roomScheduledEventGroup); - - foreach (var eventConfig in eventsConfig.ScheduledEvents) + foreach (var eventConfig in eventsConfig) { - if (!_roomScheduledEventGroup.ScheduledEvents.ContainsKey(eventConfig.Name)) - { - SchedulerUtilities.CreateEventFromConfig(eventConfig, _roomScheduledEventGroup); - continue; - } - - var roomEvent = _roomScheduledEventGroup.ScheduledEvents[eventConfig.Key]; - - if (!SchedulerUtilities.CheckEventTimeForMatch(roomEvent, DateTime.Parse(eventConfig.Time)) && - !SchedulerUtilities.CheckEventRecurrenceForMatch(roomEvent, eventConfig.Days)) - { - continue; - } - Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", roomEvent.Name); - - _roomScheduledEventGroup.DeleteEvent(roomEvent); - - SchedulerUtilities.CreateEventFromConfig(eventConfig, _roomScheduledEventGroup); + CreateOrUpdateSingleEvent(eventConfig); } _roomScheduledEventGroup.UserGroupCallBack += HandleScheduledEvent; } + private void GetOrCreateScheduleGroup() + { + if (_roomScheduledEventGroup == null) + { + _roomScheduledEventGroup = Scheduler.GetEventGroup(Key) ?? new ScheduledEventGroup(Key); + + Scheduler.AddEventGroup(_roomScheduledEventGroup); + } + + _roomScheduledEventGroup.RetrieveAllEvents(); + } + + private void CreateOrUpdateSingleEvent(ScheduledEventConfig scheduledEvent) + { + if (!_roomScheduledEventGroup.ScheduledEvents.ContainsKey(scheduledEvent.Name)) + { + SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup); + return; + } + + var roomEvent = _roomScheduledEventGroup.ScheduledEvents[scheduledEvent.Key]; + + if (!SchedulerUtilities.CheckEventTimeForMatch(roomEvent, DateTime.Parse(scheduledEvent.Time)) && + !SchedulerUtilities.CheckEventRecurrenceForMatch(roomEvent, scheduledEvent.Days)) + { + return; + } + + Debug.Console(1, this, + "Existing event does not match new config properties. Deleting existing event '{0}' and creating new event from configuration", + roomEvent.Name); + + _roomScheduledEventGroup.DeleteEvent(roomEvent); + + SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup); + } + + public void AddOrUpdateScheduledEvent(ScheduledEventConfig scheduledEvent) + { + //update config based on key of scheduleEvent + GetOrCreateScheduleGroup(); + var existingEvent = _config.RoomScheduledEvents.FirstOrDefault(e => e.Key == scheduledEvent.Key); + + if (existingEvent == null) + { + _config.RoomScheduledEvents.Add(scheduledEvent); + } + + //create or update event based on config + CreateOrUpdateSingleEvent(scheduledEvent); + //save config + Config.Properties = JToken.FromObject(_config); + + CustomSetConfig(Config); + //Fire Event + OnScheduledEventUpdate(); + } + + public void OnScheduledEventUpdate() + { + var handler = ScheduledEventsChanged; + + if (handler == null) + { + return; + } + + handler(this, new ScheduledEventEventArgs {ScheduledEvents = _config.RoomScheduledEvents}); + } + + public event EventHandler ScheduledEventsChanged; + private void HandleScheduledEvent(ScheduledEvent schevent, ScheduledEventCommon.eCallbackReason type) { - var eventConfig = _config.RoomScheduledEvents.ScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name); + var eventConfig = _config.RoomScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name); if (eventConfig == null) { @@ -150,7 +199,7 @@ namespace PepperDash.Essentials } } - private Dictionary GetDevices(ICollection config) where T:IKeyed + private Dictionary GetDevices(ICollection config) where T : IKeyed { try { @@ -162,13 +211,12 @@ namespace PepperDash.Essentials } catch { - Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Error getting devices. Check Essentials Configuration"); + Debug.Console(0, this, Debug.ErrorLogLevel.Error, + "Error getting devices. Check Essentials Configuration"); return null; } } - - #region Overrides of EssentialsRoomBase protected override Func IsWarmingFeedbackFunc @@ -213,4 +261,9 @@ namespace PepperDash.Essentials #endregion } + + public class ScheduledEventEventArgs : EventArgs + { + public List ScheduledEvents; + } } \ No newline at end of file From 3a024b8d4c0cb08cd94c5060a0cb07da795026b9 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 11:48:21 -0700 Subject: [PATCH 14/59] moved ScheduledEvents list to main object --- PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs index 3e4e0dc7..e4b88e96 100644 --- a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs @@ -10,13 +10,13 @@ namespace PepperDash.Essentials.Room.Config public string UserPin; public string TechPin; public string PresetsFileName; - public EssentialsRoomScheduledEventsConfig RoomScheduledEvents; + public List RoomScheduledEvents; public EssentialsTechRoomConfig() { Displays = new List(); Tuners = new List(); - RoomScheduledEvents = new EssentialsRoomScheduledEventsConfig(); + RoomScheduledEvents = new List(); } } } \ No newline at end of file From 0dc2e9d134e185d68a28e4fea0e13c19a3bb96f7 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 11:48:34 -0700 Subject: [PATCH 15/59] Added logic to create EssentialsTechRoom --- PepperDashEssentials/ControlSystem.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 460086e0..4e24de9f 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -12,6 +12,7 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Fusion; using PepperDash.Essentials.Devices.Common; using PepperDash.Essentials.DM; using PepperDash.Essentials.Fusion; @@ -436,7 +437,7 @@ namespace PepperDash.Essentials DeviceManager.AddDevice(room); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion"); - DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase((EssentialsHuddleSpaceRoom)room, 0xf1)); + DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase(room, 0xf1)); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge..."); @@ -454,6 +455,18 @@ namespace PepperDash.Essentials CreateMobileControlBridge(room); } + else if (room is EssentialsTechRoom) + { + DeviceManager.AddDevice(room); + + Debug.Console(0, Debug.ErrorLogLevel.Notice, + "Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion"); + DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemControllerBase(room, 0xF1)); + + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge"); + + CreateMobileControlBridge(room); + } else { Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsRoom, attempting to add to DeviceManager w/o Fusion"); From ab6d44e60461497e9ec29c1b178aa986fb220feb Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 11:48:48 -0700 Subject: [PATCH 16/59] added enable property to ScheduledEventConfig --- .../Room/Config/EssentialsRoomScheduledEventsConfig.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs index e16524ce..366f453c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs @@ -33,5 +33,8 @@ namespace PepperDash.Essentials.Room.Config [JsonProperty("acknowledgeable")] public bool Acknowledgeable; + + [JsonProperty("enable")] + public bool Enable; } } \ No newline at end of file From d2b7e71c4adb254b8ff406d03c9e52b3e874a1d8 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 11:49:30 -0700 Subject: [PATCH 17/59] Added GetScheduledEventGroup Method added logic to enable/disable events --- .../Global/Scheduler.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs index 85832cba..64ba57df 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharp.Scheduler; using PepperDash.Core; -using PepperDash.Essentials.Core.Fusion; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Core @@ -16,7 +13,7 @@ namespace PepperDash.Essentials.Core /// public static class Scheduler { - private static Dictionary EventGroups = new Dictionary(); + private static readonly Dictionary EventGroups = new Dictionary(); static Scheduler() { @@ -51,7 +48,6 @@ namespace PepperDash.Essentials.Core /// /// Adds the event group to the global list /// - /// /// public static void AddEventGroup(ScheduledEventGroup eventGroup) { @@ -69,6 +65,13 @@ namespace PepperDash.Essentials.Core if(!EventGroups.ContainsKey(eventGroup.Name)) EventGroups.Remove(eventGroup.Name); } + + public static ScheduledEventGroup GetEventGroup(string key) + { + ScheduledEventGroup returnValue; + + return EventGroups.TryGetValue(key, out returnValue) ? returnValue : null; + } } public static class SchedulerUtilities @@ -161,6 +164,15 @@ namespace PepperDash.Essentials.Core Persistent = config.Persistent }; + if (config.Enable) + { + scheduledEvent.Resume(); + } + else + { + scheduledEvent.Pause(); + } + scheduledEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); scheduledEvent.Recurrence.Weekly(config.Days); From 43d7fab04d25a27456f30a603505634c353aecf7 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 11:50:48 -0700 Subject: [PATCH 18/59] refactored Fusion Base Class --- ...lsHuddleSpaceFusionSystemControllerBase.cs | 1769 +++++++++-------- 1 file changed, 952 insertions(+), 817 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index 39cd7d78..9270ed37 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -2,164 +2,118 @@ using System.Collections.Generic; using System.Linq; using System.Text; - using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronXml; using Crestron.SimplSharp.CrestronXml.Serialization; -using Crestron.SimplSharp.CrestronXmlLinq; using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.Fusion; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - using PepperDash.Core; -using PepperDash.Essentials; -using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; - - namespace PepperDash.Essentials.Core.Fusion { - public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider - { - public event EventHandler ScheduleChange; - //public event EventHandler MeetingEndWarning; - //public event EventHandler NextMeetingBeginWarning; + public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider + { + private const string RemoteOccupancyXml = "Local{0}"; + private readonly bool _guidFileExists; - public event EventHandler RoomInfoChange; + private readonly Dictionary _sourceToFeedbackSigs = + new Dictionary(); + + protected StringSigData CurrentRoomSourceNameSig; public FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge(); + protected FusionOccupancySensorAsset FusionOccSensor; + protected FusionRemoteOccupancySensor FusionRemoteOccSensor; - protected FusionRoom FusionRoom; - protected EssentialsRoomBase Room; - Dictionary SourceToFeedbackSigs = - new Dictionary(); + protected FusionRoom FusionRoom; + protected Dictionary FusionStaticAssets; + public long PushNotificationTimeout = 5000; + protected EssentialsRoomBase Room; + public long SchedulePollInterval = 300000; - StatusMonitorCollection ErrorMessageRollUp; + private Event _currentMeeting; + private RoomSchedule _currentSchedule; + private CTimer _dailyTimeRequestTimer; + private StatusMonitorCollection _errorMessageRollUp; - protected StringSigData CurrentRoomSourceNameSig; + private FusionRoomGuids _guiDs; + private uint _ipId; + + private bool _isRegisteredForSchedulePushNotifications; + private Event _nextMeeting; + + private CTimer _pollTimer; + + private CTimer _pushNotificationTimer; + + private string _roomOccupancyRemoteString; #region System Info Sigs + //StringSigData SystemName; //StringSigData Model; //StringSigData SerialNumber; //StringSigData Uptime; + #endregion - #region Processor Info Sigs - StringSigData Ip1; - StringSigData Ip2; - StringSigData Gateway; - StringSigData Hostname; - StringSigData Domain; - StringSigData Dns1; - StringSigData Dns2; - StringSigData Mac1; - StringSigData Mac2; - StringSigData NetMask1; - StringSigData NetMask2; - StringSigData Firmware; - StringSigData[] Program = new StringSigData[10]; + private readonly StringSigData[] _program = new StringSigData[10]; + private StringSigData _dns1; + private StringSigData _dns2; + private StringSigData _domain; + private StringSigData _firmware; + private StringSigData _gateway; + private StringSigData _hostname; + private StringSigData _ip1; + private StringSigData _ip2; + private StringSigData _mac1; + private StringSigData _mac2; + private StringSigData _netMask1; + private StringSigData _netMask2; + #endregion #region Default Display Source Sigs - BooleanSigData[] Source = new BooleanSigData[10]; + private BooleanSigData[] _source = new BooleanSigData[10]; #endregion - RoomSchedule CurrentSchedule; - - Event NextMeeting; - - Event CurrentMeeting; - - protected string RoomGuid - { - get - { - return GUIDs.RoomGuid; - } - - } - - uint IpId; - - FusionRoomGuids GUIDs; - - bool GuidFileExists; - - bool IsRegisteredForSchedulePushNotifications = false; - - CTimer PollTimer = null; - - CTimer PushNotificationTimer = null; - - CTimer DailyTimeRequestTimer = null; - - // Default poll time is 5 min unless overridden by config value - public long SchedulePollInterval = 300000; - - public long PushNotificationTimeout = 5000; - - private const string RemoteOccupancyXml = "Local{0}"; - - protected Dictionary FusionStaticAssets; - - // For use with local occ sensor devices which will relay to Fusion the current occupancy status - protected FusionRemoteOccupancySensor FusionRemoteOccSensor; - - // For use with occ sensor attached to a scheduling panel in Fusion - protected FusionOccupancySensorAsset FusionOccSensor; - - public BoolFeedback RoomIsOccupiedFeedback { get; private set; } - - private string _roomOccupancyRemoteString; - public StringFeedback RoomOccupancyRemoteStringFeedback { get; private set; } - - protected Func RoomIsOccupiedFeedbackFunc - { - get - { - return () => FusionRemoteOccSensor.RoomOccupied.OutputSig.BoolValue; - } - } - - //ScheduleResponseEvent NextMeeting; - public EssentialsHuddleSpaceFusionSystemControllerBase(EssentialsRoomBase room, uint ipId) - : base(room.Key + "-fusion") - { - + : base(room.Key + "-fusion") + { try { - Room = room; - IpId = ipId; + _ipId = ipId; FusionStaticAssets = new Dictionary(); - GUIDs = new FusionRoomGuids(); + _guiDs = new FusionRoomGuids(); - var mac = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); + var mac = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); var slot = Global.ControlSystem.ProgramNumber; - string guidFilePath = Global.FilePathPrefix + string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); + var guidFilePath = Global.FilePathPrefix + + string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); - GuidFileExists = File.Exists(guidFilePath); + _guidFileExists = File.Exists(guidFilePath); // Check if file exists - if (!GuidFileExists) + if (!_guidFileExists) { // Does not exist. Create GUIDs - GUIDs = new FusionRoomGuids(Room.Name, ipId, GUIDs.GenerateNewRoomGuid(slot, mac), FusionStaticAssets); + _guiDs = new FusionRoomGuids(Room.Name, ipId, _guiDs.GenerateNewRoomGuid(slot, mac), + FusionStaticAssets); } else { @@ -170,18 +124,19 @@ namespace PepperDash.Essentials.Core.Fusion if (Room.RoomOccupancy != null) { if (Room.OccupancyStatusProviderIsRemote) + { SetUpRemoteOccupancy(); + } else { SetUpLocalOccupancy(); } } - AddPostActivationAction(() => { - CreateSymbolAndBasicSigs(IpId); + CreateSymbolAndBasicSigs(_ipId); SetUpSources(); SetUpCommunitcationMonitors(); SetUpDisplay(); @@ -192,27 +147,51 @@ namespace PepperDash.Essentials.Core.Fusion GenerateGuidFile(guidFilePath); }); - } catch (Exception e) { Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Error Building Fusion System Controller: {0}", e); } - } + } + + protected string RoomGuid + { + get { return _guiDs.RoomGuid; } + } + + public StringFeedback RoomOccupancyRemoteStringFeedback { get; private set; } + + protected Func RoomIsOccupiedFeedbackFunc + { + get { return () => FusionRemoteOccSensor.RoomOccupied.OutputSig.BoolValue; } + } + + #region IOccupancyStatusProvider Members + + public BoolFeedback RoomIsOccupiedFeedback { get; private set; } + + #endregion + + public event EventHandler ScheduleChange; + //public event EventHandler MeetingEndWarning; + //public event EventHandler NextMeetingBeginWarning; + + public event EventHandler RoomInfoChange; + + //ScheduleResponseEvent NextMeeting; /// /// Used for extension classes to execute whatever steps are necessary before generating the RVI and GUID files /// protected virtual void ExecuteCustomSteps() { - } /// /// Generates the guid file in NVRAM. If the file already exists it will be overwritten. /// /// path for the file - void GenerateGuidFile(string filePath) + private void GenerateGuidFile(string filePath) { if (string.IsNullOrEmpty(filePath)) { @@ -220,32 +199,32 @@ namespace PepperDash.Essentials.Core.Fusion return; } - CCriticalSection _fileLock = new CCriticalSection(); + var fileLock = new CCriticalSection(); try { - if (_fileLock == null || _fileLock.Disposed) + if (fileLock.Disposed) + { return; + } - _fileLock.Enter(); + fileLock.Enter(); Debug.Console(1, this, "Writing GUIDs to file"); - if (FusionOccSensor == null) - GUIDs = new FusionRoomGuids(Room.Name, IpId, RoomGuid, FusionStaticAssets); - else - GUIDs = new FusionRoomGuids(Room.Name, IpId, RoomGuid, FusionStaticAssets, FusionOccSensor); + _guiDs = FusionOccSensor == null + ? new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets) + : new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets, FusionOccSensor); - var JSON = JsonConvert.SerializeObject(GUIDs, Newtonsoft.Json.Formatting.Indented); + var json = JsonConvert.SerializeObject(_guiDs, Newtonsoft.Json.Formatting.Indented); - using (StreamWriter sw = new StreamWriter(filePath)) + using (var sw = new StreamWriter(filePath)) { - sw.Write(JSON); + sw.Write(json); sw.Flush(); } Debug.Console(1, this, "Guids successfully written to file '{0}'", filePath); - } catch (Exception e) { @@ -253,8 +232,10 @@ namespace PepperDash.Essentials.Core.Fusion } finally { - if (_fileLock != null && !_fileLock.Disposed) - _fileLock.Leave(); + if (!fileLock.Disposed) + { + fileLock.Leave(); + } } } @@ -262,42 +243,45 @@ namespace PepperDash.Essentials.Core.Fusion /// Reads the guid file from NVRAM /// /// path for te file - void ReadGuidFile(string filePath) + private void ReadGuidFile(string filePath) { - if(string.IsNullOrEmpty(filePath)) + if (string.IsNullOrEmpty(filePath)) { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Error reading guid file. No path specified."); return; } - CCriticalSection _fileLock = new CCriticalSection(); + var fileLock = new CCriticalSection(); try { - if(_fileLock == null || _fileLock.Disposed) - return; - - _fileLock.Enter(); - - if(File.Exists(filePath)) + if (fileLock.Disposed) { - var JSON = File.ReadToEnd(filePath, Encoding.ASCII); - - GUIDs = JsonConvert.DeserializeObject(JSON); - - IpId = GUIDs.IpId; - - FusionStaticAssets = GUIDs.StaticAssets; - + return; } - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Fusion Guids successfully read from file: {0}", filePath); + fileLock.Enter(); - Debug.Console(1, this, "\nRoom Name: {0}\nIPID: {1:x}\n RoomGuid: {2}", Room.Name, IpId, RoomGuid); + if (File.Exists(filePath)) + { + var json = File.ReadToEnd(filePath, Encoding.ASCII); + + _guiDs = JsonConvert.DeserializeObject(json); + + _ipId = _guiDs.IpId; + + FusionStaticAssets = _guiDs.StaticAssets; + } + + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Fusion Guids successfully read from file: {0}", + filePath); + + Debug.Console(1, this, "\nRoom Name: {0}\nIPID: {1:x}\n RoomGuid: {2}", Room.Name, _ipId, RoomGuid); foreach (var item in FusionStaticAssets) { - Debug.Console(1, this, "\nAsset Name: {0}\nAsset No: {1}\n Guid: {2}", item.Value.Name, item.Value.SlotNumber, item.Value.InstanceId); + Debug.Console(1, this, "\nAsset Name: {0}\nAsset No: {1}\n Guid: {2}", item.Value.Name, + item.Value.SlotNumber, item.Value.InstanceId); } } catch (Exception e) @@ -306,46 +290,65 @@ namespace PepperDash.Essentials.Core.Fusion } finally { - if(_fileLock != null && !_fileLock.Disposed) - _fileLock.Leave(); + if (!fileLock.Disposed) + { + fileLock.Leave(); + } } - } - protected virtual void CreateSymbolAndBasicSigs(uint ipId) - { + protected virtual void CreateSymbolAndBasicSigs(uint ipId) + { Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating Fusion Room symbol with GUID: {0}", RoomGuid); FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use(); FusionRoom.ExtenderFusionRoomDataReservedSigs.Use(); - FusionRoom.Register(); + FusionRoom.Register(); - FusionRoom.FusionStateChange += new FusionStateEventHandler(FusionRoom_FusionStateChange); + FusionRoom.FusionStateChange += FusionRoom_FusionStateChange; - FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange += new DeviceExtenderJoinChangeEventHandler(FusionRoomSchedule_DeviceExtenderSigChange); - FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange += new DeviceExtenderJoinChangeEventHandler(ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange); - FusionRoom.OnlineStatusChange += new OnlineStatusChangeEventHandler(FusionRoom_OnlineStatusChange); + FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.DeviceExtenderSigChange += + FusionRoomSchedule_DeviceExtenderSigChange; + FusionRoom.ExtenderFusionRoomDataReservedSigs.DeviceExtenderSigChange += + ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange; + FusionRoom.OnlineStatusChange += FusionRoom_OnlineStatusChange; - CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator); - CrestronConsole.AddNewConsoleCommand(CreateAsHocMeeting, "FusCreateMeeting", "Creates and Ad Hoc meeting for on hour or until the next meeting", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", + "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", + "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(CreateAsHocMeeting, "FusCreateMeeting", + "Creates and Ad Hoc meeting for on hour or until the next meeting", + ConsoleAccessLevelEnum.AccessOperator); - // Room to fusion room - Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig); + // Room to fusion room + Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig); // Moved to - CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source", eSigIoMask.InputSigOnly); - // Don't think we need to get current status of this as nothing should be alive yet. - (Room as IHasCurrentSourceInfoChange).CurrentSourceChange += new SourceInfoChangeHandler(Room_CurrentSourceInfoChange); + CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source", + eSigIoMask.InputSigOnly); + // Don't think we need to get current status of this as nothing should be alive yet. + var hasCurrentSourceInfoChange = Room as IHasCurrentSourceInfoChange; + if (hasCurrentSourceInfoChange != null) + { + hasCurrentSourceInfoChange.CurrentSourceChange += Room_CurrentSourceInfoChange; + } - FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsRoomBase).PowerOnToDefaultOrLastSource); - FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as IRunRouteAction).RunRouteAction("roomOff", Room.SourceListKey)); - // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); - FusionRoom.ErrorMessage.InputSig.StringValue = - "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; + FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction(Room.PowerOnToDefaultOrLastSource); + FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => + { + var runRouteAction = Room as IRunRouteAction; + if (runRouteAction != null) + { + runRouteAction.RunRouteAction("roomOff", Room.SourceListKey); + } + }); + // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); + FusionRoom.ErrorMessage.InputSig.StringValue = + "3: 7 Errors: This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;This is a really long error message;"; SetUpEthernetValues(); @@ -355,7 +358,7 @@ namespace PepperDash.Essentials.Core.Fusion GetProcessorInfo(); - CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); + CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } protected void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) @@ -372,82 +375,107 @@ namespace PepperDash.Essentials.Core.Fusion //Model.InputSig.StringValue = InitialParametersClass.ControllerPromptName; //SerialNumber.InputSig.StringValue = InitialParametersClass. - string response = string.Empty; + var response = string.Empty; var systemReboot = FusionRoom.CreateOffsetBoolSig(74, "Processor - Reboot", eSigIoMask.OutputSigOnly); - systemReboot.OutputSig.SetSigFalseAction(() => CrestronConsole.SendControlSystemCommand("reboot", ref response)); + systemReboot.OutputSig.SetSigFalseAction( + () => CrestronConsole.SendControlSystemCommand("reboot", ref response)); } protected void SetUpEthernetValues() { - Ip1 = FusionRoom.CreateOffsetStringSig(50, "Info - Processor - IP 1", eSigIoMask.InputSigOnly); - Ip2 = FusionRoom.CreateOffsetStringSig(51, "Info - Processor - IP 2", eSigIoMask.InputSigOnly); - Gateway = FusionRoom.CreateOffsetStringSig(52, "Info - Processor - Gateway", eSigIoMask.InputSigOnly); - Hostname = FusionRoom.CreateOffsetStringSig(53, "Info - Processor - Hostname", eSigIoMask.InputSigOnly); - Domain = FusionRoom.CreateOffsetStringSig(54, "Info - Processor - Domain", eSigIoMask.InputSigOnly); - Dns1 = FusionRoom.CreateOffsetStringSig(55, "Info - Processor - DNS 1", eSigIoMask.InputSigOnly); - Dns2 = FusionRoom.CreateOffsetStringSig(56, "Info - Processor - DNS 2", eSigIoMask.InputSigOnly); - Mac1 = FusionRoom.CreateOffsetStringSig(57, "Info - Processor - MAC 1", eSigIoMask.InputSigOnly); - Mac2 = FusionRoom.CreateOffsetStringSig(58, "Info - Processor - MAC 2", eSigIoMask.InputSigOnly); - NetMask1 = FusionRoom.CreateOffsetStringSig(59, "Info - Processor - Net Mask 1", eSigIoMask.InputSigOnly); - NetMask2 = FusionRoom.CreateOffsetStringSig(60, "Info - Processor - Net Mask 2", eSigIoMask.InputSigOnly); + _ip1 = FusionRoom.CreateOffsetStringSig(50, "Info - Processor - IP 1", eSigIoMask.InputSigOnly); + _ip2 = FusionRoom.CreateOffsetStringSig(51, "Info - Processor - IP 2", eSigIoMask.InputSigOnly); + _gateway = FusionRoom.CreateOffsetStringSig(52, "Info - Processor - Gateway", eSigIoMask.InputSigOnly); + _hostname = FusionRoom.CreateOffsetStringSig(53, "Info - Processor - Hostname", eSigIoMask.InputSigOnly); + _domain = FusionRoom.CreateOffsetStringSig(54, "Info - Processor - Domain", eSigIoMask.InputSigOnly); + _dns1 = FusionRoom.CreateOffsetStringSig(55, "Info - Processor - DNS 1", eSigIoMask.InputSigOnly); + _dns2 = FusionRoom.CreateOffsetStringSig(56, "Info - Processor - DNS 2", eSigIoMask.InputSigOnly); + _mac1 = FusionRoom.CreateOffsetStringSig(57, "Info - Processor - MAC 1", eSigIoMask.InputSigOnly); + _mac2 = FusionRoom.CreateOffsetStringSig(58, "Info - Processor - MAC 2", eSigIoMask.InputSigOnly); + _netMask1 = FusionRoom.CreateOffsetStringSig(59, "Info - Processor - Net Mask 1", eSigIoMask.InputSigOnly); + _netMask2 = FusionRoom.CreateOffsetStringSig(60, "Info - Processor - Net Mask 2", eSigIoMask.InputSigOnly); } protected void GetProcessorEthernetValues() { - Ip1.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - Gateway.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); - Hostname.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); - Domain.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0); + _ip1.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); + _gateway.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, 0); + _hostname.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); + _domain.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0); - var dnsServers = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, 0).Split(','); - Dns1.InputSig.StringValue = dnsServers[0]; + var dnsServers = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, 0).Split(','); + _dns1.InputSig.StringValue = dnsServers[0]; if (dnsServers.Length > 1) - Dns2.InputSig.StringValue = dnsServers[1]; + { + _dns2.InputSig.StringValue = dnsServers[1]; + } - Mac1.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); - NetMask1.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 0); + _mac1.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); + _netMask1.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 0); // Interface 1 - if (InitialParametersClass.NumberOfEthernetInterfaces > 1) // Only get these values if the processor has more than 1 NIC + if (InitialParametersClass.NumberOfEthernetInterfaces > 1) + // Only get these values if the processor has more than 1 NIC { - Ip2.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 1); - Mac2.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 1); - NetMask2.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 1); + _ip2.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 1); + _mac2.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 1); + _netMask2.InputSig.StringValue = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, 1); } } protected void GetProcessorInfo() { - - Firmware = FusionRoom.CreateOffsetStringSig(61, "Info - Processor - Firmware", eSigIoMask.InputSigOnly); + _firmware = FusionRoom.CreateOffsetStringSig(61, "Info - Processor - Firmware", eSigIoMask.InputSigOnly); if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) { - for (int i = 0; i < Global.ControlSystem.NumProgramsSupported; i++) + for (var i = 0; i < Global.ControlSystem.NumProgramsSupported; i++) { var join = 62 + i; var progNum = i + 1; - Program[i] = FusionRoom.CreateOffsetStringSig((uint)join, string.Format("Info - Processor - Program {0}", progNum), eSigIoMask.InputSigOnly); + _program[i] = FusionRoom.CreateOffsetStringSig((uint) join, + string.Format("Info - Processor - Program {0}", progNum), eSigIoMask.InputSigOnly); } } - Firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion; - + _firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion; } protected void GetCustomProperties() { if (FusionRoom.IsOnline) { - string fusionRoomCustomPropertiesRequest = @"RoomConfigurationRequest"; + const string fusionRoomCustomPropertiesRequest = + @"RoomConfigurationRequest"; - FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigQuery.StringValue = fusionRoomCustomPropertiesRequest; + FusionRoom.ExtenderFusionRoomDataReservedSigs.RoomConfigQuery.StringValue = + fusionRoomCustomPropertiesRequest; } } - void GetTouchpanelInfo() + private void GetTouchpanelInfo() { // TODO: Get IP and Project Name from TP } @@ -460,33 +488,33 @@ namespace PepperDash.Essentials.Core.Fusion // Send Push Notification Action request: - string requestID = "InitialPushRequest"; + const string requestId = "InitialPushRequest"; - string actionRequest = - string.Format("\n{0}\n", requestID) + + var actionRequest = + string.Format("\n{0}\n", requestId) + "RegisterPushModel\n" + "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + "\n" + - "\n"; + "\n"; Debug.Console(2, this, "Sending Fusion ActionRequest: \n{0}", actionRequest); @@ -498,17 +526,16 @@ namespace PepperDash.Essentials.Core.Fusion RequestLocalDateTime(null); // Setup timer to request time daily - if (DailyTimeRequestTimer != null && !DailyTimeRequestTimer.Disposed) + if (_dailyTimeRequestTimer != null && !_dailyTimeRequestTimer.Disposed) { - DailyTimeRequestTimer.Stop(); - DailyTimeRequestTimer.Dispose(); + _dailyTimeRequestTimer.Stop(); + _dailyTimeRequestTimer.Dispose(); } - DailyTimeRequestTimer = new CTimer(RequestLocalDateTime, null, 86400000, 86400000); + _dailyTimeRequestTimer = new CTimer(RequestLocalDateTime, null, 86400000, 86400000); - DailyTimeRequestTimer.Reset(86400000, 86400000); + _dailyTimeRequestTimer.Reset(86400000, 86400000); } - } /// @@ -517,9 +544,10 @@ namespace PepperDash.Essentials.Core.Fusion /// public void RequestLocalDateTime(object callbackObject) { - string timeRequestID = "TimeRequest"; + const string timeRequestId = "TimeRequest"; - string timeRequest = string.Format("{0}", timeRequestID); + var timeRequest = string.Format("{0}", + timeRequestId); FusionRoom.ExtenderFusionRoomDataReservedSigs.LocalDateTimeQuery.StringValue = timeRequest; } @@ -527,79 +555,78 @@ namespace PepperDash.Essentials.Core.Fusion /// /// Generates a room schedule request for this room for the next 24 hours. /// - /// string identifying this request. Used with a corresponding ScheduleResponse value public void RequestFullRoomSchedule(object callbackObject) { - DateTime now = DateTime.Today; + var now = DateTime.Today; - string currentTime = now.ToString("s"); + var currentTime = now.ToString("s"); - string requestTest = - string.Format("FullSchedleRequest{0}{1}24", RoomGuid, currentTime); + var requestTest = + string.Format( + "FullSchedleRequest{0}{1}24", + RoomGuid, currentTime); Debug.Console(2, this, "Sending Fusion ScheduleQuery: \n{0}", requestTest); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleQuery.StringValue = requestTest; - if (IsRegisteredForSchedulePushNotifications) - PushNotificationTimer.Stop(); + if (_isRegisteredForSchedulePushNotifications) + { + _pushNotificationTimer.Stop(); + } } - + /// /// Wrapper method to allow console commands to modify the current meeting end time /// /// meetingID extendTime public void ModifyMeetingEndTimeConsoleHelper(string command) { - string requestID; - string meetingID = null; - int extendMinutes = -1; + var extendMinutes = -1; - requestID = "ModifyMeetingTest12345"; + const string requestId = "ModifyMeetingTest12345"; try { var tokens = command.Split(' '); - meetingID = tokens[0]; extendMinutes = Int32.Parse(tokens[1]); - } catch (Exception e) { Debug.Console(1, this, "Error parsing console command: {0}", e); } - ModifyMeetingEndTime(requestID, extendMinutes); - + ModifyMeetingEndTime(requestId, extendMinutes); } /// /// Ends or Extends the current meeting by the specified number of minutes. /// + /// /// Number of minutes to extend the meeting. A value of 0 will end the meeting. - public void ModifyMeetingEndTime(string requestID, int extendMinutes) + public void ModifyMeetingEndTime(string requestId, int extendMinutes) { - if(CurrentMeeting == null) + if (_currentMeeting == null) { Debug.Console(1, this, "No meeting in progress. Unable to modify end time."); return; - } + } if (extendMinutes > -1) { - if(extendMinutes > 0) + if (extendMinutes > 0) { - var extendTime = CurrentMeeting.dtEnd - DateTime.Now; - double extendMinutesRaw = extendTime.TotalMinutes; + var extendTime = _currentMeeting.dtEnd - DateTime.Now; + var extendMinutesRaw = extendTime.TotalMinutes; - extendMinutes = extendMinutes + (int)Math.Round(extendMinutesRaw); + extendMinutes = extendMinutes + (int) Math.Round(extendMinutesRaw); } - string requestTest = string.Format( + var requestTest = string.Format( "{0}{1}MeetingChange" - , requestID, RoomGuid, CurrentMeeting.MeetingID, extendMinutes); + , requestId, RoomGuid, _currentMeeting.MeetingID, extendMinutes); Debug.Console(1, this, "Sending MeetingChange Request: \n{0}", requestTest); @@ -609,8 +636,6 @@ namespace PepperDash.Essentials.Core.Fusion { Debug.Console(1, this, "Invalid time specified"); } - - } /// @@ -618,38 +643,38 @@ namespace PepperDash.Essentials.Core.Fusion /// public void CreateAsHocMeeting(string command) { - string requestID = "CreateAdHocMeeting"; + const string requestId = "CreateAdHocMeeting"; - DateTime now = DateTime.Now.AddMinutes(1); + var now = DateTime.Now.AddMinutes(1); now.AddSeconds(-now.Second); // Assume 1 hour meeting if possible - DateTime dtEnd = now.AddHours(1); + var dtEnd = now.AddHours(1); // Check if room is available for 1 hour before next meeting - if (NextMeeting != null) + if (_nextMeeting != null) { - var roomAvailable = NextMeeting.dtEnd.Subtract(dtEnd); + var roomAvailable = _nextMeeting.dtEnd.Subtract(dtEnd); if (roomAvailable.TotalMinutes < 60) { - /// Room not available for full hour, book until next meeting starts - dtEnd = NextMeeting.dtEnd; + // Room not available for full hour, book until next meeting starts + dtEnd = _nextMeeting.dtEnd; } } - string createMeetingRequest = + var createMeetingRequest = "" + - string.Format("{0}", requestID) + - string.Format("{0}", RoomGuid) + - "" + - string.Format("{0}", now.ToString("s")) + - string.Format("{0}", dtEnd.ToString("s")) + - "AdHoc Meeting" + - "Room User" + - "Example Message" + - "" + + string.Format("{0}", requestId) + + string.Format("{0}", RoomGuid) + + "" + + string.Format("{0}", now.ToString("s")) + + string.Format("{0}", dtEnd.ToString("s")) + + "AdHoc Meeting" + + "Room User" + + "Example Message" + + "" + ""; Debug.Console(2, this, "Sending CreateMeeting Request: \n{0}", createMeetingRequest); @@ -659,7 +684,6 @@ namespace PepperDash.Essentials.Core.Fusion //Debug.Console(1, this, "Sending CreateMeeting Request: \n{0}", command); //FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = command; - } /// @@ -667,73 +691,73 @@ namespace PepperDash.Essentials.Core.Fusion /// /// /// - protected void ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) + protected void ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, + SigEventArgs args) { - Debug.Console(2, this, "Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue); + Debug.Console(2, this, "Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, + args.Sig.StringValue); if (args.Sig == FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQueryResponse) { try { - XmlDocument message = new XmlDocument(); + var message = new XmlDocument(); message.LoadXml(args.Sig.StringValue); var actionResponse = message["ActionResponse"]; - if (actionResponse != null) + if (actionResponse == null) { - var requestID = actionResponse["RequestID"]; + return; + } - if (requestID.InnerText == "InitialPushRequest") + var requestId = actionResponse["RequestID"]; + + if (requestId.InnerText != "InitialPushRequest") + { + return; + } + + if (actionResponse["ActionID"].InnerText != "RegisterPushModel") + { + return; + } + + var parameters = actionResponse["Parameters"]; + + foreach (var isRegistered in from XmlElement parameter in parameters + where parameter.HasAttributes + select parameter.Attributes + into attributes + where attributes["ID"].Value == "Registered" + select Int32.Parse(attributes["Value"].Value)) + { + switch (isRegistered) { - if (actionResponse["ActionID"].InnerText == "RegisterPushModel") - { - var parameters = actionResponse["Parameters"]; - - foreach (XmlElement parameter in parameters) + case 1: + _isRegisteredForSchedulePushNotifications = true; + if (_pollTimer != null && !_pollTimer.Disposed) { - if (parameter.HasAttributes) - { - var attributes = parameter.Attributes; - - if (attributes["ID"].Value == "Registered") - { - var isRegistered = Int32.Parse(attributes["Value"].Value); - - if (isRegistered == 1) - { - IsRegisteredForSchedulePushNotifications = true; - - if (PollTimer != null && !PollTimer.Disposed) - { - PollTimer.Stop(); - PollTimer.Dispose(); - } - - PushNotificationTimer = new CTimer(RequestFullRoomSchedule, null, PushNotificationTimeout, PushNotificationTimeout); - - PushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); - } - else if (isRegistered == 0) - { - IsRegisteredForSchedulePushNotifications = false; - - if (PushNotificationTimer != null && !PushNotificationTimer.Disposed) - { - PushNotificationTimer.Stop(); - PushNotificationTimer.Dispose(); - } - - PollTimer = new CTimer(RequestFullRoomSchedule, null, SchedulePollInterval, SchedulePollInterval); - - PollTimer.Reset(SchedulePollInterval, SchedulePollInterval); - } - } - } + _pollTimer.Stop(); + _pollTimer.Dispose(); } - } + _pushNotificationTimer = new CTimer(RequestFullRoomSchedule, null, + PushNotificationTimeout, PushNotificationTimeout); + _pushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); + break; + case 0: + _isRegisteredForSchedulePushNotifications = false; + if (_pushNotificationTimer != null && !_pushNotificationTimer.Disposed) + { + _pushNotificationTimer.Stop(); + _pushNotificationTimer.Dispose(); + } + _pollTimer = new CTimer(RequestFullRoomSchedule, null, SchedulePollInterval, + SchedulePollInterval); + _pollTimer.Reset(SchedulePollInterval, SchedulePollInterval); + break; } } } @@ -746,7 +770,7 @@ namespace PepperDash.Essentials.Core.Fusion { try { - XmlDocument message = new XmlDocument(); + var message = new XmlDocument(); message.LoadXml(args.Sig.StringValue); @@ -759,13 +783,15 @@ namespace PepperDash.Essentials.Core.Fusion if (localDateTime != null) { var tempLocalDateTime = localDateTime.InnerText; - - DateTime currentTime = DateTime.Parse(tempLocalDateTime); + + var currentTime = DateTime.Parse(tempLocalDateTime); Debug.Console(1, this, "DateTime from Fusion Server: {0}", currentTime); // Parse time and date from response and insert values - CrestronEnvironment.SetTimeAndDate((ushort)currentTime.Hour, (ushort)currentTime.Minute, (ushort)currentTime.Second, (ushort)currentTime.Month, (ushort)currentTime.Day, (ushort)currentTime.Year); + CrestronEnvironment.SetTimeAndDate((ushort) currentTime.Hour, (ushort) currentTime.Minute, + (ushort) currentTime.Second, (ushort) currentTime.Month, (ushort) currentTime.Day, + (ushort) currentTime.Year); Debug.Console(1, this, "Processor time set to {0}", CrestronEnvironment.GetLocalTime()); } @@ -780,13 +806,13 @@ namespace PepperDash.Essentials.Core.Fusion { // Room info response with custom properties - string roomConfigResponseArgs = args.Sig.StringValue.Replace("&", "and"); + var roomConfigResponseArgs = args.Sig.StringValue.Replace("&", "and"); Debug.Console(2, this, "Fusion Response: \n {0}", roomConfigResponseArgs); try { - XmlDocument roomConfigResponse = new XmlDocument(); + var roomConfigResponse = new XmlDocument(); roomConfigResponse.LoadXml(roomConfigResponseArgs); @@ -794,13 +820,13 @@ namespace PepperDash.Essentials.Core.Fusion if (requestRoomConfiguration != null) { - RoomInformation roomInformation = new RoomInformation(); + var roomInformation = new RoomInformation(); foreach (XmlElement e in roomConfigResponse.FirstChild.ChildNodes) { if (e.Name == "RoomInformation") { - XmlReader roomInfo = new XmlReader(e.OuterXml); + var roomInfo = new XmlReader(e.OuterXml); roomInformation = CrestronXMLSerialization.DeSerializeObject(roomInfo); } @@ -808,7 +834,7 @@ namespace PepperDash.Essentials.Core.Fusion { foreach (XmlElement el in e) { - FusionCustomProperty customProperty = new FusionCustomProperty(); + var customProperty = new FusionCustomProperty(); if (el.Name == "CustomField") { @@ -838,7 +864,9 @@ namespace PepperDash.Essentials.Core.Fusion var handler = RoomInfoChange; if (handler != null) + { handler(this, new EventArgs()); + } CustomPropertiesBridge.EvaluateRoomInfo(Room.Key, roomInformation); } @@ -851,7 +879,6 @@ namespace PepperDash.Essentials.Core.Fusion //getRoomInfoBusy = false; //_DynFusion.API.EISC.BooleanInput[Constants.GetRoomInfo].BoolValue = getRoomInfoBusy; } - } /// @@ -859,130 +886,127 @@ namespace PepperDash.Essentials.Core.Fusion /// /// /// - protected void FusionRoomSchedule_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) + protected void FusionRoomSchedule_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, + SigEventArgs args) { - Debug.Console(2, this, "Scehdule Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue); + Debug.Console(2, this, "Scehdule Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, + args.Sig.Name, args.Sig.StringValue); - if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleResponse) - { - try - { - ScheduleResponse scheduleResponse = new ScheduleResponse(); + if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleResponse) + { + try + { + var scheduleResponse = new ScheduleResponse(); - XmlDocument message = new XmlDocument(); + var message = new XmlDocument(); - message.LoadXml(args.Sig.StringValue); + message.LoadXml(args.Sig.StringValue); - var response = message["ScheduleResponse"]; + var response = message["ScheduleResponse"]; - if (response != null) - { - // Check for push notification - if (response["RequestID"].InnerText == "RVRequest") - { - var action = response["Action"]; + if (response != null) + { + // Check for push notification + if (response["RequestID"].InnerText == "RVRequest") + { + var action = response["Action"]; - if (action.OuterXml.IndexOf("RequestSchedule") > -1) - { - PushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); - } - } - else // Not a push notification - { - CurrentSchedule = new RoomSchedule(); // Clear Current Schedule - CurrentMeeting = null; // Clear Current Meeting - NextMeeting = null; // Clear Next Meeting + if (action.OuterXml.IndexOf("RequestSchedule", StringComparison.Ordinal) > -1) + { + _pushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout); + } + } + else // Not a push notification + { + _currentSchedule = new RoomSchedule(); // Clear Current Schedule + _currentMeeting = null; // Clear Current Meeting + _nextMeeting = null; // Clear Next Meeting - bool isNextMeeting = false; + var isNextMeeting = false; - foreach (XmlElement element in message.FirstChild.ChildNodes) - { - if (element.Name == "RequestID") - { - scheduleResponse.RequestID = element.InnerText; - } - else if (element.Name == "RoomID") - { - scheduleResponse.RoomID = element.InnerText; - } - else if (element.Name == "RoomName") - { - scheduleResponse.RoomName = element.InnerText; - } - else if (element.Name == "Event") - { - Debug.Console(2, this, "Event Found:\n{0}", element.OuterXml); + foreach (XmlElement element in message.FirstChild.ChildNodes) + { + if (element.Name == "RequestID") + { + scheduleResponse.RequestID = element.InnerText; + } + else if (element.Name == "RoomID") + { + scheduleResponse.RoomID = element.InnerText; + } + else if (element.Name == "RoomName") + { + scheduleResponse.RoomName = element.InnerText; + } + else if (element.Name == "Event") + { + Debug.Console(2, this, "Event Found:\n{0}", element.OuterXml); - XmlReader reader = new XmlReader(element.OuterXml); + var reader = new XmlReader(element.OuterXml); - Event tempEvent = new Event(); + var tempEvent = CrestronXMLSerialization.DeSerializeObject(reader); - tempEvent = CrestronXMLSerialization.DeSerializeObject(reader); + scheduleResponse.Events.Add(tempEvent); - scheduleResponse.Events.Add(tempEvent); + // Check is this is the current event + if (tempEvent.dtStart <= DateTime.Now && tempEvent.dtEnd >= DateTime.Now) + { + _currentMeeting = tempEvent; // Set Current Meeting + isNextMeeting = true; // Flag that next element is next meeting + } - // Check is this is the current event - if (tempEvent.dtStart <= DateTime.Now && tempEvent.dtEnd >= DateTime.Now) - { - CurrentMeeting = tempEvent; // Set Current Meeting - isNextMeeting = true; // Flag that next element is next meeting - } + if (isNextMeeting) + { + _nextMeeting = tempEvent; // Set Next Meeting + isNextMeeting = false; + } - if (isNextMeeting) - { - NextMeeting = tempEvent; // Set Next Meeting - isNextMeeting = false; - } + _currentSchedule.Meetings.Add(tempEvent); + } + } - CurrentSchedule.Meetings.Add(tempEvent); - } + PrintTodaysSchedule(); - } + if (!_isRegisteredForSchedulePushNotifications) + { + _pollTimer.Reset(SchedulePollInterval, SchedulePollInterval); + } - PrintTodaysSchedule(); - - if (!IsRegisteredForSchedulePushNotifications) - PollTimer.Reset(SchedulePollInterval, SchedulePollInterval); - - // Fire Schedule Change Event - var handler = ScheduleChange; - - if (handler != null) - { - handler(this, new ScheduleChangeEventArgs() { Schedule = CurrentSchedule }); - } - - } - } - - - - } - catch (Exception e) - { - Debug.Console(1, this, "Error parsing ScheduleResponse: {0}", e); - } - } - else if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateResponse) - { - Debug.Console(2, this, "Create Meeting Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue); - } + // Fire Schedule Change Event + var handler = ScheduleChange; + if (handler != null) + { + handler(this, new ScheduleChangeEventArgs {Schedule = _currentSchedule}); + } + } + } + } + catch (Exception e) + { + Debug.Console(1, this, "Error parsing ScheduleResponse: {0}", e); + } + } + else if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateResponse) + { + Debug.Console(2, this, "Create Meeting Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, + args.Sig.Name, args.Sig.StringValue); + } } /// /// Prints today's schedule to console for debugging /// - void PrintTodaysSchedule() + private void PrintTodaysSchedule() { if (Debug.Level > 1) { - if (CurrentSchedule.Meetings.Count > 0) + if (_currentSchedule.Meetings.Count > 0) { Debug.Console(1, this, "Today's Schedule for '{0}'\n", Room.Name); - foreach (Event e in CurrentSchedule.Meetings) + foreach (var e in _currentSchedule.Meetings) { Debug.Console(1, this, "Subject: {0}", e.Subject); Debug.Console(1, this, "Organizer: {0}", e.Organizer); @@ -995,63 +1019,62 @@ namespace PepperDash.Essentials.Core.Fusion } } - protected virtual void SetUpSources() - { - // Sources - var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsRoomBase).SourceListKey); - if (dict != null) - { - // NEW PROCESS: - // Make these lists and insert the fusion attributes by iterating these - var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls); - uint i = 1; - foreach (var kvp in setTopBoxes) - { - TryAddRouteActionSigs("Display 1 - Source TV " + i, 188 + i, kvp.Key, kvp.Value.SourceDevice); - i++; - if (i > 5) // We only have five spots - break; - } - - var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls); - i = 1; - foreach (var kvp in discPlayers) - { - TryAddRouteActionSigs("Display 1 - Source DVD " + i, 181 + i, kvp.Key, kvp.Value.SourceDevice); - i++; - if (i > 5) // We only have five spots - break; - } - - var laptops = dict.Where(d => d.Value.SourceDevice is Devices.Laptop); - i = 1; - foreach (var kvp in laptops) - { - TryAddRouteActionSigs("Display 1 - Source Laptop " + i, 166 + i, kvp.Key, kvp.Value.SourceDevice); - i++; - if (i > 10) // We only have ten spots??? - break; - } - - foreach (var kvp in dict) + protected virtual void SetUpSources() + { + // Sources + var dict = ConfigReader.ConfigObject.GetSourceListForKey(Room.SourceListKey); + if (dict != null) + { + // NEW PROCESS: + // Make these lists and insert the fusion attributes by iterating these + var setTopBoxes = dict.Where(d => d.Value.SourceDevice is ISetTopBoxControls); + uint i = 1; + foreach (var kvp in setTopBoxes) { - var usageDevice = kvp.Value.SourceDevice as IUsageTracking; - - if (usageDevice != null) + TryAddRouteActionSigs("Display 1 - Source TV " + i, 188 + i, kvp.Key, kvp.Value.SourceDevice); + i++; + if (i > 5) // We only have five spots { - usageDevice.UsageTracker = new UsageTracking(usageDevice as Device); - usageDevice.UsageTracker.UsageIsTracked = true; - usageDevice.UsageTracker.DeviceUsageEnded += new EventHandler(UsageTracker_DeviceUsageEnded); + break; } } - - } - else - { - Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'", - (Room as EssentialsRoomBase).SourceListKey, Room.Key); - } - } + + var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls); + i = 1; + foreach (var kvp in discPlayers) + { + TryAddRouteActionSigs("Display 1 - Source DVD " + i, 181 + i, kvp.Key, kvp.Value.SourceDevice); + i++; + if (i > 5) // We only have five spots + { + break; + } + } + + var laptops = dict.Where(d => d.Value.SourceDevice is Devices.Laptop); + i = 1; + foreach (var kvp in laptops) + { + TryAddRouteActionSigs("Display 1 - Source Laptop " + i, 166 + i, kvp.Key, kvp.Value.SourceDevice); + i++; + if (i > 10) // We only have ten spots??? + { + break; + } + } + + foreach (var usageDevice in dict.Select(kvp => kvp.Value.SourceDevice).OfType()) + { + usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) {UsageIsTracked = true}; + usageDevice.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; + } + } + else + { + Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'", + Room.SourceListKey, Room.Key); + } + } /// /// Collects usage data from source and sends to Fusion @@ -1059,24 +1082,31 @@ namespace PepperDash.Essentials.Core.Fusion /// /// protected void UsageTracker_DeviceUsageEnded(object sender, DeviceUsageEventArgs e) - { + { var deviceTracker = sender as UsageTracking; - var configDevice = ConfigReader.ConfigObject.Devices.Where(d => d.Key.Equals(deviceTracker.Parent)); + if (deviceTracker == null) + { + return; + } - string group = ConfigReader.GetGroupForDeviceKey(deviceTracker.Parent.Key); + var group = ConfigReader.GetGroupForDeviceKey(deviceTracker.Parent.Key); - string currentMeetingId = "-"; + var currentMeetingId = "-"; - if (CurrentMeeting != null) - currentMeetingId = CurrentMeeting.MeetingID; + if (_currentMeeting != null) + { + currentMeetingId = _currentMeeting.MeetingID; + } //String Format: "USAGE||[Date YYYY-MM-DD]||[Time HH-mm-ss]||TIME||[Asset_Type]||[Asset_Name]||[Minutes_used]||[Asset_ID]||[Meeting_ID]" // [Asset_ID] property does not appear to be used in Crestron SSI examples. They are sending "-" instead so that's what is replicated here - string deviceUsage = string.Format("USAGE||{0}||{1}||TIME||{2}||{3}||-||{4}||-||{5}||{6}||\r\n", e.UsageEndTime.ToString("yyyy-MM-dd"), e.UsageEndTime.ToString("HH:mm:ss"), - group, deviceTracker.Parent.Name, e.MinutesUsed, "-", currentMeetingId); + var deviceUsage = string.Format("USAGE||{0}||{1}||TIME||{2}||{3}||-||{4}||-||{5}||{6}||\r\n", + e.UsageEndTime.ToString("yyyy-MM-dd"), e.UsageEndTime.ToString("HH:mm:ss"), + @group, deviceTracker.Parent.Name, e.MinutesUsed, "-", currentMeetingId); - Debug.Console(1, this, "Device usage for: {0} ended at {1}. In use for {2} minutes", deviceTracker.Parent.Name, e.UsageEndTime, e.MinutesUsed); + Debug.Console(1, this, "Device usage for: {0} ended at {1}. In use for {2} minutes", + deviceTracker.Parent.Name, e.UsageEndTime, e.MinutesUsed); FusionRoom.DeviceUsage.InputSig.StringValue = deviceUsage; @@ -1084,41 +1114,51 @@ namespace PepperDash.Essentials.Core.Fusion } - protected void TryAddRouteActionSigs(string attrName, uint attrNum, string routeKey, Device pSrc) - { - Debug.Console(2, this, "Creating attribute '{0}' with join {1} for source {2}", - attrName, attrNum, pSrc.Key); - try - { - var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputOutputSig); - // Need feedback when this source is selected - // Event handler, added below, will compare source changes with this sig dict - SourceToFeedbackSigs.Add(pSrc, sigD.InputSig); + protected void TryAddRouteActionSigs(string attrName, uint attrNum, string routeKey, Device pSrc) + { + Debug.Console(2, this, "Creating attribute '{0}' with join {1} for source {2}", + attrName, attrNum, pSrc.Key); + try + { + var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputOutputSig); + // Need feedback when this source is selected + // Event handler, added below, will compare source changes with this sig dict + _sourceToFeedbackSigs.Add(pSrc, sigD.InputSig); - // And respond to selection in Fusion - sigD.OutputSig.SetSigFalseAction(() => (Room as IRunRouteAction).RunRouteAction(routeKey, Room.SourceListKey)); - } - catch (Exception) - { - Debug.Console(2, this, "Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING", attrNum, attrName, pSrc.Key); - } - } + // And respond to selection in Fusion + sigD.OutputSig.SetSigFalseAction(() => + { + var runRouteAction = Room as IRunRouteAction; + if (runRouteAction != null) + { + runRouteAction.RunRouteAction(routeKey, Room.SourceListKey); + } + }); + } + catch (Exception) + { + Debug.Console(2, this, "Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING", + attrNum, attrName, pSrc.Key); + } + } - /// - /// - /// - void SetUpCommunitcationMonitors() - { + /// + /// + /// + private void SetUpCommunitcationMonitors() + { uint displayNum = 0; uint touchpanelNum = 0; uint xpanelNum = 0; - // Attach to all room's devices with monitors. - //foreach (var dev in DeviceManager.Devices) - foreach (var dev in DeviceManager.GetDevices()) - { - if (!(dev is ICommunicationMonitor)) - continue; + // Attach to all room's devices with monitors. + //foreach (var dev in DeviceManager.Devices) + foreach (var dev in DeviceManager.GetDevices()) + { + if (!(dev is ICommunicationMonitor)) + { + continue; + } string attrName = null; uint attrNum = 1; @@ -1141,7 +1181,9 @@ namespace PepperDash.Essentials.Core.Fusion attrNum = attrNum + touchpanelNum; if (attrNum > 10) + { continue; + } attrName = "Online - XPanel " + attrNum; attrNum += 160; @@ -1152,7 +1194,9 @@ namespace PepperDash.Essentials.Core.Fusion attrNum = attrNum + xpanelNum; if (attrNum > 10) + { continue; + } attrName = "Online - Touch Panel " + attrNum; attrNum += 150; @@ -1160,45 +1204,47 @@ namespace PepperDash.Essentials.Core.Fusion } } - //else - if (dev is DisplayBase) - { - attrNum = attrNum + displayNum; - if (attrNum > 10) - continue; - attrName = "Online - Display " + attrNum; - attrNum += 170; + //else + if (dev is DisplayBase) + { + attrNum = attrNum + displayNum; + if (attrNum > 10) + { + continue; + } + attrName = "Online - Display " + attrNum; + attrNum += 170; displayNum++; - } - //else if (dev is DvdDeviceBase) - //{ - // if (attrNum > 5) - // continue; - // attrName = "Device Ok - DVD " + attrNum; - // attrNum += 260; - //} - // add set top box + } + //else if (dev is DvdDeviceBase) + //{ + // if (attrNum > 5) + // continue; + // attrName = "Device Ok - DVD " + attrNum; + // attrNum += 260; + //} + // add set top box - // add Cresnet roll-up + // add Cresnet roll-up - // add DM-devices roll-up + // add DM-devices roll-up - if (attrName != null) - { - // Link comm status to sig and update - var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly); - var smd = dev as ICommunicationMonitor; - sigD.InputSig.BoolValue = smd.CommunicationMonitor.Status == MonitorStatus.IsOk; - smd.CommunicationMonitor.StatusChange += (o, a) => - { sigD.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; }; - Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", dev.Key, attrName); - } - } - } + if (attrName != null) + { + // Link comm status to sig and update + var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly); + var smd = dev as ICommunicationMonitor; + sigD.InputSig.BoolValue = smd.CommunicationMonitor.Status == MonitorStatus.IsOk; + smd.CommunicationMonitor.StatusChange += + (o, a) => { sigD.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; }; + Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", dev.Key, attrName); + } + } + } - protected virtual void SetUpDisplay() - { + protected virtual void SetUpDisplay() + { try { //Setup Display Usage Monitoring @@ -1207,35 +1253,52 @@ namespace PepperDash.Essentials.Core.Fusion // Consider updating this in multiple display systems - foreach (DisplayBase display in displays) + foreach (var display in displays.Cast()) { - display.UsageTracker = new UsageTracking(display); - display.UsageTracker.UsageIsTracked = true; - display.UsageTracker.DeviceUsageEnded += new EventHandler(UsageTracker_DeviceUsageEnded); + display.UsageTracker = new UsageTracking(display) {UsageIsTracked = true}; + display.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; } - var defaultDisplay = (Room as IHasDefaultDisplay).DefaultDisplay as DisplayBase; + var hasDefaultDisplay = Room as IHasDefaultDisplay; + if (hasDefaultDisplay == null) + { + return; + } + var defaultDisplay = hasDefaultDisplay.DefaultDisplay as DisplayBase; if (defaultDisplay == null) { Debug.Console(1, this, "Cannot link null display to Fusion because default display is null"); return; } - var dispPowerOnAction = new Action(b => { if (!b) defaultDisplay.PowerOn(); }); - var dispPowerOffAction = new Action(b => { if (!b) defaultDisplay.PowerOff(); }); + var dispPowerOnAction = new Action(b => + { + if (!b) + { + defaultDisplay.PowerOn(); + } + }); + var dispPowerOffAction = new Action(b => + { + if (!b) + { + defaultDisplay.PowerOff(); + } + }); // Display to fusion room sigs FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction; - FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction; + FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction; MapDisplayToRoomJoins(1, 158, defaultDisplay); - var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); + var deviceConfig = + ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); //Check for existing asset in GUIDs collection - var tempAsset = new FusionAsset(); + FusionAsset tempAsset; if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) { @@ -1244,11 +1307,13 @@ namespace PepperDash.Essentials.Core.Fusion else { // Create a new asset - tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), defaultDisplay.Name, "Display", ""); + tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), + defaultDisplay.Name, "Display", ""); FusionStaticAssets.Add(deviceConfig.Uid, tempAsset); } - var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId); + var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", + tempAsset.InstanceId); dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; @@ -1257,13 +1322,14 @@ namespace PepperDash.Essentials.Core.Fusion { defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig); if (defaultDisplay is IDisplayUsage) + { (defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig); + } defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig); - } - // Use extension methods + // Use extension methods dispAsset.TrySetMakeModel(defaultDisplay); dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay); } @@ -1271,323 +1337,397 @@ namespace PepperDash.Essentials.Core.Fusion { Debug.Console(1, this, "Error setting up display in Fusion: {0}", e); } - - } + } /// /// Maps room attributes to a display at a specified index /// - /// - /// a + /// + /// + /// + /// a protected virtual void MapDisplayToRoomJoins(int displayIndex, int joinOffset, DisplayBase display) { - string displayName = string.Format("Display {0} - ", displayIndex); + var displayName = string.Format("Display {0} - ", displayIndex); - if (display == (Room as IHasDefaultDisplay).DefaultDisplay) + var hasDefaultDisplay = Room as IHasDefaultDisplay; + if (hasDefaultDisplay == null || display != hasDefaultDisplay.DefaultDisplay) { - // Display volume - var defaultDisplayVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig); - defaultDisplayVolume.OutputSig.UserObject = new Action(b => (display as IBasicVolumeWithFeedback).SetVolume(b)); - (display as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(defaultDisplayVolume.InputSig); - - // Power on - var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig); - defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => { if (!b) display.PowerOn(); }); - - // Power Off - var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 1, displayName + "Power Off", eSigIoMask.InputOutputSig); - defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => { if (!b) display.PowerOff(); }); ; - - - var defaultTwoWayDisplay = display as IHasPowerControlWithFeedback; - if (defaultTwoWayDisplay != null) + return; + } + // Display volume + var defaultDisplayVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", + eSigIoMask.InputOutputSig); + defaultDisplayVolume.OutputSig.UserObject = new Action(b => + { + var basicVolumeWithFeedback = display as IBasicVolumeWithFeedback; + if (basicVolumeWithFeedback == null) { - defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); - defaultTwoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(defaultDisplayPowerOff.InputSig); + return; } - // Current Source - var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig); - defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as IRunRouteAction).RunRouteAction("roomOff", Room.SourceListKey); }); ; + basicVolumeWithFeedback.SetVolume(b); + basicVolumeWithFeedback.VolumeLevelFeedback.LinkInputSig(defaultDisplayVolume.InputSig); + }); + + + // Power on + var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint) joinOffset, displayName + "Power On", + eSigIoMask.InputOutputSig); + defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => + { + if (!b) + { + display.PowerOn(); + } + }); + + // Power Off + var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 1, displayName + "Power Off", + eSigIoMask.InputOutputSig); + defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => + { + if (!b) + { + display.PowerOff(); + } + }); + + + var defaultTwoWayDisplay = display as IHasPowerControlWithFeedback; + if (defaultTwoWayDisplay != null) + { + defaultTwoWayDisplay.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); + defaultTwoWayDisplay.PowerIsOnFeedback.LinkComplementInputSig(defaultDisplayPowerOff.InputSig); } + + // Current Source + var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 8, + displayName + "Source None", eSigIoMask.InputOutputSig); + defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => + { + if (!b) + { + var runRouteAction = Room as IRunRouteAction; + if (runRouteAction != null) + { + runRouteAction.RunRouteAction("roomOff", Room.SourceListKey); + } + } + }); } - void SetUpError() - { - // Roll up ALL device errors - ErrorMessageRollUp = new StatusMonitorCollection(this); - foreach (var dev in DeviceManager.GetDevices()) - { - var md = dev as ICommunicationMonitor; - if (md != null) - { - ErrorMessageRollUp.AddMonitor(md.CommunicationMonitor); - Debug.Console(2, this, "Adding '{0}' to room's overall error monitor", md.CommunicationMonitor.Parent.Key); - } - } - ErrorMessageRollUp.Start(); - FusionRoom.ErrorMessage.InputSig.StringValue = ErrorMessageRollUp.Message; - ErrorMessageRollUp.StatusChange += (o, a) => - { - FusionRoom.ErrorMessage.InputSig.StringValue = ErrorMessageRollUp.Message; - }; - - } + private void SetUpError() + { + // Roll up ALL device errors + _errorMessageRollUp = new StatusMonitorCollection(this); + foreach (var dev in DeviceManager.GetDevices()) + { + var md = dev as ICommunicationMonitor; + if (md != null) + { + _errorMessageRollUp.AddMonitor(md.CommunicationMonitor); + Debug.Console(2, this, "Adding '{0}' to room's overall error monitor", + md.CommunicationMonitor.Parent.Key); + } + } + _errorMessageRollUp.Start(); + FusionRoom.ErrorMessage.InputSig.StringValue = _errorMessageRollUp.Message; + _errorMessageRollUp.StatusChange += + (o, a) => { FusionRoom.ErrorMessage.InputSig.StringValue = _errorMessageRollUp.Message; }; + } /// /// Sets up a local occupancy sensor, such as one attached to a Fusion Scheduling panel. The occupancy status of the room will be read from Fusion /// - void SetUpLocalOccupancy() + private void SetUpLocalOccupancy() { RoomIsOccupiedFeedback = new BoolFeedback(RoomIsOccupiedFeedbackFunc); - FusionRoom.FusionAssetStateChange += new FusionAssetStateEventHandler(FusionRoom_FusionAssetStateChange); + FusionRoom.FusionAssetStateChange += FusionRoom_FusionAssetStateChange; // Build Occupancy Asset? // Link sigs? //Room.SetRoomOccupancy(this as IOccupancyStatusProvider, 0); - - } - void FusionRoom_FusionAssetStateChange(FusionBase device, FusionAssetStateEventArgs args) + private void FusionRoom_FusionAssetStateChange(FusionBase device, FusionAssetStateEventArgs args) { - if (args.EventId == FusionAssetEventId.RoomOccupiedReceivedEventId || args.EventId == FusionAssetEventId.RoomUnoccupiedReceivedEventId) + if (args.EventId == FusionAssetEventId.RoomOccupiedReceivedEventId || + args.EventId == FusionAssetEventId.RoomUnoccupiedReceivedEventId) + { RoomIsOccupiedFeedback.FireUpdate(); - + } } /// /// Sets up remote occupancy that will relay the occupancy status determined by local system devices to Fusion /// - void SetUpRemoteOccupancy() - { - + private void SetUpRemoteOccupancy() + { // Need to have the room occupancy object first and somehow determine the slot number of the Occupancy asset but will not be able to use the UID from config likely. // Consider defining an object just for Room Occupancy (either eAssetType.Occupancy Sensor (local) or eAssetType.RemoteOccupancySensor (from Fusion sched. panel)) and reserving slot 4 for that asset (statics would start at 5) //if (Room.OccupancyObj != null) //{ - var tempOccAsset = GUIDs.OccupancyAsset; - - if(tempOccAsset == null) - { - FusionOccSensor = new FusionOccupancySensorAsset(eAssetType.OccupancySensor); - tempOccAsset = FusionOccSensor; - } + var tempOccAsset = _guiDs.OccupancyAsset; - var occSensorAsset = FusionRoom.CreateOccupancySensorAsset(tempOccAsset.SlotNumber, tempOccAsset.Name, "Occupancy Sensor", tempOccAsset.InstanceId); + if (tempOccAsset == null) + { + FusionOccSensor = new FusionOccupancySensorAsset(eAssetType.OccupancySensor); + tempOccAsset = FusionOccSensor; + } - occSensorAsset.RoomOccupied.AddSigToRVIFile = true; + var occSensorAsset = FusionRoom.CreateOccupancySensorAsset(tempOccAsset.SlotNumber, tempOccAsset.Name, + "Occupancy Sensor", tempOccAsset.InstanceId); - var occSensorShutdownMinutes = FusionRoom.CreateOffsetUshortSig(70, "Occ Shutdown - Minutes", eSigIoMask.InputOutputSig); - - // Tie to method on occupancy object - //occSensorShutdownMinutes.OutputSig.UserObject(new Action(ushort)(b => Room.OccupancyObj.SetShutdownMinutes(b)); + occSensorAsset.RoomOccupied.AddSigToRVIFile = true; + + //var occSensorShutdownMinutes = FusionRoom.CreateOffsetUshortSig(70, "Occ Shutdown - Minutes", eSigIoMask.InputOutputSig); + + // Tie to method on occupancy object + //occSensorShutdownMinutes.OutputSig.UserObject(new Action(ushort)(b => Room.OccupancyObj.SetShutdownMinutes(b)); - RoomOccupancyRemoteStringFeedback = new StringFeedback(() => _roomOccupancyRemoteString); - Room.RoomOccupancy.RoomIsOccupiedFeedback.LinkInputSig(occSensorAsset.RoomOccupied.InputSig); - Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; - RoomOccupancyRemoteStringFeedback.LinkInputSig(occSensorAsset.RoomOccupancyInfo.InputSig); - + RoomOccupancyRemoteStringFeedback = new StringFeedback(() => _roomOccupancyRemoteString); + Room.RoomOccupancy.RoomIsOccupiedFeedback.LinkInputSig(occSensorAsset.RoomOccupied.InputSig); + Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; + RoomOccupancyRemoteStringFeedback.LinkInputSig(occSensorAsset.RoomOccupancyInfo.InputSig); + //} } - void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) + private void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e) { _roomOccupancyRemoteString = String.Format(RemoteOccupancyXml, e.BoolValue ? "Occupied" : "Unoccupied"); RoomOccupancyRemoteStringFeedback.FireUpdate(); } - /// - /// Helper to get the number from the end of a device's key string - /// - /// -1 if no number matched - int ExtractNumberFromKey(string key) - { + /// + /// Helper to get the number from the end of a device's key string + /// + /// -1 if no number matched + private int ExtractNumberFromKey(string key) + { var capture = System.Text.RegularExpressions.Regex.Match(key, @"\b(\d+)"); - if (!capture.Success) - return -1; - else return Convert.ToInt32(capture.Groups[1].Value); - } + if (!capture.Success) + { + return -1; + } + return Convert.ToInt32(capture.Groups[1].Value); + } - /// - /// Event handler for when room source changes - /// - protected void Room_CurrentSourceInfoChange(SourceListItem info, ChangeType type) - { - // Handle null. Nothing to do when switching from or to null - if (info == null || info.SourceDevice == null) - return; + /// + /// Event handler for when room source changes + /// + protected void Room_CurrentSourceInfoChange(SourceListItem info, ChangeType type) + { + // Handle null. Nothing to do when switching from or to null + if (info == null || info.SourceDevice == null) + { + return; + } - var dev = info.SourceDevice; - if (type == ChangeType.WillChange) - { - if (SourceToFeedbackSigs.ContainsKey(dev)) - SourceToFeedbackSigs[dev].BoolValue = false; - } - else - { - if (SourceToFeedbackSigs.ContainsKey(dev)) - SourceToFeedbackSigs[dev].BoolValue = true; + var dev = info.SourceDevice; + if (type == ChangeType.WillChange) + { + if (_sourceToFeedbackSigs.ContainsKey(dev)) + { + _sourceToFeedbackSigs[dev].BoolValue = false; + } + } + else + { + if (_sourceToFeedbackSigs.ContainsKey(dev)) + { + _sourceToFeedbackSigs[dev].BoolValue = true; + } //var name = (room == null ? "" : room.Name); - CurrentRoomSourceNameSig.InputSig.StringValue = info.SourceDevice.Name; - } - } + CurrentRoomSourceNameSig.InputSig.StringValue = info.SourceDevice.Name; + } + } - protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args) - { + protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args) + { + // The sig/UO method: Need separate handlers for fixed and user sigs, all flavors, + // even though they all contain sigs. - // The sig/UO method: Need separate handlers for fixed and user sigs, all flavors, - // even though they all contain sigs. + var sigData = args.UserConfiguredSigDetail as BooleanSigDataFixedName; - var sigData = (args.UserConfiguredSigDetail as BooleanSigDataFixedName); - if (sigData != null) - { - var outSig = sigData.OutputSig; - if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.BoolValue); - else if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.UShortValue); - else if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.StringValue); - return; - } + BoolOutputSig outSig; + if (sigData != null) + { + outSig = sigData.OutputSig; + if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.BoolValue); + } + else if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.UShortValue); + } + else if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.StringValue); + } + return; + } - var attrData = (args.UserConfiguredSigDetail as BooleanSigData); - if (attrData != null) - { - var outSig = attrData.OutputSig; - if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.BoolValue); - else if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.UShortValue); - else if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.StringValue); - return; - } - - } - } + var attrData = (args.UserConfiguredSigDetail as BooleanSigData); + if (attrData == null) + { + return; + } + outSig = attrData.OutputSig; + if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.BoolValue); + } + else if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.UShortValue); + } + else if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.StringValue); + } + } + } - public static class FusionRoomExtensions - { - /// - /// Creates and returns a fusion attribute. The join number will match the established Simpl - /// standard of 50+, and will generate a 50+ join in the RVI. It calls - /// FusionRoom.AddSig with join number - 49 - /// - /// The new attribute - public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) - { - if (number < 50) throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); - number -= 49; - fr.AddSig(eSigType.Bool, number, name, mask); - return fr.UserDefinedBooleanSigDetails[number]; - } + public static class FusionRoomExtensions + { + /// + /// Creates and returns a fusion attribute. The join number will match the established Simpl + /// standard of 50+, and will generate a 50+ join in the RVI. It calls + /// FusionRoom.AddSig with join number - 49 + /// + /// The new attribute + public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) + { + if (number < 50) + { + throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); + } + number -= 49; + fr.AddSig(eSigType.Bool, number, name, mask); + return fr.UserDefinedBooleanSigDetails[number]; + } - /// - /// Creates and returns a fusion attribute. The join number will match the established Simpl - /// standard of 50+, and will generate a 50+ join in the RVI. It calls - /// FusionRoom.AddSig with join number - 49 - /// - /// The new attribute - public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) - { - if (number < 50) throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); - number -= 49; - fr.AddSig(eSigType.UShort, number, name, mask); - return fr.UserDefinedUShortSigDetails[number]; - } + /// + /// Creates and returns a fusion attribute. The join number will match the established Simpl + /// standard of 50+, and will generate a 50+ join in the RVI. It calls + /// FusionRoom.AddSig with join number - 49 + /// + /// The new attribute + public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) + { + if (number < 50) + { + throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); + } + number -= 49; + fr.AddSig(eSigType.UShort, number, name, mask); + return fr.UserDefinedUShortSigDetails[number]; + } - /// - /// Creates and returns a fusion attribute. The join number will match the established Simpl - /// standard of 50+, and will generate a 50+ join in the RVI. It calls - /// FusionRoom.AddSig with join number - 49 - /// - /// The new attribute - public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) - { - if (number < 50) throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); - number -= 49; - fr.AddSig(eSigType.String, number, name, mask); - return fr.UserDefinedStringSigDetails[number]; - } + /// + /// Creates and returns a fusion attribute. The join number will match the established Simpl + /// standard of 50+, and will generate a 50+ join in the RVI. It calls + /// FusionRoom.AddSig with join number - 49 + /// + /// The new attribute + public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) + { + if (number < 50) + { + throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); + } + number -= 49; + fr.AddSig(eSigType.String, number, name, mask); + return fr.UserDefinedStringSigDetails[number]; + } - /// - /// Creates and returns a static asset - /// - /// the new asset - public static FusionStaticAsset CreateStaticAsset(this FusionRoom fr, uint number, string name, string type, string instanceId) - { + /// + /// Creates and returns a static asset + /// + /// the new asset + public static FusionStaticAsset CreateStaticAsset(this FusionRoom fr, uint number, string name, string type, + string instanceId) + { Debug.Console(0, "Adding Fusion Static Asset '{0}' to slot {1} with GUID: '{2}'", name, number, instanceId); - fr.AddAsset(eAssetType.StaticAsset, number, name, type, instanceId); - return fr.UserConfigurableAssetDetails[number].Asset as FusionStaticAsset; - } + fr.AddAsset(eAssetType.StaticAsset, number, name, type, instanceId); + return fr.UserConfigurableAssetDetails[number].Asset as FusionStaticAsset; + } - public static FusionOccupancySensor CreateOccupancySensorAsset(this FusionRoom fr, uint number, string name, string type, string instanceId) + public static FusionOccupancySensor CreateOccupancySensorAsset(this FusionRoom fr, uint number, string name, + string type, string instanceId) { - Debug.Console(0, "Adding Fusion Occupancy Sensor Asset '{0}' to slot {1} with GUID: '{2}'", name, number, instanceId); + Debug.Console(0, "Adding Fusion Occupancy Sensor Asset '{0}' to slot {1} with GUID: '{2}'", name, number, + instanceId); fr.AddAsset(eAssetType.OccupancySensor, number, name, type, instanceId); return fr.UserConfigurableAssetDetails[number].Asset as FusionOccupancySensor; } - } + } - //************************************************************************************************ - /// - /// Extensions to enhance Fusion room, asset and signal creation. - /// - public static class FusionStaticAssetExtensions - { - /// - /// Tries to set a Fusion asset with the make and model of a device. - /// If the provided Device is IMakeModel, will set the corresponding parameters on the fusion static asset. - /// Otherwise, does nothing. - /// - public static void TrySetMakeModel(this FusionStaticAsset asset, Device device) - { - var mm = device as IMakeModel; - if (mm != null) - { - asset.ParamMake.Value = mm.DeviceMake; - asset.ParamModel.Value = mm.DeviceModel; - } - } + //************************************************************************************************ + /// + /// Extensions to enhance Fusion room, asset and signal creation. + /// + public static class FusionStaticAssetExtensions + { + /// + /// Tries to set a Fusion asset with the make and model of a device. + /// If the provided Device is IMakeModel, will set the corresponding parameters on the fusion static asset. + /// Otherwise, does nothing. + /// + public static void TrySetMakeModel(this FusionStaticAsset asset, Device device) + { + var mm = device as IMakeModel; + if (mm != null) + { + asset.ParamMake.Value = mm.DeviceMake; + asset.ParamModel.Value = mm.DeviceModel; + } + } - /// - /// Tries to attach the AssetError input on a Fusion asset to a Device's - /// CommunicationMonitor.StatusChange event. Does nothing if the device is not - /// IStatusMonitor - /// - /// - /// - public static void TryLinkAssetErrorToCommunication(this FusionStaticAsset asset, Device device) - { - if (device is ICommunicationMonitor) - { - var monitor = (device as ICommunicationMonitor).CommunicationMonitor; - monitor.StatusChange += (o, a) => - { - // Link connected and error inputs on asset - asset.Connected.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; - asset.AssetError.InputSig.StringValue = a.Status.ToString(); - }; - // set current value - asset.Connected.InputSig.BoolValue = monitor.Status == MonitorStatus.IsOk; - asset.AssetError.InputSig.StringValue = monitor.Status.ToString(); - } - } - } + /// + /// Tries to attach the AssetError input on a Fusion asset to a Device's + /// CommunicationMonitor.StatusChange event. Does nothing if the device is not + /// IStatusMonitor + /// + /// + /// + public static void TryLinkAssetErrorToCommunication(this FusionStaticAsset asset, Device device) + { + if (device is ICommunicationMonitor) + { + var monitor = (device as ICommunicationMonitor).CommunicationMonitor; + monitor.StatusChange += (o, a) => + { + // Link connected and error inputs on asset + asset.Connected.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; + asset.AssetError.InputSig.StringValue = a.Status.ToString(); + }; + // set current value + asset.Connected.InputSig.BoolValue = monitor.Status == MonitorStatus.IsOk; + asset.AssetError.InputSig.StringValue = monitor.Status.ToString(); + } + } + } public class RoomInformation { + public RoomInformation() + { + FusionCustomProperties = new List(); + } + public string ID { get; set; } public string Name { get; set; } public string Location { get; set; } @@ -1598,27 +1738,22 @@ namespace PepperDash.Essentials.Core.Fusion public string SubErrorMsg { get; set; } public string EmailInfo { get; set; } public List FusionCustomProperties { get; set; } - - public RoomInformation() - { - FusionCustomProperties = new List(); - } } + public class FusionCustomProperty { - public string ID { get; set; } - public string CustomFieldName { get; set; } - public string CustomFieldType { get; set; } - public string CustomFieldValue { get; set; } - public FusionCustomProperty() { - } public FusionCustomProperty(string id) { ID = id; } + + public string ID { get; set; } + public string CustomFieldName { get; set; } + public string CustomFieldType { get; set; } + public string CustomFieldValue { get; set; } } } \ No newline at end of file From 9c4650b4afd573ae05ae4fa85bf9f59b8b4c1f6d Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 16:32:06 -0700 Subject: [PATCH 19/59] fixes to get it to load --- .../Room/Config/EssentialsRoomConfig.cs | 4 +-- .../Room/Config/EssentialsTechRoomConfig.cs | 17 +++++++++-- .../Room/Types/EssentialsTechRoom.cs | 28 +++++++++---------- .../Global/Scheduler.cs | 8 ++++-- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs index 3aee1e20..79844ce4 100644 --- a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs @@ -31,7 +31,7 @@ namespace PepperDash.Essentials.Room.Config { return new EssentialsHuddleVtc1Room(roomConfig); } - if (typeName == "ddvc01Bridge") + if (typeName == "ddvc01bridge") { return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing. } @@ -40,7 +40,7 @@ namespace PepperDash.Essentials.Room.Config return new EssentialsDualDisplayRoom(roomConfig); } - return typeName != "techRoom" ? null : new EssentialsTechRoom(roomConfig); + return typeName != "techroom" ? null : new EssentialsTechRoom(roomConfig); } /// diff --git a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs index e4b88e96..ccf9ec6d 100644 --- a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs @@ -1,22 +1,33 @@ using System.Collections.Generic; +using Newtonsoft.Json; namespace PepperDash.Essentials.Room.Config { public class EssentialsTechRoomConfig { + [JsonProperty("displays")] public List Displays; + + [JsonProperty("tuners")] public List Tuners; - public string ScheduleProviderKey; + + [JsonProperty("userPin")] public string UserPin; + + [JsonProperty("techPin")] public string TechPin; + + [JsonProperty("presetFileName")] public string PresetsFileName; - public List RoomScheduledEvents; + + [JsonProperty("scheduledEvents")] + public List ScheduledEvents; public EssentialsTechRoomConfig() { Displays = new List(); Tuners = new List(); - RoomScheduledEvents = new List(); + ScheduledEvents = new List(); } } } \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index cb8ebfa1..c7f474eb 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -74,7 +74,7 @@ namespace PepperDash.Essentials private void CreateOrUpdateScheduledEvents() { - var eventsConfig = _config.RoomScheduledEvents; + var eventsConfig = _config.ScheduledEvents; GetOrCreateScheduleGroup(); @@ -127,11 +127,11 @@ namespace PepperDash.Essentials { //update config based on key of scheduleEvent GetOrCreateScheduleGroup(); - var existingEvent = _config.RoomScheduledEvents.FirstOrDefault(e => e.Key == scheduledEvent.Key); + var existingEvent = _config.ScheduledEvents.FirstOrDefault(e => e.Key == scheduledEvent.Key); if (existingEvent == null) { - _config.RoomScheduledEvents.Add(scheduledEvent); + _config.ScheduledEvents.Add(scheduledEvent); } //create or update event based on config @@ -144,7 +144,7 @@ namespace PepperDash.Essentials OnScheduledEventUpdate(); } - public void OnScheduledEventUpdate() + private void OnScheduledEventUpdate() { var handler = ScheduledEventsChanged; @@ -153,14 +153,14 @@ namespace PepperDash.Essentials return; } - handler(this, new ScheduledEventEventArgs {ScheduledEvents = _config.RoomScheduledEvents}); + handler(this, new ScheduledEventEventArgs {ScheduledEvents = _config.ScheduledEvents}); } public event EventHandler ScheduledEventsChanged; private void HandleScheduledEvent(ScheduledEvent schevent, ScheduledEventCommon.eCallbackReason type) { - var eventConfig = _config.RoomScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name); + var eventConfig = _config.ScheduledEvents.FirstOrDefault(e => e.Key == schevent.Name); if (eventConfig == null) { @@ -221,42 +221,42 @@ namespace PepperDash.Essentials protected override Func IsWarmingFeedbackFunc { - get { throw new NotImplementedException(); } + get { return () => false; } } protected override Func IsCoolingFeedbackFunc { - get { throw new NotImplementedException(); } + get { return () => false; } } protected override Func OnFeedbackFunc { - get { throw new NotImplementedException(); } + get { return () => RoomPowerIsOn; } } protected override void EndShutdown() { - throw new NotImplementedException(); + } public override void SetDefaultLevels() { - throw new NotImplementedException(); + } public override void PowerOnToDefaultOrLastSource() { - throw new NotImplementedException(); + } public override bool RunDefaultPresentRoute() { - throw new NotImplementedException(); + return false; } public override void RoomVacatedForTimeoutPeriod(object o) { - throw new NotImplementedException(); + } #endregion diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs index 64ba57df..6544f1f4 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs @@ -175,13 +175,15 @@ namespace PepperDash.Essentials.Core scheduledEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); - scheduledEvent.Recurrence.Weekly(config.Days); - var eventTime = DateTime.Parse(config.Time); - if (DateTime.Now < eventTime) eventTime.AddDays(1); + if (DateTime.Now > eventTime) eventTime = eventTime.AddDays(1); scheduledEvent.DateAndTime.SetAbsoluteEventTime(eventTime); + + scheduledEvent.Recurrence.Weekly(config.Days); + + } } } \ No newline at end of file From c4755f23cd7a80e70e749e184ca07e1d640a5860 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 16:58:33 -0700 Subject: [PATCH 20/59] added logic to subscribe to scheduled event --- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 6 +++++- .../PepperDashEssentialsBase/Global/Scheduler.cs | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index c7f474eb..f6fe1b39 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -120,7 +120,9 @@ namespace PepperDash.Essentials _roomScheduledEventGroup.DeleteEvent(roomEvent); - SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup); + var tempEvent = SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup); + + tempEvent.UserCallBack += HandleScheduledEvent; } public void AddOrUpdateScheduledEvent(ScheduledEventConfig scheduledEvent) @@ -168,6 +170,8 @@ namespace PepperDash.Essentials return; } + Debug.Console(1, this, "Running actions for event {0}", schevent.Name); + if (eventConfig.Acknowledgeable) { schevent.Acknowledge(); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs index 6544f1f4..9f27a15c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs @@ -151,12 +151,12 @@ namespace PepperDash.Essentials.Core return evnt.Recurrence.RecurrenceDays == days; } - public static void CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group) + public static ScheduledEvent CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group) { if (group == null) { Debug.Console(0, "Unable to create event. Group is null"); - return; + return null; } var scheduledEvent = new ScheduledEvent(config.Key, group) { @@ -183,7 +183,7 @@ namespace PepperDash.Essentials.Core scheduledEvent.Recurrence.Weekly(config.Days); - + return scheduledEvent; } } } \ No newline at end of file From 099e387570ff9be4efef9029c1736728c0927c3f Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 7 Dec 2020 17:21:05 -0700 Subject: [PATCH 21/59] getting things in the right order for scheduling --- .../Room/Types/EssentialsTechRoom.cs | 6 ++--- .../Global/Scheduler.cs | 22 +++++++++---------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index f6fe1b39..b9edbb70 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -102,7 +102,7 @@ namespace PepperDash.Essentials { if (!_roomScheduledEventGroup.ScheduledEvents.ContainsKey(scheduledEvent.Name)) { - SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup); + SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup, HandleScheduledEvent); return; } @@ -120,9 +120,7 @@ namespace PepperDash.Essentials _roomScheduledEventGroup.DeleteEvent(roomEvent); - var tempEvent = SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup); - - tempEvent.UserCallBack += HandleScheduledEvent; + SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup, HandleScheduledEvent); } public void AddOrUpdateScheduledEvent(ScheduledEventConfig scheduledEvent) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs index 9f27a15c..11232896 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs @@ -151,12 +151,12 @@ namespace PepperDash.Essentials.Core return evnt.Recurrence.RecurrenceDays == days; } - public static ScheduledEvent CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group) + public static void CreateEventFromConfig(ScheduledEventConfig config, ScheduledEventGroup group, ScheduledEvent.UserEventCallBack handler) { if (group == null) { Debug.Console(0, "Unable to create event. Group is null"); - return null; + return; } var scheduledEvent = new ScheduledEvent(config.Key, group) { @@ -164,14 +164,7 @@ namespace PepperDash.Essentials.Core Persistent = config.Persistent }; - if (config.Enable) - { - scheduledEvent.Resume(); - } - else - { - scheduledEvent.Pause(); - } + scheduledEvent.UserCallBack += handler; scheduledEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday); @@ -183,7 +176,14 @@ namespace PepperDash.Essentials.Core scheduledEvent.Recurrence.Weekly(config.Days); - return scheduledEvent; + if (config.Enable) + { + scheduledEvent.Enable(); + } + else + { + scheduledEvent.Disable(); + } } } } \ No newline at end of file From 2eaf21b1e0790178fb425de114a57fd198e79770 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 08:01:01 -0700 Subject: [PATCH 22/59] Fix event retrieval --- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index b9edbb70..da362173 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -100,7 +100,7 @@ namespace PepperDash.Essentials private void CreateOrUpdateSingleEvent(ScheduledEventConfig scheduledEvent) { - if (!_roomScheduledEventGroup.ScheduledEvents.ContainsKey(scheduledEvent.Name)) + if (!_roomScheduledEventGroup.ScheduledEvents.ContainsKey(scheduledEvent.Key)) { SchedulerUtilities.CreateEventFromConfig(scheduledEvent, _roomScheduledEventGroup, HandleScheduledEvent); return; From 2c36c0f2cbe87c893045268520f6c54a5a1491d8 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 08:01:25 -0700 Subject: [PATCH 23/59] Run `GoWithLoad` command in separate thread when using donotloadonnextboot --- PepperDashEssentials/ControlSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 4e24de9f..58a545f2 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -53,7 +53,7 @@ namespace PepperDash.Essentials if (Debug.DoNotLoadOnNextBoot) { - CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file", + CrestronConsole.AddNewConsoleCommand(s => CrestronInvoke.BeginInvoke((o) => GoWithLoad()), "go", "Loads configuration file", ConsoleAccessLevelEnum.AccessOperator); } From a78b29b0a12087bb0c311db5abe09a35e0349654 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 08:01:58 -0700 Subject: [PATCH 24/59] #523 Add NullCheck and Debug message for com Port --- .../PepperDashEssentialsBase/Comm and IR/ComPortController.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/ComPortController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/ComPortController.cs index ddb578d7..8d2f2db1 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/ComPortController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/ComPortController.cs @@ -56,6 +56,10 @@ namespace PepperDash.Essentials.Core private void RegisterAndConfigureComPort() { + if (Port == null) + { + Debug.Console(0,this,Debug.ErrorLogLevel.Error, "Configured com Port for this device does not exist."); + } if (Port.Parent is CrestronControlSystem) { var result = Port.Register(); From 4d67279827f0d436d177a8a850af4650aaf893b8 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 08:02:35 -0700 Subject: [PATCH 25/59] Log message to error log when configured com port doesn't exist --- .../PepperDashEssentialsBase/Comm and IR/CommFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs index a8fa67e4..8a5efe47 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/CommFactory.cs @@ -104,7 +104,7 @@ namespace PepperDash.Essentials.Core var dev = GetIComPortsDeviceFromManagedDevice(config.ControlPortDevKey); if (dev != null && config.ControlPortNumber <= dev.NumberOfComPorts) return dev.ComPorts[config.ControlPortNumber]; - Debug.Console(0, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber); + Debug.Console(0,Debug.ErrorLogLevel.Notice, "GetComPort: Device '{0}' does not have com port {1}", config.ControlPortDevKey, config.ControlPortNumber); return null; } From d990930b19565eac741169b2f6b60f6ba4a95879 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 11:05:52 -0700 Subject: [PATCH 26/59] #523 Add return statement --- .../PepperDashEssentialsBase/Comm and IR/ComPortController.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/ComPortController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/ComPortController.cs index 8d2f2db1..75e9ae72 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/ComPortController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Comm and IR/ComPortController.cs @@ -59,6 +59,7 @@ namespace PepperDash.Essentials.Core if (Port == null) { Debug.Console(0,this,Debug.ErrorLogLevel.Error, "Configured com Port for this device does not exist."); + return; } if (Port.Parent is CrestronControlSystem) { From 8feb7a142c2863424e9cd8f61cba05aff42ae0e7 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 11:06:06 -0700 Subject: [PATCH 27/59] #524 Fix Fusion Printing --- .../Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index 9270ed37..dcc86635 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -276,7 +276,7 @@ namespace PepperDash.Essentials.Core.Fusion Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Fusion Guids successfully read from file: {0}", filePath); - Debug.Console(1, this, "\nRoom Name: {0}\nIPID: {1:x}\n RoomGuid: {2}", Room.Name, _ipId, RoomGuid); + Debug.Console(1, this, "\r\n********************\r\n\tRoom Name: {0}\r\n\tIPID: {1:X}\r\n\tRoomGuid: {2}\r\n*******************", Room.Name, _ipId, RoomGuid); foreach (var item in FusionStaticAssets) { From 9204ad2701268fb3f5d40a7331fe69be9170c833 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 12:48:26 -0700 Subject: [PATCH 28/59] #525 Add Rooms Array & LinkToRooms method --- .../Bridges/BridgeBase.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs index 151b5461..443a720e 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs @@ -131,6 +131,16 @@ namespace PepperDash.Essentials.Core.Bridges } } + RegisterEisc(); + } + + private void RegisterEisc() + { + if (Eisc.Registered) + { + return; + } + var registerResult = Eisc.Register(); if (registerResult != eDeviceRegistrationUnRegistrationResponse.Success) @@ -142,6 +152,27 @@ namespace PepperDash.Essentials.Core.Bridges Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "EISC registration successful"); } + public void LinkToRooms() + { + Debug.Console(1, this, "Linking Rooms..."); + + foreach (var room in PropertiesConfig.Rooms) + { + var rm = DeviceManager.GetDeviceForKey(room.RoomKey) as IBridgeAdvanced; + + if (rm == null) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, + "Room {0} does not implement IBridgeAdvanced. Skipping...", room.RoomKey); + continue; + } + + rm.LinkToApi(Eisc, room.JoinStart, room.JoinMapKey, this); + } + + RegisterEisc(); + } + /// /// Adds a join map /// @@ -290,6 +321,9 @@ namespace PepperDash.Essentials.Core.Bridges [JsonProperty("devices")] public List Devices { get; set; } + [JsonProperty("rooms")] + public List Rooms { get; set; } + public class ApiDevicePropertiesConfig { @@ -303,6 +337,18 @@ namespace PepperDash.Essentials.Core.Bridges public string JoinMapKey { get; set; } } + public class ApiRoomPropertiesConfig + { + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + [JsonProperty("joinStart")] + public uint JoinStart { get; set; } + + [JsonProperty("joinMapKey")] + public string JoinMapKey { get; set; } + } + } public class EiscApiAdvancedFactory : EssentialsDeviceFactory From 2e636082bb016bebb165ec55d8f58f464e17170c Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 12:50:55 -0700 Subject: [PATCH 29/59] #526 Add ITvPresetsProvider interface --- .../DeviceTypeInterfaces/ITvPresetsProvider.cs | 9 +++++++++ .../PepperDash_Essentials_Core.csproj | 1 + 2 files changed, 10 insertions(+) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ITvPresetsProvider.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ITvPresetsProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ITvPresetsProvider.cs new file mode 100644 index 00000000..61b8ec09 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/ITvPresetsProvider.cs @@ -0,0 +1,9 @@ +using PepperDash.Essentials.Core.Presets; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + public interface ITvPresetsProvider + { + DevicePresetsModel TvPresets { get; } + } +} \ 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 1a2fc594..49f4b25a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -199,6 +199,7 @@ + From 748b1ca14767f92677c9c92d40fd61592f882c0b Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 12:51:20 -0700 Subject: [PATCH 30/59] Add config properties Implement ITvPresetsProvider --- PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs | 4 ++++ PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs index ccf9ec6d..7b470574 100644 --- a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs @@ -23,6 +23,10 @@ namespace PepperDash.Essentials.Room.Config [JsonProperty("scheduledEvents")] public List ScheduledEvents; + [JsonProperty("isPrimary")] public bool IsPrimary; + + [JsonProperty("isTvPresetsProvider")] public bool IsTvPresetsProvider; + public EssentialsTechRoomConfig() { Displays = new List(); diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index da362173..e639a4a0 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -7,13 +7,14 @@ using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Presets; using PepperDash.Essentials.Devices.Common; using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials { - public class EssentialsTechRoom : EssentialsRoomBase + public class EssentialsTechRoom : EssentialsRoomBase, ITvPresetsProvider { private readonly EssentialsTechRoomConfig _config; private readonly Dictionary _displays; @@ -41,7 +42,7 @@ namespace PepperDash.Essentials CreateOrUpdateScheduledEvents(); } - public DevicePresetsModel TunerPresets + public DevicePresetsModel TvPresets { get { return _tunerPresets; } } From 169e89774853612a367d7b58749a8baf0d45e5dd Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 12:54:35 -0700 Subject: [PATCH 31/59] Add CriticalSection for file ops --- .../Presets/DevicePresets.cs | 60 ++++++++++++------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index ccce6ea7..84b3cbd3 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -15,6 +15,7 @@ namespace PepperDash.Essentials.Core.Presets /// public class DevicePresetsModel : Device { + private CCriticalSection _fileOps = new CCriticalSection(); private readonly bool _initSuccess; /// @@ -101,27 +102,35 @@ namespace PepperDash.Essentials.Core.Presets public void LoadChannels() { - PresetsAreLoaded = false; try { - var pl = JsonConvert.DeserializeObject(File.ReadToEnd(_filePath, Encoding.ASCII)); - Name = pl.Name; - PresetsList = pl.Channels; - } - catch (Exception e) - { - Debug.Console(2, this, - "LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}", - _filePath, e.Message); - // Just save a default empty list - PresetsList = new List(); - } - PresetsAreLoaded = true; + _fileOps.Enter(); + PresetsAreLoaded = false; + try + { + var pl = JsonConvert.DeserializeObject(File.ReadToEnd(_filePath, Encoding.ASCII)); + Name = pl.Name; + PresetsList = pl.Channels; + } + catch (Exception e) + { + Debug.Console(2, this, + "LoadChannels: Error reading presets file. These presets will be empty:\r '{0}'\r Error:{1}", + _filePath, e.Message); + // Just save a default empty list + PresetsList = new List(); + } + PresetsAreLoaded = true; - var handler = PresetsLoaded; - if (handler != null) + var handler = PresetsLoaded; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + finally { - handler(this, EventArgs.Empty); + _fileOps.Leave(); } } @@ -209,12 +218,21 @@ namespace PepperDash.Essentials.Core.Presets private void SavePresets() { - var json = JsonConvert.SerializeObject(PresetsList); - - using (var file = File.Open(_filePath, FileMode.Truncate)) + try { - file.Write(json, Encoding.UTF8); + _fileOps.Enter(); + var json = JsonConvert.SerializeObject(PresetsList); + + using (var file = File.Open(_filePath, FileMode.Truncate)) + { + file.Write(json, Encoding.UTF8); + } } + finally + { + _fileOps.Leave(); + } + } private void Pulse(Action act) From 56cf54a6443b521c3e3b6be7b26db51eb289a9e1 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 16:24:03 -0700 Subject: [PATCH 32/59] Added LinkRooms as a PostActivationAction --- .../Bridges/BridgeBase.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs index 443a720e..86db81ba 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs @@ -99,12 +99,19 @@ namespace PepperDash.Essentials.Core.Bridges Eisc.SigChange += Eisc_SigChange; AddPostActivationAction(LinkDevices); + AddPostActivationAction(LinkRooms); } private void LinkDevices() { Debug.Console(1, this, "Linking Devices..."); + if (PropertiesConfig.Devices == null) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "No devices linked to this bridge"); + return; + } + foreach (var d in PropertiesConfig.Devices) { var device = DeviceManager.GetDeviceForKey(d.DeviceKey); @@ -152,10 +159,16 @@ namespace PepperDash.Essentials.Core.Bridges Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "EISC registration successful"); } - public void LinkToRooms() + public void LinkRooms() { Debug.Console(1, this, "Linking Rooms..."); + if (PropertiesConfig.Rooms == null) + { + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "No rooms linked to this bridge."); + return; + } + foreach (var room in PropertiesConfig.Rooms) { var rm = DeviceManager.GetDeviceForKey(room.RoomKey) as IBridgeAdvanced; From b09c1517385cd270b07eca21658810f304debd90 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 16:24:22 -0700 Subject: [PATCH 33/59] Added logic to send presets to far end --- .../DeviceTypeInterfaces/INumeric.cs | 4 +-- .../Presets/DevicePresets.cs | 29 ++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/INumeric.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/INumeric.cs index 0294a0b5..62ea8b3f 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/INumeric.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/DeviceTypeInterfaces/INumeric.cs @@ -1,5 +1,5 @@ using Crestron.SimplSharpPro.DeviceSupport; - +using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.SmartObjects; @@ -8,7 +8,7 @@ namespace PepperDash.Essentials.Core /// /// /// - public interface INumericKeypad + public interface INumericKeypad:IKeyed { void Digit0(bool pressRelease); void Digit1(bool pressRelease); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index 84b3cbd3..55522cf0 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json; using PepperDash.Core; //using SSMono.IO; +using PepperDash.Core.WebApi.Presets; namespace PepperDash.Essentials.Core.Presets { @@ -15,9 +16,13 @@ namespace PepperDash.Essentials.Core.Presets /// public class DevicePresetsModel : Device { - private CCriticalSection _fileOps = new CCriticalSection(); + public delegate void PresetChangedCallback(ISetTopBoxNumericKeypad device, string channel); + + private readonly CCriticalSection _fileOps = new CCriticalSection(); private readonly bool _initSuccess; + private ISetTopBoxNumericKeypad _setTopBox; + /// /// The methods on the STB device to call when dialing /// @@ -32,6 +37,8 @@ namespace PepperDash.Essentials.Core.Presets { try { + _setTopBox = setTopBox; + // Grab the digit functions from the device // If any fail, the whole thing fails peacefully _dialFunctions = new Dictionary>(10) @@ -76,6 +83,8 @@ namespace PepperDash.Essentials.Core.Presets _initSuccess = true; } + public event PresetChangedCallback PresetChanged; + public int PulseTime { get; set; } public int DigitSpacingMs { get; set; } public bool PresetsAreLoaded { get; private set; } @@ -172,6 +181,10 @@ namespace PepperDash.Essentials.Core.Presets } _dialIsRunning = false; }); + + if (_setTopBox == null) return; + + OnPresetChanged(_setTopBox, chanNum); } public void Dial(int presetNum, ISetTopBoxNumericKeypad setTopBox) @@ -201,9 +214,23 @@ namespace PepperDash.Essentials.Core.Presets _enterFunction = setTopBox.KeypadEnter; + OnPresetChanged(setTopBox, chanNum); + Dial(chanNum); } + private void OnPresetChanged(ISetTopBoxNumericKeypad setTopBox, string channel) + { + var handler = PresetChanged; + + if (handler == null) + { + return; + } + + handler(setTopBox, channel); + } + public void UpdatePreset(int index, PresetChannel preset) { if (index >= PresetsList.Count) From 7e8f216afb77cbfa393901e47948723cf2884267 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 16:24:35 -0700 Subject: [PATCH 34/59] added logic to send presets to far end --- .../Room/Types/EssentialsTechRoom.cs | 119 ++++++++++++++++-- 1 file changed, 110 insertions(+), 9 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index e639a4a0..74eaac6a 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -3,9 +3,12 @@ using System.Collections.Generic; using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.Scheduler; +using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Presets; @@ -14,7 +17,7 @@ using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials { - public class EssentialsTechRoom : EssentialsRoomBase, ITvPresetsProvider + public class EssentialsTechRoom : EssentialsRoomBase, ITvPresetsProvider, IBridgeAdvanced { private readonly EssentialsTechRoomConfig _config; private readonly Dictionary _displays; @@ -22,6 +25,7 @@ namespace PepperDash.Essentials private readonly DevicePresetsModel _tunerPresets; private readonly Dictionary _tuners; + private Dictionary _currentPresets; private ScheduledEventGroup _roomScheduledEventGroup; public EssentialsTechRoom(DeviceConfig config) : base(config) @@ -32,20 +36,21 @@ namespace PepperDash.Essentials _tunerPresets.LoadChannels(); + _tunerPresets.PresetChanged += TunerPresetsOnPresetChanged; + _tuners = GetDevices(_config.Tuners); _displays = GetDevices(_config.Displays); RoomPowerIsOnFeedback = new BoolFeedback(() => RoomPowerIsOn); + SetUpTunerPresetsFeedback(); + SubscribeToDisplayFeedbacks(); CreateOrUpdateScheduledEvents(); } - public DevicePresetsModel TvPresets - { - get { return _tunerPresets; } - } + public Dictionary CurrentPresetsFeedbacks { get; private set; } public Dictionary Tuners { @@ -64,6 +69,43 @@ namespace PepperDash.Essentials get { return _displays.All(kv => kv.Value.PowerIsOnFeedback.BoolValue); } } + #region ITvPresetsProvider Members + + public DevicePresetsModel TvPresets + { + get { return _tunerPresets; } + } + + #endregion + + private void TunerPresetsOnPresetChanged(ISetTopBoxNumericKeypad device, string channel) + { + if (!_currentPresets.ContainsKey(device.Key)) + { + return; + } + + _currentPresets[device.Key] = channel; + + if (!CurrentPresetsFeedbacks.ContainsKey(device.Key)) + { + CurrentPresetsFeedbacks[device.Key].FireUpdate(); + } + } + + private void SetUpTunerPresetsFeedback() + { + _currentPresets = new Dictionary(); + CurrentPresetsFeedbacks = new Dictionary(); + + foreach (var setTopBox in _tuners) + { + var tuner = setTopBox.Value; + _currentPresets.Add(tuner.Key, String.Empty); + CurrentPresetsFeedbacks.Add(tuner.Key, new StringFeedback(() => _currentPresets[tuner.Key])); + } + } + private void SubscribeToDisplayFeedbacks() { foreach (var display in _displays) @@ -239,17 +281,14 @@ namespace PepperDash.Essentials protected override void EndShutdown() { - } public override void SetDefaultLevels() { - } public override void PowerOnToDefaultOrLastSource() { - } public override bool RunDefaultPresentRoute() @@ -259,10 +298,72 @@ namespace PepperDash.Essentials public override void RoomVacatedForTimeoutPeriod(object o) { - } #endregion + + #region Implementation of IBridgeAdvanced + + public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + + var joinMap = new EssentialsTechRoomJoinMap(joinStart); + var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); + + if (!String.IsNullOrEmpty(joinMapSerialized)) + { + joinMap = JsonConvert.DeserializeObject(joinMapSerialized); + } + + if (bridge != null) + { + bridge.AddJoinMap(Key, joinMap); + } + uint i; + if (_config.IsPrimary) + { + i = 0; + foreach (var feedback in CurrentPresetsFeedbacks) + { + feedback.Value.LinkInputSig(trilist.StringInput[(uint) (joinMap.CurrentPreset.JoinNumber + i)]); + i++; + } + + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) + { + return; + } + + foreach (var feedback in CurrentPresetsFeedbacks) + { + feedback.Value.FireUpdate(); + } + }; + } + + i = 0; + foreach (var setTopBox in _tuners) + { + var tuner = setTopBox; + + trilist.SetStringSigAction(joinMap.CurrentPreset.JoinNumber + i, s => _tunerPresets.Dial(s, tuner.Value)); + } + } + + #endregion + + private class EssentialsTechRoomJoinMap : JoinMapBaseAdvanced + { + [JoinName("currentPreset")] + public JoinDataComplete CurrentPreset = new JoinDataComplete(new JoinData {JoinNumber = 1, JoinSpan = 16}, + new JoinMetadata {Description = "Current Tuner Preset", JoinType = eJoinType.Serial}); + + public EssentialsTechRoomJoinMap(uint joinStart) : base(joinStart, typeof(EssentialsTechRoomJoinMap)) + { + } + } } public class ScheduledEventEventArgs : EventArgs From 6e4fa48b9d1b16dd8e5bdb2698f9c5da80c9665e Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 8 Dec 2020 16:34:00 -0700 Subject: [PATCH 35/59] rearrange message formatting --- .../PepperDashEssentialsBase/Plugins/PluginLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs index f0a7aeeb..01da1c54 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Plugins/PluginLoader.cs @@ -410,7 +410,7 @@ namespace PepperDash.Essentials if (!passed) { Debug.Console(0, Debug.ErrorLogLevel.Error, - "**********\r\nPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n**********", + "\r\n********************\r\n\tPlugin indicates minimum Essentials version {0}. Dependency check failed. Skipping Plugin {1}\r\n********************", plugin.MinimumEssentialsFrameworkVersion, loadedAssembly.Name); return; } From 3e5685994341174ecd36d48e256e8594a9863316 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 9 Dec 2020 15:14:52 -0700 Subject: [PATCH 36/59] add UpdatePresets method --- .../PepperDashEssentialsBase/Presets/DevicePresets.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index 55522cf0..85e3038e 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -243,6 +243,13 @@ namespace PepperDash.Essentials.Core.Presets SavePresets(); } + public void UpdatePresets(List presets) + { + PresetsList = presets; + + SavePresets(); + } + private void SavePresets() { try From f8ae6264f7e5bc1d62fa9a89242a93422c4d6c77 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 9 Dec 2020 16:18:21 -0700 Subject: [PATCH 37/59] add some debug statements and fix presets file loading --- PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs | 2 +- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 2 +- .../PepperDashEssentialsBase/Presets/DevicePresets.cs | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs index 7b470574..292a6b7c 100644 --- a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs @@ -17,7 +17,7 @@ namespace PepperDash.Essentials.Room.Config [JsonProperty("techPin")] public string TechPin; - [JsonProperty("presetFileName")] + [JsonProperty("presetsFileName")] public string PresetsFileName; [JsonProperty("scheduledEvents")] diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index 74eaac6a..c90e9414 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -34,7 +34,7 @@ namespace PepperDash.Essentials _tunerPresets = new DevicePresetsModel(String.Format("{0}-presets", config.Key), _config.PresetsFileName); - _tunerPresets.LoadChannels(); + _tunerPresets.SetFileName(_config.PresetsFileName); _tunerPresets.PresetChanged += TunerPresetsOnPresetChanged; diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index 85e3038e..6fb228a4 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -106,6 +106,8 @@ namespace PepperDash.Essentials.Core.Presets public void SetFileName(string path) { _filePath = ListPathPrefix + path; + + Debug.Console(2, this, "Setting presets file path to {0}", _filePath); LoadChannels(); } @@ -114,6 +116,8 @@ namespace PepperDash.Essentials.Core.Presets try { _fileOps.Enter(); + + Debug.Console(2, this, "Loading presets from {0}", _filePath); PresetsAreLoaded = false; try { From 1ee87c0499964a2f1bb9034afe4358e8328a0084 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 9 Dec 2020 16:37:14 -0700 Subject: [PATCH 38/59] add some debug statements and fix presets file loading --- .../Presets/PresetChannel.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/PresetChannel.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/PresetChannel.cs index b9650e60..259ccbb9 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/PresetChannel.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/PresetChannel.cs @@ -10,19 +10,22 @@ namespace PepperDash.Essentials.Core.Presets public class PresetChannel { - [JsonProperty(Required = Required.Always)] + [JsonProperty(Required = Required.Always,PropertyName = "name")] public string Name { get; set; } - [JsonProperty(Required = Required.Always)] + + [JsonProperty(Required = Required.Always, PropertyName = "iconUrl")] public string IconUrl { get; set; } - [JsonProperty(Required = Required.Always)] + + [JsonProperty(Required = Required.Always, PropertyName = "channel")] public string Channel { get; set; } } public class PresetsList { - [JsonProperty(Required=Required.Always)] + [JsonProperty(Required=Required.Always,PropertyName = "name")] public string Name { get; set; } - [JsonProperty(Required = Required.Always)] + + [JsonProperty(Required = Required.Always, PropertyName = "channels")] public List Channels { get; set; } } } \ No newline at end of file From 01ddf1721ca8a944a7106978197b1d1d17241caa Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 11 Dec 2020 15:42:38 -0700 Subject: [PATCH 39/59] add method to get scheduled events --- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 5 +++++ .../PepperDashEssentialsBase/Global/Scheduler.cs | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index c90e9414..3dc45c3a 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -187,6 +187,11 @@ namespace PepperDash.Essentials OnScheduledEventUpdate(); } + public List GetScheduledEvents() + { + return _config.ScheduledEvents ?? new List(); + } + private void OnScheduledEventUpdate() { var handler = ScheduledEventsChanged; diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs index 11232896..192f7dd0 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs @@ -170,7 +170,15 @@ namespace PepperDash.Essentials.Core var eventTime = DateTime.Parse(config.Time); - if (DateTime.Now > eventTime) eventTime = eventTime.AddDays(1); + if (DateTime.Now > eventTime) + { + eventTime = eventTime.AddDays(1); + } + + while (!config.Days.ToString().ToLower().Contains(eventTime.DayOfWeek.ToString().ToLower())) + { + eventTime = eventTime.AddDays(1); + } scheduledEvent.DateAndTime.SetAbsoluteEventTime(eventTime); From eb114b4a951d25a16906c61efdbe6914c0c44844 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 15 Dec 2020 08:44:10 -0700 Subject: [PATCH 40/59] make Days enum serialize to string --- .../Room/Config/EssentialsRoomScheduledEventsConfig.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs index 366f453c..88ac7db9 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Crestron.SimplSharp.Scheduler; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Room.Config @@ -20,6 +21,7 @@ namespace PepperDash.Essentials.Room.Config public string Name; [JsonProperty("days")] + [JsonConverter(typeof(StringEnumConverter))] public ScheduledEventCommon.eWeekDays Days; [JsonProperty("time")] From a4a99f4a9b045f5660a7931ec32be2d906f03828 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 15 Dec 2020 09:47:08 -0700 Subject: [PATCH 41/59] remove JsonConverter Attribute --- .../Room/Config/EssentialsRoomScheduledEventsConfig.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs index 88ac7db9..cd0c2586 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Config/EssentialsRoomScheduledEventsConfig.cs @@ -21,7 +21,6 @@ namespace PepperDash.Essentials.Room.Config public string Name; [JsonProperty("days")] - [JsonConverter(typeof(StringEnumConverter))] public ScheduledEventCommon.eWeekDays Days; [JsonProperty("time")] From d2c308c0092f1c9f735037a8ba2704de0f9c86e2 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 15 Dec 2020 09:47:35 -0700 Subject: [PATCH 42/59] Add methods & logic to make sure... ...day & time is in the list of recurrence days --- .../Global/Scheduler.cs | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs index 192f7dd0..fb305172 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Global/Scheduler.cs @@ -1,10 +1,14 @@ using System; using System.Collections.Generic; +using System.Linq; using Crestron.SimplSharp; +using Crestron.SimplSharp.Reflection; using Crestron.SimplSharp.Scheduler; using PepperDash.Core; +using PepperDash.Essentials.Core.Fusion; using PepperDash.Essentials.Room.Config; +using Activator = System.Activator; namespace PepperDash.Essentials.Core { @@ -175,9 +179,18 @@ namespace PepperDash.Essentials.Core eventTime = eventTime.AddDays(1); } - while (!config.Days.ToString().ToLower().Contains(eventTime.DayOfWeek.ToString().ToLower())) + Debug.Console(2, "[Scheduler] Current Date day of week: {0} recurrence days: {1}", eventTime.DayOfWeek, + config.Days); + + var dayOfWeekConverted = ConvertDayOfWeek(eventTime); + + Debug.Console(1, "[Scheduler] eventTime Day: {0}", dayOfWeekConverted); + + while (!dayOfWeekConverted.IsFlagSet(config.Days)) { eventTime = eventTime.AddDays(1); + + dayOfWeekConverted = ConvertDayOfWeek(eventTime); } scheduledEvent.DateAndTime.SetAbsoluteEventTime(eventTime); @@ -193,5 +206,28 @@ namespace PepperDash.Essentials.Core scheduledEvent.Disable(); } } + + private static ScheduledEventCommon.eWeekDays ConvertDayOfWeek(DateTime eventTime) + { + return (ScheduledEventCommon.eWeekDays) Enum.Parse(typeof(ScheduledEventCommon.eWeekDays), eventTime.DayOfWeek.ToString(), true); + } + + private static bool IsFlagSet(this T value, T flag) where T : struct + { + CheckIsEnum(true); + + var lValue = Convert.ToInt64(value); + var lFlag = Convert.ToInt64(flag); + + return (lValue & lFlag) != 0; + } + + private static void CheckIsEnum(bool withFlags) + { + if (!typeof(T).IsEnum) + throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName)); + if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute))) + throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName)); + } } } \ No newline at end of file From 91eec8c258cc7f1446676e8719e1594f375449e9 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 15 Dec 2020 16:43:09 -0700 Subject: [PATCH 43/59] fix scheduled event saving --- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index 3dc45c3a..acd44710 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -170,12 +170,16 @@ namespace PepperDash.Essentials { //update config based on key of scheduleEvent GetOrCreateScheduleGroup(); - var existingEvent = _config.ScheduledEvents.FirstOrDefault(e => e.Key == scheduledEvent.Key); + var existingEventIndex = _config.ScheduledEvents.FindIndex((e) => e.Key == scheduledEvent.Key); - if (existingEvent == null) + if (existingEventIndex < 0) { _config.ScheduledEvents.Add(scheduledEvent); } + else + { + _config.ScheduledEvents[existingEventIndex] = scheduledEvent; + } //create or update event based on config CreateOrUpdateSingleEvent(scheduledEvent); From 66cd39c0138b0d92b9030fd30b7b96c3b236a953 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 16 Dec 2020 16:21:10 -0700 Subject: [PATCH 44/59] changed event names and added saved event --- .../Room/Types/EssentialsTechRoom.cs | 4 +-- .../Presets/DevicePresets.cs | 28 ++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index acd44710..535cab22 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -36,7 +36,7 @@ namespace PepperDash.Essentials _tunerPresets.SetFileName(_config.PresetsFileName); - _tunerPresets.PresetChanged += TunerPresetsOnPresetChanged; + _tunerPresets.PresetRecalled += TunerPresetsOnPresetRecalled; _tuners = GetDevices(_config.Tuners); _displays = GetDevices(_config.Displays); @@ -78,7 +78,7 @@ namespace PepperDash.Essentials #endregion - private void TunerPresetsOnPresetChanged(ISetTopBoxNumericKeypad device, string channel) + private void TunerPresetsOnPresetRecalled(ISetTopBoxNumericKeypad device, string channel) { if (!_currentPresets.ContainsKey(device.Key)) { diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index 6fb228a4..d2724d77 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -16,12 +16,14 @@ namespace PepperDash.Essentials.Core.Presets /// public class DevicePresetsModel : Device { - public delegate void PresetChangedCallback(ISetTopBoxNumericKeypad device, string channel); + public delegate void PresetRecalledCallback(ISetTopBoxNumericKeypad device, string channel); + + public delegate void PresetsSavedCallback(List presets); private readonly CCriticalSection _fileOps = new CCriticalSection(); private readonly bool _initSuccess; - private ISetTopBoxNumericKeypad _setTopBox; + private readonly ISetTopBoxNumericKeypad _setTopBox; /// /// The methods on the STB device to call when dialing @@ -83,7 +85,8 @@ namespace PepperDash.Essentials.Core.Presets _initSuccess = true; } - public event PresetChangedCallback PresetChanged; + public event PresetRecalledCallback PresetRecalled; + public event PresetsSavedCallback PresetsSaved; public int PulseTime { get; set; } public int DigitSpacingMs { get; set; } @@ -188,7 +191,7 @@ namespace PepperDash.Essentials.Core.Presets if (_setTopBox == null) return; - OnPresetChanged(_setTopBox, chanNum); + OnPresetRecalled(_setTopBox, chanNum); } public void Dial(int presetNum, ISetTopBoxNumericKeypad setTopBox) @@ -218,14 +221,14 @@ namespace PepperDash.Essentials.Core.Presets _enterFunction = setTopBox.KeypadEnter; - OnPresetChanged(setTopBox, chanNum); + OnPresetRecalled(setTopBox, chanNum); Dial(chanNum); } - private void OnPresetChanged(ISetTopBoxNumericKeypad setTopBox, string channel) + private void OnPresetRecalled(ISetTopBoxNumericKeypad setTopBox, string channel) { - var handler = PresetChanged; + var handler = PresetRecalled; if (handler == null) { @@ -265,6 +268,8 @@ namespace PepperDash.Essentials.Core.Presets { file.Write(json, Encoding.UTF8); } + + } finally { @@ -273,6 +278,15 @@ namespace PepperDash.Essentials.Core.Presets } + private void OnPresetsSaved() + { + var handler = PresetsSaved; + + if (handler == null) return; + + handler(PresetsList); + } + private void Pulse(Action act) { act(true); From 695ff5487f4e5db7f45db1a01a295cfd56829a44 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Dec 2020 10:38:31 -0700 Subject: [PATCH 45/59] actually fire the PresetsSaved event --- .../PepperDashEssentialsBase/Presets/DevicePresets.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index d2724d77..85e5dfdb 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -248,6 +248,8 @@ namespace PepperDash.Essentials.Core.Presets PresetsList[index] = preset; SavePresets(); + + OnPresetsSaved(); } public void UpdatePresets(List presets) @@ -255,6 +257,8 @@ namespace PepperDash.Essentials.Core.Presets PresetsList = presets; SavePresets(); + + OnPresetsSaved(); } private void SavePresets() From 57ebd2b6086732e089e0eecab82ab4a6698dec0b Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 17 Dec 2020 14:07:48 -0700 Subject: [PATCH 46/59] Adds IRunDirectAction to EssentialsTechRoom --- .../Room/Types/EssentialsTechRoom.cs | 55 +- .../Room/Interfaces.cs | 8 + .../VideoCodec/ZoomRoom/ResponseObjects.cs | 2666 ++++++++--------- 3 files changed, 1394 insertions(+), 1335 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index 535cab22..515a4355 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -17,7 +17,7 @@ using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials { - public class EssentialsTechRoom : EssentialsRoomBase, ITvPresetsProvider, IBridgeAdvanced + public class EssentialsTechRoom : EssentialsRoomBase, ITvPresetsProvider, IBridgeAdvanced, IRunDirectRouteAction { private readonly EssentialsTechRoomConfig _config; private readonly Dictionary _displays; @@ -28,6 +28,8 @@ namespace PepperDash.Essentials private Dictionary _currentPresets; private ScheduledEventGroup _roomScheduledEventGroup; + private GenericSource DummySource = new GenericSource("$off", "Dummy Source"); + public EssentialsTechRoom(DeviceConfig config) : base(config) { _config = config.Properties.ToObject(); @@ -48,6 +50,8 @@ namespace PepperDash.Essentials SubscribeToDisplayFeedbacks(); CreateOrUpdateScheduledEvents(); + + DeviceManager.AddDevice(DummySource); } public Dictionary CurrentPresetsFeedbacks { get; private set; } @@ -241,7 +245,7 @@ namespace PepperDash.Essentials { foreach (var display in _displays) { - display.Value.PowerOn(); + } } @@ -373,6 +377,53 @@ namespace PepperDash.Essentials { } } + + #region IRunDirectRouteAction Members + + private void RunDirectRoute(IRoutingOutputs source, IRoutingSink dest) + { + if (dest == null) + { + Debug.Console(1, this, "Cannot route, unknown destination '{0}'", dest.Key); + return; + } + + if (source.Key.Equals("$off", StringComparison.OrdinalIgnoreCase)) + { + dest.ReleaseRoute(); + if (dest is IHasPowerControl) + (dest as IHasPowerControl).PowerOff(); + } + else + { + if (source == null) + { + Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", source.Key, dest.Key); + return; + } + dest.ReleaseAndMakeRoute(source, eRoutingSignalType.Video); + } + } + + /// + /// Attempts to route directly between a source and destination + /// + /// + /// + public void RunDirectRoute(string sourceKey, string destinationKey) + { + IRoutingSink dest = null; + + dest = DeviceManager.GetDeviceForKey(destinationKey) as IRoutingSink; + + var source = DeviceManager.GetDeviceForKey(sourceKey) as IRoutingOutputs; + + RunDirectRoute(source, dest); + } + + + + #endregion } public class ScheduledEventEventArgs : EventArgs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs index 1743bdaa..82871228 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs @@ -41,6 +41,14 @@ namespace PepperDash.Essentials.Core } + /// + /// Simplified routing direct from source to destination + /// + public interface IRunDirectRouteAction + { + void RunDirectRoute(string sourceKey, string destinationKey); + } + /// /// For rooms that default presentation only routing /// diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs index 3be18c1d..36cce89f 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs @@ -1,1335 +1,1335 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.ComponentModel; -using System.Runtime.CompilerServices; -using Crestron.SimplSharp; - -using PepperDash.Core; -using PepperDash.Essentials.Devices.Common.Codec; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; - -namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom -{ - public enum eZoomRoomResponseType - { - zEvent, - zStatus, - zConfiguration, - zCommand - } - - public abstract class NotifiableObject : INotifyPropertyChanged - { - #region INotifyPropertyChanged Members - - public event PropertyChangedEventHandler PropertyChanged; - - protected void NotifyPropertyChanged(string propertyName) - { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } - - #endregion - } - - /// - /// Used to track the current status of a ZoomRoom - /// - public class ZoomRoomStatus - { - public zStatus.Login Login { get; set; } - public zStatus.SystemUnit SystemUnit { get; set; } - public zStatus.Phonebook Phonebook { get; set; } - public zStatus.Call Call { get; set; } - public zStatus.Capabilities Capabilities { get; set; } - public zStatus.Sharing Sharing { get; set; } - public zStatus.NumberOfScreens NumberOfScreens { get; set; } - public zStatus.Layout Layout { get; set; } - public zStatus.Video Video { get; set; } - public zStatus.CameraShare CameraShare { get; set; } - public List AudioInputs { get; set; } - public List AudioOuputs { get; set; } - public List Cameras { get; set; } - public zEvent.PhoneCallStatus PhoneCall { get; set; } - - public ZoomRoomStatus() - { - Login = new zStatus.Login(); - SystemUnit = new zStatus.SystemUnit(); - Phonebook = new zStatus.Phonebook(); - Call = new zStatus.Call(); - Capabilities = new zStatus.Capabilities(); - Sharing = new zStatus.Sharing(); - NumberOfScreens = new zStatus.NumberOfScreens(); - Layout = new zStatus.Layout(); - Video = new zStatus.Video(); - CameraShare = new zStatus.CameraShare(); - AudioInputs = new List(); - AudioOuputs = new List(); - Cameras = new List(); - PhoneCall = new zEvent.PhoneCallStatus(); - } - } - - /// - /// Used to track the current configuration of a ZoomRoom - /// - public class ZoomRoomConfiguration - { - public zConfiguration.Call Call { get; set; } - public zConfiguration.Audio Audio { get; set; } - public zConfiguration.Video Video { get; set; } - public zConfiguration.Client Client { get; set; } - public zConfiguration.Camera Camera { get; set; } - - public ZoomRoomConfiguration() - { - Call = new zConfiguration.Call(); - Audio = new zConfiguration.Audio(); - Video = new zConfiguration.Video(); - Client = new zConfiguration.Client(); +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.ComponentModel; +using System.Runtime.CompilerServices; +using Crestron.SimplSharp; + +using PepperDash.Core; +using PepperDash.Essentials.Devices.Common.Codec; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom +{ + public enum eZoomRoomResponseType + { + zEvent, + zStatus, + zConfiguration, + zCommand + } + + public abstract class NotifiableObject : INotifyPropertyChanged + { + #region INotifyPropertyChanged Members + + public event PropertyChangedEventHandler PropertyChanged; + + protected void NotifyPropertyChanged(string propertyName) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + + #endregion + } + + /// + /// Used to track the current status of a ZoomRoom + /// + public class ZoomRoomStatus + { + public zStatus.Login Login { get; set; } + public zStatus.SystemUnit SystemUnit { get; set; } + public zStatus.Phonebook Phonebook { get; set; } + public zStatus.Call Call { get; set; } + public zStatus.Capabilities Capabilities { get; set; } + public zStatus.Sharing Sharing { get; set; } + public zStatus.NumberOfScreens NumberOfScreens { get; set; } + public zStatus.Layout Layout { get; set; } + public zStatus.Video Video { get; set; } + public zStatus.CameraShare CameraShare { get; set; } + public List AudioInputs { get; set; } + public List AudioOuputs { get; set; } + public List Cameras { get; set; } + public zEvent.PhoneCallStatus PhoneCall { get; set; } + + public ZoomRoomStatus() + { + Login = new zStatus.Login(); + SystemUnit = new zStatus.SystemUnit(); + Phonebook = new zStatus.Phonebook(); + Call = new zStatus.Call(); + Capabilities = new zStatus.Capabilities(); + Sharing = new zStatus.Sharing(); + NumberOfScreens = new zStatus.NumberOfScreens(); + Layout = new zStatus.Layout(); + Video = new zStatus.Video(); + CameraShare = new zStatus.CameraShare(); + AudioInputs = new List(); + AudioOuputs = new List(); + Cameras = new List(); + PhoneCall = new zEvent.PhoneCallStatus(); + } + } + + /// + /// Used to track the current configuration of a ZoomRoom + /// + public class ZoomRoomConfiguration + { + public zConfiguration.Call Call { get; set; } + public zConfiguration.Audio Audio { get; set; } + public zConfiguration.Video Video { get; set; } + public zConfiguration.Client Client { get; set; } + public zConfiguration.Camera Camera { get; set; } + + public ZoomRoomConfiguration() + { + Call = new zConfiguration.Call(); + Audio = new zConfiguration.Audio(); + Video = new zConfiguration.Video(); + Client = new zConfiguration.Client(); Camera = new zConfiguration.Camera(); - } - } - - /// - /// Represents a response from a ZoomRoom system - /// - public class Response - { - public Status Status { get; set; } - public bool Sync { get; set; } - [JsonProperty("topKey")] - public string TopKey { get; set; } - [JsonProperty("type")] - public string Type { get; set; } - - public Response() - { - Status = new Status(); - } - } - - public class Status - { - [JsonProperty("message")] - public string Message { get; set; } - [JsonProperty("state")] - public string State { get; set; } - } - - - /// - /// zStatus class stucture - /// - public class zStatus - { - public class Login - { - [JsonProperty("ZAAPI Release")] - public string ZAAPIRelease { get; set; } - [JsonProperty("Zoom Room Release")] - public string ZoomRoomRelease { get; set; } - } - - public class SystemUnit - { - [JsonProperty("email")] - public string Email { get; set; } - [JsonProperty("login_type")] - public string LoginType { get; set; } - [JsonProperty("meeting_number")] - public string MeetingNumber { get; set; } - [JsonProperty("platform")] - public string Platform { get; set; } - [JsonProperty("room_info")] - public RoomInfo RoomInfo { get; set; } - [JsonProperty("room_version")] - public string RoomVersion { get; set; } - - public SystemUnit() - { - RoomInfo = new RoomInfo(); - } - } - - public class RoomInfo - { - [JsonProperty("account_email")] - public string AccountEmail { get; set; } - [JsonProperty("display_version")] - public string DisplayVersion { get; set; } - [JsonProperty("is_auto_answer_enabled")] - public bool AutoAnswerIsEnabled { get; set; } - [JsonProperty("is_auto_answer_selected")] - public bool AutoAnswerIsSelected { get; set; } - [JsonProperty("room_name")] - public string RoomName { get; set; } - } - - public class CloudPbxInfo - { - [JsonProperty("company_number")] - public string CompanyNumber { get; set; } - [JsonProperty("extension")] - public string Extension { get; set; } - [JsonProperty("isValid")] - public bool IsValid { get; set; } - } - - public enum ePresence - { - PRESENCE_OFFLINE, - PRESENCE_ONLINE, - PRESENCE_AWAY, - PRESENCE_BUSY, - PRESENCE_DND - } - - public class Contact - { - [JsonProperty("avatarURL")] - public string AvatarURL { get; set; } - [JsonProperty("cloud_pbx_info")] - public CloudPbxInfo CloudPbxInfo { get; set; } - [JsonProperty("email")] - public string Email { get; set; } - [JsonProperty("firstName")] - public string FirstName { get; set; } - [JsonProperty("index")] - public int Index { get; set; } - [JsonProperty("isLegacy")] - public bool IsLegacy { get; set; } - [JsonProperty("isZoomRoom")] - public bool IsZoomRoom { get; set; } - [JsonProperty("jid")] - public string Jid { get; set; } - [JsonProperty("lastName")] - public string LastName { get; set; } - [JsonProperty("onDesktop")] - public bool OnDesktop { get; set; } - [JsonProperty("onMobile")] - public bool OnMobile { get; set; } - [JsonProperty("phoneNumber")] - public string PhoneNumber { get; set; } - [JsonProperty("presence")] - public ePresence Presence { get; set; } - [JsonProperty("presence_status")] - public int PresenceStatus { get; set; } - [JsonProperty("screenName")] - public string ScreenName { get; set; } - [JsonProperty("sip_phone_number")] - public string SipPhoneNumber { get; set; } - - - public Contact() - { - CloudPbxInfo = new CloudPbxInfo(); - } - } - - /// - /// Used to be able to inplement IInvitableContact on DirectoryContact - /// - public class ZoomDirectoryContact : DirectoryContact, IInvitableContact - { - - } - - public class Phonebook - { - [JsonProperty("Contacts")] - public List Contacts { get; set; } - - public Phonebook() - { - Contacts = new List(); - } - - /// - /// Converts from zStatus.Contact types to generic directory items - /// - /// - public static CodecDirectory ConvertZoomContactsToGeneric(List zoomContacts) - { - var directory = new CodecDirectory(); - - var folders = new List(); - - var roomFolder = new DirectoryFolder(); - - var contactFolder = new DirectoryFolder(); - - var contacts = new List(); - - // Check if there are any zoom rooms - var zoomRooms = zoomContacts.FindAll(c => c.IsZoomRoom); - - if (zoomRooms.Count > 0) - { - // If so, setup a rooms and contacts folder and add them. - roomFolder.Name = "Rooms"; - roomFolder.ParentFolderId = "root"; - roomFolder.FolderId = "rooms"; - - contactFolder.Name = "Contacts"; - contactFolder.ParentFolderId = "root"; - contactFolder.FolderId = "contacts"; - - folders.Add(roomFolder); - folders.Add(contactFolder); - - directory.AddFoldersToDirectory(folders); - } - - try - { - if (zoomContacts.Count == 0) return directory; - { - foreach (Contact c in zoomContacts) - { - var contact = new ZoomDirectoryContact {Name = c.ScreenName, ContactId = c.Jid}; - - if (folders.Count > 0) - { - contact.ParentFolderId = c.IsZoomRoom ? "rooms" : "contacts"; - } - - contacts.Add(contact); - } - - directory.AddContactsToDirectory(contacts); - } - } - catch (Exception e) - { - Debug.Console(1, "Error converting Zoom Phonebook results to generic: {0}", e); - } - - return directory; - } - } - - public enum eCallStatus - { - UNKNOWN, - NOT_IN_MEETING, - CONNECTING_MEETING, - IN_MEETING, - LOGGED_OUT - } - - public class ClosedCaption - { - public bool Available { get; set; } - } - - public class Call : NotifiableObject - { - private eCallStatus _status; - private List _participants; - - public bool IsInCall; - - public eCallStatus Status - { - get - { - return _status; - } - set - { - if (value != _status) - { - _status = value; - IsInCall = _status == eCallStatus.IN_MEETING || _status == eCallStatus.CONNECTING_MEETING; - NotifyPropertyChanged("Status"); - } - } - } - public ClosedCaption ClosedCaption { get; set; } - public List Participants - { - get - { - return _participants; - } - set - { - _participants = value; - NotifyPropertyChanged("Participants"); - } - } - public zEvent.SharingState Sharing { get; set; } - - public CallRecordInfo CallRecordInfo { get; set; } - - private zCommand.InfoResult _info; - - public zCommand.InfoResult Info - { - get - { - return _info; - } - set - { - _info = value; - NotifyPropertyChanged("Info"); - } - } - - public Call() - { - ClosedCaption = new ClosedCaption(); - Participants = new List(); - Sharing = new zEvent.SharingState(); - CallRecordInfo = new CallRecordInfo(); - Info = new zCommand.InfoResult(); - } - } - - public class Capabilities - { - public bool aec_Setting_Stored_In_ZR { get; set; } - public bool can_Dtmf_For_Invite_By_Phone { get; set; } - public bool can_Mute_On_Entry { get; set; } - public bool can_Ringing_In_Pstn_Call { get; set; } - public bool can_Switch_To_Specific_Camera { get; set; } - public bool is_Airhost_Disabled { get; set; } - public bool pstn_Call_In_Local_resentation { get; set; } - public bool support_Claim_Host { get; set; } - public bool support_Out_Room_Display { get; set; } - public bool support_Pin_And_Spotlight { get; set; } - public bool supports_Audio_Checkup { get; set; } - public bool supports_CheckIn { get; set; } - public bool supports_Cloud_PBX { get; set; } - public bool supports_Encrypted_Connection { get; set; } - public bool supports_Expel_User_Permanently { get; set; } - public bool supports_H323_DTMF { get; set; } - public bool supports_Hdmi_Cec_Control { get; set; } - public bool supports_Highly_Reverberant_Room { get; set; } - public bool supports_Loading_Contacts_Dynamically { get; set; } - public bool supports_Loading_Participants_Dynamically { get; set; } - public bool supports_Mic_Record_Test { get; set; } - public bool supports_Multi_Share { get; set; } - public bool supports_ShareCamera { get; set; } - public bool supports_Share_For_Floating_And_Content_Only { get; set; } - public bool supports_Sip_Call_out { get; set; } - public bool supports_Software_Audio_Processing { get; set; } - public bool supports_Web_Settings_Push { get; set; } - } - - public class Sharing : NotifiableObject - { - private string _dispState; - private string _password; - - public string directPresentationPairingCode { get; set; } - /// - /// Laptop client sharing key - /// - public string directPresentationSharingKey { get; set; } - public string dispState - { - get - { - return _dispState; - } - set - { - if (value != _dispState) - { - _dispState = value; - NotifyPropertyChanged("dispState"); - } - } - } - public bool isAirHostClientConnected { get; set; } - public bool isBlackMagicConnected { get; set; } - public bool isBlackMagicDataAvailable { get; set; } - public bool isDirectPresentationConnected { get; set; } - public bool isSharingBlackMagic { get; set; } - /// - /// IOS Airplay code - /// - public string password - { - get - { - return _password; - } - set - { - if (value != _password) - { - _password = value; - NotifyPropertyChanged("password"); - } - } - } - public string serverName { get; set; } - public string wifiName { get; set; } - } - - public class NumberOfScreens - { - [JsonProperty("NumberOfCECScreens")] - public int NumOfCECScreens { get; set; } - [JsonProperty("NumberOfScreens")] - public int NumOfScreens { get; set; } - } - - /// - /// AudioInputLine/AudioOutputLine/VideoCameraLine list item - /// - public class AudioVideoInputOutputLineItem - { - public string Alias { get; set; } - public string Name { get; set; } - public bool Selected { get; set; } - public bool combinedDevice { get; set; } - public string id { get; set; } - public bool manuallySelected { get; set; } - public int numberOfCombinedDevices { get; set; } - public int ptzComId { get; set; } - } - - public class Video - { - public bool Optimizable { get; set; } - } - - public class CameraShare : NotifiableObject - { - private bool _canControlCamera; - private bool _isSharing; - - [JsonProperty("can_Control_Camera")] - public bool CanControlCamera - { - get - { - return _canControlCamera; - } - set - { - if (value != _canControlCamera) - { - _canControlCamera = value; - NotifyPropertyChanged("CanControlCamera"); - } - } - } - public string id { get; set; } - public bool is_Mirrored { get; set; } - [JsonProperty("is_Sharing")] - public bool IsSharing - { - get - { - return _isSharing; - } - set - { - if (value != _isSharing) - { - _isSharing = value; - NotifyPropertyChanged("IsSharing"); - } - } - } - public int pan_Tilt_Speed { get; set; } - - } - - public class Layout - { - public bool can_Adjust_Floating_Video { get; set; } - public bool can_Switch_Floating_Share_Content { get; set; } - public bool can_Switch_Share_On_All_Screens { get; set; } - public bool can_Switch_Speaker_View { get; set; } - public bool can_Switch_Wall_View { get; set; } - public bool is_In_First_Page { get; set; } - public bool is_In_Last_Page { get; set; } - public bool is_supported { get; set; } - public int video_Count_In_Current_Page { get; set; } - public string video_type { get; set; } - } - - public class CallRecordInfo - { - public bool canRecord { get; set; } - public bool emailRequired { get; set; } - public bool amIRecording { get; set; } - public bool meetingIsBeingRecorded { get; set; } - } - } - - /// - /// zEvent Class Structure - /// - public class zEvent - { - public class NeedWaitForHost - { - public bool Wait { get; set; } - } - - public class IncomingCallIndication - { - public string callerJID { get; set; } - public string calleeJID { get; set; } - public string meetingID { get; set; } - public string password { get; set; } - public string meetingOption { get; set; } - public long MeetingNumber { get; set; } - public string callerName { get; set; } - public string avatarURL { get; set; } - public int lifeTime { get; set; } - public bool accepted { get; set; } - } - - public class CallConnectError - { - public int error_code { get; set; } - public string error_message { get; set; } - } - - public class CallDisconnect - { - public bool Successful - { - get - { - return success == "on"; - } - } - - public string success { get; set; } - } - - public class Layout - { - public bool Sharethumb { get; set; } - } - - public class Call - { - public Layout Layout { get; set; } - } - - public class Client - { - public Call Call { get; set; } - } - - public enum eSharingState - { - None, - Connecting, - Sending, - Receiving, - Send_Receiving - } - - public class SharingState : NotifiableObject - { - private bool _paused; - private eSharingState _state; - - public bool IsSharing; - - [JsonProperty("paused")] - public bool Paused - { - get - { - return _paused; - } - set - { - if (value != _paused) - { - _paused = value; - NotifyPropertyChanged("Paused"); - } - } - } - [JsonProperty("state")] - public eSharingState State - { - get - { - return _state; - } - set - { - if (value != _state) - { - _state = value; - IsSharing = _state == eSharingState.Sending; - NotifyPropertyChanged("State"); - } - } - } - } - - public class PinStatusOfScreenNotification - { - [JsonProperty("can_be_pinned")] - public bool CanBePinned { get; set; } - [JsonProperty("can_pin_share")] - public bool CanPinShare { get; set; } - [JsonProperty("pinned_share_source_id")] - public int PinnedShareSourceId { get; set; } - [JsonProperty("pinned_user_id")] - public int PinnedUserId { get; set; } - [JsonProperty("screen_index")] - public int ScreenIndex { get; set; } - [JsonProperty("screen_layout")] - public int ScreenLayout { get; set; } - [JsonProperty("share_source_type")] - public int ShareSourceType { get; set; } - [JsonProperty("why_cannot_pin_share")] - public string WhyCannotPinShare { get; set; } - } - - public class PhoneCallStatus:NotifiableObject - { - private bool _isIncomingCall; - private string _peerDisplayName; - private string _peerNumber; - - private bool _offHook; - - public string CallId { get; set; } - public bool IsIncomingCall { - get { return _isIncomingCall; } - set - { - if(value == _isIncomingCall) return; - - _isIncomingCall = value; - NotifyPropertyChanged("IsIncomingCall"); - } } - - public string PeerDisplayName - { - get { return _peerDisplayName; } - set - { - if (value == _peerDisplayName) return; - _peerDisplayName = value; - NotifyPropertyChanged("PeerDisplayName"); - } - } - - public string PeerNumber - { - get { return _peerNumber; } - set - { - if (value == _peerNumber) return; - - _peerNumber = value; - NotifyPropertyChanged("PeerNumber"); - } - } - - public string PeerUri { get; set; } - - private ePhoneCallStatus _status; - public ePhoneCallStatus Status - { - get { return _status; } - set - { - _status = value; - OffHook = _status == ePhoneCallStatus.PhoneCallStatus_Accepted || - _status == ePhoneCallStatus.PhoneCallStatus_InCall || - _status == ePhoneCallStatus.PhoneCallStatus_Init || - _status == ePhoneCallStatus.PhoneCallStatus_Ringing; - } - } - - public bool OffHook - { - get { return _offHook; } - set - { - if (value == _offHook) return; - - _offHook = value; - NotifyPropertyChanged("OffHook"); - } - } - } - - public enum ePhoneCallStatus - { - PhoneCallStatus_Ringing, - PhoneCallStatus_Terminated, - PhoneCallStatus_Accepted, - PhoneCallStatus_InCall, - PhoneCallStatus_Init, - } - } - - /// - /// zConfiguration class structure - /// - public class zConfiguration - { - public class Sharing - { - [JsonProperty("optimize_video_sharing")] - public bool OptimizeVideoSharing { get; set; } - } - - public class Camera : NotifiableObject - { - private bool _mute; - - public bool Mute - { - get { return _mute; } - set - { - Debug.Console(1, "Camera Mute response received: {0}", value); - - if (value == _mute) return; - - _mute = value; - NotifyPropertyChanged("Mute"); - } - } - } - - public class Microphone : NotifiableObject - { - private bool _mute; - - public bool Mute - { - get - { - return _mute; - } - set - { - if(value != _mute) - { - _mute = value; - NotifyPropertyChanged("Mute"); - } - } - } - } - - public enum eLayoutStyle - { - Gallery, - Speaker, - Strip, - ShareAll - } - - public enum eLayoutSize - { - Off, - Size1, - Size2, - Size3, - Strip - } - - public enum eLayoutPosition - { - Center, - Up, - Right, - UpRight, - Down, - DownRight, - Left, - UpLeft, - DownLeft - } - - public class Layout:NotifiableObject - { - public bool ShareThumb { get; set; } - public eLayoutStyle Style { get; set; } - public eLayoutSize Size { get; set; } - - private eLayoutPosition _position; - public eLayoutPosition Position { - get { return _position; } - set - { - _position = value; - NotifyPropertyChanged("Position"); - } } - } - - public class Lock - { - public bool Enable { get; set; } - } - - public class ClosedCaption - { - public bool Visible { get; set; } - public int FontSize { get; set; } - } - - public class MuteUserOnEntry - { - public bool Enable { get; set; } - } - - public class Call - { - public Sharing Sharing { get; set; } - public Camera Camera { get; set; } - public Microphone Microphone { get; set; } - public Layout Layout { get; set; } - public Lock Lock { get; set; } - public MuteUserOnEntry MuteUserOnEntry { get; set; } - public ClosedCaption ClosedCaption { get; set; } - - - public Call() - { - Sharing = new Sharing(); - Camera = new Camera(); - Microphone = new Microphone(); - Layout = new Layout(); - Lock = new Lock(); - MuteUserOnEntry = new MuteUserOnEntry(); - ClosedCaption = new ClosedCaption(); - } - } - - public class Audio - { - public Input Input { get; set; } - public Output Output { get; set; } - - public Audio() - { - Input = new Input(); - Output = new Output(); - } - } - - public class Input : Output - { - [JsonProperty("reduce_reverb")] - public bool ReduceReverb { get; set; } - } - - public class Output : NotifiableObject - { - private int _volume; - - [JsonProperty("volume")] - public int Volume - { - get - { - return _volume; - } - set - { - if (value != _volume) - { - _volume = value; - NotifyPropertyChanged("Volume"); - } - } - } - [JsonProperty("selectedId")] - public string SelectedId { get; set; } - [JsonProperty("is_sap_disabled")] - public bool IsSapDisabled { get; set; } - } - - public class Video : NotifiableObject - { - private bool _hideConfSelfVideo; - - [JsonProperty("hide_conf_self_video")] - public bool HideConfSelfVideo - { - get - { - return _hideConfSelfVideo; - } - set - { - if (value != _hideConfSelfVideo) - { - _hideConfSelfVideo = value; - NotifyPropertyChanged("HideConfSelfVideo"); - } - } - } - - public VideoCamera Camera { get; set; } - - public Video() - { - Camera = new VideoCamera(); - } - } - - public class VideoCamera : NotifiableObject - { - private string _selectedId; - - [JsonProperty("selectedId")] - public string SelectedId { - get - { - return _selectedId; - } - set - { - if (value != _selectedId) - { - _selectedId = value; - NotifyPropertyChanged("SelectedId"); - } - } - - } - public bool Mirror { get; set; } - } - - public class Client - { - public string appVersion { get; set; } - public string deviceSystem { get; set; } - } - - } - - /// - /// zCommand class structure - /// - public class zCommand - { - public class BookingsListResult - { - [JsonProperty("accessRole")] - public string AccessRole { get; set; } - [JsonProperty("calendarChangeKey")] - public string CalendarChangeKey { get; set; } - [JsonProperty("calendarID")] - public string CalendarId { get; set; } - [JsonProperty("checkIn")] - public bool CheckIn { get; set; } - [JsonProperty("creatorEmail")] - public string CreatorEmail { get; set; } - [JsonProperty("creatorName")] - public string CreatorName { get; set; } - [JsonProperty("endTime")] - public DateTime EndTime { get; set; } - [JsonProperty("hostName")] - public string HostName { get; set; } - [JsonProperty("isInstantMeeting")] - public bool IsInstantMeeting { get; set; } - [JsonProperty("isPrivate")] - public bool IsPrivate { get; set; } - [JsonProperty("location")] - public string Location { get; set; } - [JsonProperty("meetingName")] - public string MeetingName { get; set; } - [JsonProperty("meetingNumber")] - public string MeetingNumber { get; set; } - [JsonProperty("scheduledFrom")] - public string ScheduledFrom { get; set; } - [JsonProperty("startTime")] - public DateTime StartTime { get; set; } - [JsonProperty("third_party")] - public ThirdParty ThirdParty { get; set; } - } - - public static List GetGenericMeetingsFromBookingResult(List bookings, - int minutesBeforeMeetingStart) - { - var rv = GetGenericMeetingsFromBookingResult(bookings); - - foreach (var meeting in rv) - { - meeting.MinutesBeforeMeeting = minutesBeforeMeetingStart; - } - - return rv; - } - /// - /// Extracts the necessary meeting values from the Zoom bookings response and converts them to the generic class - /// - /// - /// - public static List GetGenericMeetingsFromBookingResult(List bookings) - { - var meetings = new List(); - - if (Debug.Level > 0) - { - Debug.Console(1, "Meetings List:\n"); - } - - foreach (var b in bookings) - { - var meeting = new Meeting(); - - if (b.MeetingNumber != null) - meeting.Id = b.MeetingNumber; - if (b.CreatorName != null) - meeting.Organizer = b.CreatorName; - if (b.MeetingName != null) - meeting.Title = b.MeetingName; - //if (b.Agenda != null) - // meeting.Agenda = b.Agenda.Value; - if (b.StartTime != null) - meeting.StartTime = b.StartTime; - if (b.EndTime != null) - meeting.EndTime = b.EndTime; - - meeting.Privacy = b.IsPrivate ? eMeetingPrivacy.Private : eMeetingPrivacy.Public; - - // No meeting.Calls data exists for Zoom Rooms. Leaving out for now. - var now = DateTime.Now; - if (meeting.StartTime < now && meeting.EndTime < now) - { - Debug.Console(1, "Skipping meeting {0}. Meeting is in the past.", meeting.Title); - continue; - } - - meetings.Add(meeting); - - if (Debug.Level > 0) - { - Debug.Console(1, "Title: {0}, ID: {1}, Organizer: {2}", meeting.Title, meeting.Id, meeting.Organizer); - Debug.Console(1, " Start Time: {0}, End Time: {1}, Duration: {2}", meeting.StartTime, meeting.EndTime, meeting.Duration); - Debug.Console(1, " Joinable: {0}\n", meeting.Joinable); - } - } - - meetings.OrderBy(m => m.StartTime); - - return meetings; - } - - public class HandStatus - { - [JsonProperty("is_raise_hand")] - public bool IsRaiseHand { get; set; } - [JsonProperty("optimize_vis_validideo_sharing")] - public string IsValid { get; set; } - [JsonProperty("time_stamp")] - public string TimeStamp { get; set; } - } - - public class ListParticipant - { - [JsonProperty("audio_status state")] - public string AudioStatusState { get; set; } - [JsonProperty("audio_status type")] - public string AudioStatusType { get; set; } - [JsonProperty("avatar_url")] - public string AvatarUrl { get; set; } - [JsonProperty("camera_status am_i_controlling")] - public bool CameraStatusAmIControlling { get; set; } - [JsonProperty("camera_status can_i_request_control")] - public bool CameraStatusCanIRequestConrol { get; set; } - [JsonProperty("camera_status can_move_camera")] - public bool CameraStatusCanMoveCamera { get; set; } - [JsonProperty("camera_status can_switch_camera")] - public bool CameraStatusCanSwitchCamera { get; set; } - [JsonProperty("camera_status can_zoom_camera")] - public bool CameraStatusCanZoomCamera { get; set; } - [JsonProperty("can_edit_closed_caption")] - public bool CanEditClosedCaption { get; set; } - [JsonProperty("can_record")] - public bool CanRecord { get; set; } - [JsonProperty("event")] - public string Event { get; set; } - [JsonProperty("hand_status")] - public HandStatus HandStatus { get; set; } - [JsonProperty("isCohost")] - public bool IsCohost { get; set; } - [JsonProperty("is_client_support_closed_caption")] - public bool IsClientSupportClosedCaption { get; set; } - [JsonProperty("is_client_support_coHost")] - public bool IsClientSupportCoHost { get; set; } - [JsonProperty("is_host")] - public bool IsHost { get; set; } - [JsonProperty("is_myself")] - public bool IsMyself { get; set; } - [JsonProperty("is_recording")] - public bool IsRecording { get; set; } - [JsonProperty("is_video_can_mute_byHost")] - public bool IsVideoCanMuteByHost { get; set; } - [JsonProperty("is_video_can_unmute_byHost")] - public bool IsVideoCanUnmuteByHost { get; set; } - [JsonProperty("local_recording_disabled")] - public bool LocalRecordingDisabled { get; set; } - [JsonProperty("user_id")] - public int UserId { get; set; } - [JsonProperty("user_name")] - public string UserName { get; set; } - [JsonProperty("user_type")] - public string UserType { get; set; } - [JsonProperty("video_status has_source")] - public bool VideoStatusHasSource { get; set; } - [JsonProperty("video_status is_receiving")] - public bool VideoStatusIsReceiving { get; set; } - [JsonProperty("video_status is_sending")] - public bool VideoStatusIsSending { get; set; } - - public ListParticipant() - { - HandStatus = new HandStatus(); - } - - public static List GetGenericParticipantListFromParticipantsResult( - List participants) - { - return - participants.Select( - p => - new Participant - { - Name = p.UserName, - IsHost = p.IsHost, - CanMuteVideo = p.IsVideoCanMuteByHost, - CanUnmuteVideo = p.IsVideoCanUnmuteByHost, - AudioMuteFb = p.AudioStatusState == "AUDIO_MUTED", - VideoMuteFb = p.VideoStatusIsSending - }).ToList(); - } - } - - public class CallinCountryList - { - public int code { get; set; } - public string display_number { get; set; } - public string id { get; set; } - public string name { get; set; } - public string number { get; set; } - } - - public class CalloutCountryList - { - public int code { get; set; } - public string display_number { get; set; } - public string id { get; set; } - public string name { get; set; } - public string number { get; set; } - } - - public class TollFreeCallinList - { - public int code { get; set; } - public string display_number { get; set; } - public string id { get; set; } - public string name { get; set; } - public string number { get; set; } - } - - public class Info - { - public List callin_country_list { get; set; } - public List callout_country_list { get; set; } - public List toll_free_callin_list { get; set; } - } - - public class ThirdParty - { - public string h323_address { get; set; } - public string meeting_number { get; set; } - public string service_provider { get; set; } - public string sip_address { get; set; } - } - - public class MeetingListItem - { - public string accessRole { get; set; } - public string calendarChangeKey { get; set; } - public string calendarID { get; set; } - public bool checkIn { get; set; } - public string creatorEmail { get; set; } - public string creatorName { get; set; } - public string endTime { get; set; } - public string hostName { get; set; } - public bool isInstantMeeting { get; set; } - public bool isPrivate { get; set; } - public string location { get; set; } - public string meetingName { get; set; } - public string meetingNumber { get; set; } - public string scheduledFrom { get; set; } - public string startTime { get; set; } - public ThirdParty third_party { get; set; } - - public MeetingListItem() - { - third_party = new ThirdParty(); - } - } - - public class InfoResult - { - public Info Info { get; set; } - public bool am_i_original_host { get; set; } - public string default_callin_country { get; set; } - public string dialIn { get; set; } - public string international_url { get; set; } - public string invite_email_content { get; set; } - public string invite_email_subject { get; set; } - public bool is_callin_country_list_available { get; set; } - public bool is_calling_room_system_enabled { get; set; } - public bool is_toll_free_callin_list_available { get; set; } - public bool is_view_only { get; set; } - public bool is_waiting_room { get; set; } - public bool is_webinar { get; set; } - public string meeting_id { get; set; } - public MeetingListItem meeting_list_item { get; set; } - public string meeting_password { get; set; } - public string meeting_type { get; set; } - public int my_userid { get; set; } - public int participant_id { get; set; } - public string real_meeting_id { get; set; } - public string schedule_option { get; set; } - public string schedule_option2 { get; set; } - public string support_callout_type { get; set; } - public string toll_free_number { get; set; } - public string user_type { get; set; } - - public InfoResult() - { - Info = new Info(); - meeting_list_item = new MeetingListItem(); - } - } - - public class Phonebook - { - public List Contacts { get; set; } - public int Limit { get; set; } - public int Offset { get; set; } - } - } + } + } + + /// + /// Represents a response from a ZoomRoom system + /// + public class Response + { + public Status Status { get; set; } + public bool Sync { get; set; } + [JsonProperty("topKey")] + public string TopKey { get; set; } + [JsonProperty("type")] + public string Type { get; set; } + + public Response() + { + Status = new Status(); + } + } + + public class Status + { + [JsonProperty("message")] + public string Message { get; set; } + [JsonProperty("state")] + public string State { get; set; } + } + + + /// + /// zStatus class stucture + /// + public class zStatus + { + public class Login + { + [JsonProperty("ZAAPI Release")] + public string ZAAPIRelease { get; set; } + [JsonProperty("Zoom Room Release")] + public string ZoomRoomRelease { get; set; } + } + + public class SystemUnit + { + [JsonProperty("email")] + public string Email { get; set; } + [JsonProperty("login_type")] + public string LoginType { get; set; } + [JsonProperty("meeting_number")] + public string MeetingNumber { get; set; } + [JsonProperty("platform")] + public string Platform { get; set; } + [JsonProperty("room_info")] + public RoomInfo RoomInfo { get; set; } + [JsonProperty("room_version")] + public string RoomVersion { get; set; } + + public SystemUnit() + { + RoomInfo = new RoomInfo(); + } + } + + public class RoomInfo + { + [JsonProperty("account_email")] + public string AccountEmail { get; set; } + [JsonProperty("display_version")] + public string DisplayVersion { get; set; } + [JsonProperty("is_auto_answer_enabled")] + public bool AutoAnswerIsEnabled { get; set; } + [JsonProperty("is_auto_answer_selected")] + public bool AutoAnswerIsSelected { get; set; } + [JsonProperty("room_name")] + public string RoomName { get; set; } + } + + public class CloudPbxInfo + { + [JsonProperty("company_number")] + public string CompanyNumber { get; set; } + [JsonProperty("extension")] + public string Extension { get; set; } + [JsonProperty("isValid")] + public bool IsValid { get; set; } + } + + public enum ePresence + { + PRESENCE_OFFLINE, + PRESENCE_ONLINE, + PRESENCE_AWAY, + PRESENCE_BUSY, + PRESENCE_DND + } + + public class Contact + { + [JsonProperty("avatarURL")] + public string AvatarURL { get; set; } + [JsonProperty("cloud_pbx_info")] + public CloudPbxInfo CloudPbxInfo { get; set; } + [JsonProperty("email")] + public string Email { get; set; } + [JsonProperty("firstName")] + public string FirstName { get; set; } + [JsonProperty("index")] + public int Index { get; set; } + [JsonProperty("isLegacy")] + public bool IsLegacy { get; set; } + [JsonProperty("isZoomRoom")] + public bool IsZoomRoom { get; set; } + [JsonProperty("jid")] + public string Jid { get; set; } + [JsonProperty("lastName")] + public string LastName { get; set; } + [JsonProperty("onDesktop")] + public bool OnDesktop { get; set; } + [JsonProperty("onMobile")] + public bool OnMobile { get; set; } + [JsonProperty("phoneNumber")] + public string PhoneNumber { get; set; } + [JsonProperty("presence")] + public ePresence Presence { get; set; } + [JsonProperty("presence_status")] + public int PresenceStatus { get; set; } + [JsonProperty("screenName")] + public string ScreenName { get; set; } + [JsonProperty("sip_phone_number")] + public string SipPhoneNumber { get; set; } + + + public Contact() + { + CloudPbxInfo = new CloudPbxInfo(); + } + } + + /// + /// Used to be able to inplement IInvitableContact on DirectoryContact + /// + public class ZoomDirectoryContact : DirectoryContact, IInvitableContact + { + + } + + public class Phonebook + { + [JsonProperty("Contacts")] + public List Contacts { get; set; } + + public Phonebook() + { + Contacts = new List(); + } + + /// + /// Converts from zStatus.Contact types to generic directory items + /// + /// + public static CodecDirectory ConvertZoomContactsToGeneric(List zoomContacts) + { + var directory = new CodecDirectory(); + + var folders = new List(); + + var roomFolder = new DirectoryFolder(); + + var contactFolder = new DirectoryFolder(); + + var contacts = new List(); + + // Check if there are any zoom rooms + var zoomRooms = zoomContacts.FindAll(c => c.IsZoomRoom); + + if (zoomRooms.Count > 0) + { + // If so, setup a rooms and contacts folder and add them. + roomFolder.Name = "Rooms"; + roomFolder.ParentFolderId = "root"; + roomFolder.FolderId = "rooms"; + + contactFolder.Name = "Contacts"; + contactFolder.ParentFolderId = "root"; + contactFolder.FolderId = "contacts"; + + folders.Add(roomFolder); + folders.Add(contactFolder); + + directory.AddFoldersToDirectory(folders); + } + + try + { + if (zoomContacts.Count == 0) return directory; + { + foreach (Contact c in zoomContacts) + { + var contact = new ZoomDirectoryContact {Name = c.ScreenName, ContactId = c.Jid}; + + if (folders.Count > 0) + { + contact.ParentFolderId = c.IsZoomRoom ? "rooms" : "contacts"; + } + + contacts.Add(contact); + } + + directory.AddContactsToDirectory(contacts); + } + } + catch (Exception e) + { + Debug.Console(1, "Error converting Zoom Phonebook results to generic: {0}", e); + } + + return directory; + } + } + + public enum eCallStatus + { + UNKNOWN, + NOT_IN_MEETING, + CONNECTING_MEETING, + IN_MEETING, + LOGGED_OUT + } + + public class ClosedCaption + { + public bool Available { get; set; } + } + + public class Call : NotifiableObject + { + private eCallStatus _status; + private List _participants; + + public bool IsInCall; + + public eCallStatus Status + { + get + { + return _status; + } + set + { + if (value != _status) + { + _status = value; + IsInCall = _status == eCallStatus.IN_MEETING || _status == eCallStatus.CONNECTING_MEETING; + NotifyPropertyChanged("Status"); + } + } + } + public ClosedCaption ClosedCaption { get; set; } + public List Participants + { + get + { + return _participants; + } + set + { + _participants = value; + NotifyPropertyChanged("Participants"); + } + } + public zEvent.SharingState Sharing { get; set; } + + public CallRecordInfo CallRecordInfo { get; set; } + + private zCommand.InfoResult _info; + + public zCommand.InfoResult Info + { + get + { + return _info; + } + set + { + _info = value; + NotifyPropertyChanged("Info"); + } + } + + public Call() + { + ClosedCaption = new ClosedCaption(); + Participants = new List(); + Sharing = new zEvent.SharingState(); + CallRecordInfo = new CallRecordInfo(); + Info = new zCommand.InfoResult(); + } + } + + public class Capabilities + { + public bool aec_Setting_Stored_In_ZR { get; set; } + public bool can_Dtmf_For_Invite_By_Phone { get; set; } + public bool can_Mute_On_Entry { get; set; } + public bool can_Ringing_In_Pstn_Call { get; set; } + public bool can_Switch_To_Specific_Camera { get; set; } + public bool is_Airhost_Disabled { get; set; } + public bool pstn_Call_In_Local_resentation { get; set; } + public bool support_Claim_Host { get; set; } + public bool support_Out_Room_Display { get; set; } + public bool support_Pin_And_Spotlight { get; set; } + public bool supports_Audio_Checkup { get; set; } + public bool supports_CheckIn { get; set; } + public bool supports_Cloud_PBX { get; set; } + public bool supports_Encrypted_Connection { get; set; } + public bool supports_Expel_User_Permanently { get; set; } + public bool supports_H323_DTMF { get; set; } + public bool supports_Hdmi_Cec_Control { get; set; } + public bool supports_Highly_Reverberant_Room { get; set; } + public bool supports_Loading_Contacts_Dynamically { get; set; } + public bool supports_Loading_Participants_Dynamically { get; set; } + public bool supports_Mic_Record_Test { get; set; } + public bool supports_Multi_Share { get; set; } + public bool supports_ShareCamera { get; set; } + public bool supports_Share_For_Floating_And_Content_Only { get; set; } + public bool supports_Sip_Call_out { get; set; } + public bool supports_Software_Audio_Processing { get; set; } + public bool supports_Web_Settings_Push { get; set; } + } + + public class Sharing : NotifiableObject + { + private string _dispState; + private string _password; + + public string directPresentationPairingCode { get; set; } + /// + /// Laptop client sharing key + /// + public string directPresentationSharingKey { get; set; } + public string dispState + { + get + { + return _dispState; + } + set + { + if (value != _dispState) + { + _dispState = value; + NotifyPropertyChanged("dispState"); + } + } + } + public bool isAirHostClientConnected { get; set; } + public bool isBlackMagicConnected { get; set; } + public bool isBlackMagicDataAvailable { get; set; } + public bool isDirectPresentationConnected { get; set; } + public bool isSharingBlackMagic { get; set; } + /// + /// IOS Airplay code + /// + public string password + { + get + { + return _password; + } + set + { + if (value != _password) + { + _password = value; + NotifyPropertyChanged("password"); + } + } + } + public string serverName { get; set; } + public string wifiName { get; set; } + } + + public class NumberOfScreens + { + [JsonProperty("NumberOfCECScreens")] + public int NumOfCECScreens { get; set; } + [JsonProperty("NumberOfScreens")] + public int NumOfScreens { get; set; } + } + + /// + /// AudioInputLine/AudioOutputLine/VideoCameraLine list item + /// + public class AudioVideoInputOutputLineItem + { + public string Alias { get; set; } + public string Name { get; set; } + public bool Selected { get; set; } + public bool combinedDevice { get; set; } + public string id { get; set; } + public bool manuallySelected { get; set; } + public int numberOfCombinedDevices { get; set; } + public int ptzComId { get; set; } + } + + public class Video + { + public bool Optimizable { get; set; } + } + + public class CameraShare : NotifiableObject + { + private bool _canControlCamera; + private bool _isSharing; + + [JsonProperty("can_Control_Camera")] + public bool CanControlCamera + { + get + { + return _canControlCamera; + } + set + { + if (value != _canControlCamera) + { + _canControlCamera = value; + NotifyPropertyChanged("CanControlCamera"); + } + } + } + public string id { get; set; } + public bool is_Mirrored { get; set; } + [JsonProperty("is_Sharing")] + public bool IsSharing + { + get + { + return _isSharing; + } + set + { + if (value != _isSharing) + { + _isSharing = value; + NotifyPropertyChanged("IsSharing"); + } + } + } + public int pan_Tilt_Speed { get; set; } + + } + + public class Layout + { + public bool can_Adjust_Floating_Video { get; set; } + public bool can_Switch_Floating_Share_Content { get; set; } + public bool can_Switch_Share_On_All_Screens { get; set; } + public bool can_Switch_Speaker_View { get; set; } + public bool can_Switch_Wall_View { get; set; } + public bool is_In_First_Page { get; set; } + public bool is_In_Last_Page { get; set; } + public bool is_supported { get; set; } + public int video_Count_In_Current_Page { get; set; } + public string video_type { get; set; } + } + + public class CallRecordInfo + { + public bool canRecord { get; set; } + public bool emailRequired { get; set; } + public bool amIRecording { get; set; } + public bool meetingIsBeingRecorded { get; set; } + } + } + + /// + /// zEvent Class Structure + /// + public class zEvent + { + public class NeedWaitForHost + { + public bool Wait { get; set; } + } + + public class IncomingCallIndication + { + public string callerJID { get; set; } + public string calleeJID { get; set; } + public string meetingID { get; set; } + public string password { get; set; } + public string meetingOption { get; set; } + public long MeetingNumber { get; set; } + public string callerName { get; set; } + public string avatarURL { get; set; } + public int lifeTime { get; set; } + public bool accepted { get; set; } + } + + public class CallConnectError + { + public int error_code { get; set; } + public string error_message { get; set; } + } + + public class CallDisconnect + { + public bool Successful + { + get + { + return success == "on"; + } + } + + public string success { get; set; } + } + + public class Layout + { + public bool Sharethumb { get; set; } + } + + public class Call + { + public Layout Layout { get; set; } + } + + public class Client + { + public Call Call { get; set; } + } + + public enum eSharingState + { + None, + Connecting, + Sending, + Receiving, + Send_Receiving + } + + public class SharingState : NotifiableObject + { + private bool _paused; + private eSharingState _state; + + public bool IsSharing; + + [JsonProperty("paused")] + public bool Paused + { + get + { + return _paused; + } + set + { + if (value != _paused) + { + _paused = value; + NotifyPropertyChanged("Paused"); + } + } + } + [JsonProperty("state")] + public eSharingState State + { + get + { + return _state; + } + set + { + if (value != _state) + { + _state = value; + IsSharing = _state == eSharingState.Sending; + NotifyPropertyChanged("State"); + } + } + } + } + + public class PinStatusOfScreenNotification + { + [JsonProperty("can_be_pinned")] + public bool CanBePinned { get; set; } + [JsonProperty("can_pin_share")] + public bool CanPinShare { get; set; } + [JsonProperty("pinned_share_source_id")] + public int PinnedShareSourceId { get; set; } + [JsonProperty("pinned_user_id")] + public int PinnedUserId { get; set; } + [JsonProperty("screen_index")] + public int ScreenIndex { get; set; } + [JsonProperty("screen_layout")] + public int ScreenLayout { get; set; } + [JsonProperty("share_source_type")] + public int ShareSourceType { get; set; } + [JsonProperty("why_cannot_pin_share")] + public string WhyCannotPinShare { get; set; } + } + + public class PhoneCallStatus:NotifiableObject + { + private bool _isIncomingCall; + private string _peerDisplayName; + private string _peerNumber; + + private bool _offHook; + + public string CallId { get; set; } + public bool IsIncomingCall { + get { return _isIncomingCall; } + set + { + if(value == _isIncomingCall) return; + + _isIncomingCall = value; + NotifyPropertyChanged("IsIncomingCall"); + } } + + public string PeerDisplayName + { + get { return _peerDisplayName; } + set + { + if (value == _peerDisplayName) return; + _peerDisplayName = value; + NotifyPropertyChanged("PeerDisplayName"); + } + } + + public string PeerNumber + { + get { return _peerNumber; } + set + { + if (value == _peerNumber) return; + + _peerNumber = value; + NotifyPropertyChanged("PeerNumber"); + } + } + + public string PeerUri { get; set; } + + private ePhoneCallStatus _status; + public ePhoneCallStatus Status + { + get { return _status; } + set + { + _status = value; + OffHook = _status == ePhoneCallStatus.PhoneCallStatus_Accepted || + _status == ePhoneCallStatus.PhoneCallStatus_InCall || + _status == ePhoneCallStatus.PhoneCallStatus_Init || + _status == ePhoneCallStatus.PhoneCallStatus_Ringing; + } + } + + public bool OffHook + { + get { return _offHook; } + set + { + if (value == _offHook) return; + + _offHook = value; + NotifyPropertyChanged("OffHook"); + } + } + } + + public enum ePhoneCallStatus + { + PhoneCallStatus_Ringing, + PhoneCallStatus_Terminated, + PhoneCallStatus_Accepted, + PhoneCallStatus_InCall, + PhoneCallStatus_Init, + } + } + + /// + /// zConfiguration class structure + /// + public class zConfiguration + { + public class Sharing + { + [JsonProperty("optimize_video_sharing")] + public bool OptimizeVideoSharing { get; set; } + } + + public class Camera : NotifiableObject + { + private bool _mute; + + public bool Mute + { + get { return _mute; } + set + { + Debug.Console(1, "Camera Mute response received: {0}", value); + + if (value == _mute) return; + + _mute = value; + NotifyPropertyChanged("Mute"); + } + } + } + + public class Microphone : NotifiableObject + { + private bool _mute; + + public bool Mute + { + get + { + return _mute; + } + set + { + if(value != _mute) + { + _mute = value; + NotifyPropertyChanged("Mute"); + } + } + } + } + + public enum eLayoutStyle + { + Gallery, + Speaker, + Strip, + ShareAll + } + + public enum eLayoutSize + { + Off, + Size1, + Size2, + Size3, + Strip + } + + public enum eLayoutPosition + { + Center, + Up, + Right, + UpRight, + Down, + DownRight, + Left, + UpLeft, + DownLeft + } + + public class Layout:NotifiableObject + { + public bool ShareThumb { get; set; } + public eLayoutStyle Style { get; set; } + public eLayoutSize Size { get; set; } + + private eLayoutPosition _position; + public eLayoutPosition Position { + get { return _position; } + set + { + _position = value; + NotifyPropertyChanged("Position"); + } } + } + + public class Lock + { + public bool Enable { get; set; } + } + + public class ClosedCaption + { + public bool Visible { get; set; } + public int FontSize { get; set; } + } + + public class MuteUserOnEntry + { + public bool Enable { get; set; } + } + + public class Call + { + public Sharing Sharing { get; set; } + public Camera Camera { get; set; } + public Microphone Microphone { get; set; } + public Layout Layout { get; set; } + public Lock Lock { get; set; } + public MuteUserOnEntry MuteUserOnEntry { get; set; } + public ClosedCaption ClosedCaption { get; set; } + + + public Call() + { + Sharing = new Sharing(); + Camera = new Camera(); + Microphone = new Microphone(); + Layout = new Layout(); + Lock = new Lock(); + MuteUserOnEntry = new MuteUserOnEntry(); + ClosedCaption = new ClosedCaption(); + } + } + + public class Audio + { + public Input Input { get; set; } + public Output Output { get; set; } + + public Audio() + { + Input = new Input(); + Output = new Output(); + } + } + + public class Input : Output + { + [JsonProperty("reduce_reverb")] + public bool ReduceReverb { get; set; } + } + + public class Output : NotifiableObject + { + private int _volume; + + [JsonProperty("volume")] + public int Volume + { + get + { + return _volume; + } + set + { + if (value != _volume) + { + _volume = value; + NotifyPropertyChanged("Volume"); + } + } + } + [JsonProperty("selectedId")] + public string SelectedId { get; set; } + [JsonProperty("is_sap_disabled")] + public bool IsSapDisabled { get; set; } + } + + public class Video : NotifiableObject + { + private bool _hideConfSelfVideo; + + [JsonProperty("hide_conf_self_video")] + public bool HideConfSelfVideo + { + get + { + return _hideConfSelfVideo; + } + set + { + if (value != _hideConfSelfVideo) + { + _hideConfSelfVideo = value; + NotifyPropertyChanged("HideConfSelfVideo"); + } + } + } + + public VideoCamera Camera { get; set; } + + public Video() + { + Camera = new VideoCamera(); + } + } + + public class VideoCamera : NotifiableObject + { + private string _selectedId; + + [JsonProperty("selectedId")] + public string SelectedId { + get + { + return _selectedId; + } + set + { + if (value != _selectedId) + { + _selectedId = value; + NotifyPropertyChanged("SelectedId"); + } + } + + } + public bool Mirror { get; set; } + } + + public class Client + { + public string appVersion { get; set; } + public string deviceSystem { get; set; } + } + + } + + /// + /// zCommand class structure + /// + public class zCommand + { + public class BookingsListResult + { + [JsonProperty("accessRole")] + public string AccessRole { get; set; } + [JsonProperty("calendarChangeKey")] + public string CalendarChangeKey { get; set; } + [JsonProperty("calendarID")] + public string CalendarId { get; set; } + [JsonProperty("checkIn")] + public bool CheckIn { get; set; } + [JsonProperty("creatorEmail")] + public string CreatorEmail { get; set; } + [JsonProperty("creatorName")] + public string CreatorName { get; set; } + [JsonProperty("endTime")] + public DateTime EndTime { get; set; } + [JsonProperty("hostName")] + public string HostName { get; set; } + [JsonProperty("isInstantMeeting")] + public bool IsInstantMeeting { get; set; } + [JsonProperty("isPrivate")] + public bool IsPrivate { get; set; } + [JsonProperty("location")] + public string Location { get; set; } + [JsonProperty("meetingName")] + public string MeetingName { get; set; } + [JsonProperty("meetingNumber")] + public string MeetingNumber { get; set; } + [JsonProperty("scheduledFrom")] + public string ScheduledFrom { get; set; } + [JsonProperty("startTime")] + public DateTime StartTime { get; set; } + [JsonProperty("third_party")] + public ThirdParty ThirdParty { get; set; } + } + + public static List GetGenericMeetingsFromBookingResult(List bookings, + int minutesBeforeMeetingStart) + { + var rv = GetGenericMeetingsFromBookingResult(bookings); + + foreach (var meeting in rv) + { + meeting.MinutesBeforeMeeting = minutesBeforeMeetingStart; + } + + return rv; + } + /// + /// Extracts the necessary meeting values from the Zoom bookings response and converts them to the generic class + /// + /// + /// + public static List GetGenericMeetingsFromBookingResult(List bookings) + { + var meetings = new List(); + + if (Debug.Level > 0) + { + Debug.Console(1, "Meetings List:\n"); + } + + foreach (var b in bookings) + { + var meeting = new Meeting(); + + if (b.MeetingNumber != null) + meeting.Id = b.MeetingNumber; + if (b.CreatorName != null) + meeting.Organizer = b.CreatorName; + if (b.MeetingName != null) + meeting.Title = b.MeetingName; + //if (b.Agenda != null) + // meeting.Agenda = b.Agenda.Value; + if (b.StartTime != null) + meeting.StartTime = b.StartTime; + if (b.EndTime != null) + meeting.EndTime = b.EndTime; + + meeting.Privacy = b.IsPrivate ? eMeetingPrivacy.Private : eMeetingPrivacy.Public; + + // No meeting.Calls data exists for Zoom Rooms. Leaving out for now. + var now = DateTime.Now; + if (meeting.StartTime < now && meeting.EndTime < now) + { + Debug.Console(1, "Skipping meeting {0}. Meeting is in the past.", meeting.Title); + continue; + } + + meetings.Add(meeting); + + if (Debug.Level > 0) + { + Debug.Console(1, "Title: {0}, ID: {1}, Organizer: {2}", meeting.Title, meeting.Id, meeting.Organizer); + Debug.Console(1, " Start Time: {0}, End Time: {1}, Duration: {2}", meeting.StartTime, meeting.EndTime, meeting.Duration); + Debug.Console(1, " Joinable: {0}\n", meeting.Joinable); + } + } + + meetings.OrderBy(m => m.StartTime); + + return meetings; + } + + public class HandStatus + { + [JsonProperty("is_raise_hand")] + public bool IsRaiseHand { get; set; } + [JsonProperty("optimize_vis_validideo_sharing")] + public string IsValid { get; set; } + [JsonProperty("time_stamp")] + public string TimeStamp { get; set; } + } + + public class ListParticipant + { + [JsonProperty("audio_status state")] + public string AudioStatusState { get; set; } + [JsonProperty("audio_status type")] + public string AudioStatusType { get; set; } + [JsonProperty("avatar_url")] + public string AvatarUrl { get; set; } + [JsonProperty("camera_status am_i_controlling")] + public bool CameraStatusAmIControlling { get; set; } + [JsonProperty("camera_status can_i_request_control")] + public bool CameraStatusCanIRequestConrol { get; set; } + [JsonProperty("camera_status can_move_camera")] + public bool CameraStatusCanMoveCamera { get; set; } + [JsonProperty("camera_status can_switch_camera")] + public bool CameraStatusCanSwitchCamera { get; set; } + [JsonProperty("camera_status can_zoom_camera")] + public bool CameraStatusCanZoomCamera { get; set; } + [JsonProperty("can_edit_closed_caption")] + public bool CanEditClosedCaption { get; set; } + [JsonProperty("can_record")] + public bool CanRecord { get; set; } + [JsonProperty("event")] + public string Event { get; set; } + [JsonProperty("hand_status")] + public HandStatus HandStatus { get; set; } + [JsonProperty("isCohost")] + public bool IsCohost { get; set; } + [JsonProperty("is_client_support_closed_caption")] + public bool IsClientSupportClosedCaption { get; set; } + [JsonProperty("is_client_support_coHost")] + public bool IsClientSupportCoHost { get; set; } + [JsonProperty("is_host")] + public bool IsHost { get; set; } + [JsonProperty("is_myself")] + public bool IsMyself { get; set; } + [JsonProperty("is_recording")] + public bool IsRecording { get; set; } + [JsonProperty("is_video_can_mute_byHost")] + public bool IsVideoCanMuteByHost { get; set; } + [JsonProperty("is_video_can_unmute_byHost")] + public bool IsVideoCanUnmuteByHost { get; set; } + [JsonProperty("local_recording_disabled")] + public bool LocalRecordingDisabled { get; set; } + [JsonProperty("user_id")] + public int UserId { get; set; } + [JsonProperty("user_name")] + public string UserName { get; set; } + [JsonProperty("user_type")] + public string UserType { get; set; } + [JsonProperty("video_status has_source")] + public bool VideoStatusHasSource { get; set; } + [JsonProperty("video_status is_receiving")] + public bool VideoStatusIsReceiving { get; set; } + [JsonProperty("video_status is_sending")] + public bool VideoStatusIsSending { get; set; } + + public ListParticipant() + { + HandStatus = new HandStatus(); + } + + public static List GetGenericParticipantListFromParticipantsResult( + List participants) + { + return + participants.Select( + p => + new Participant + { + Name = p.UserName, + IsHost = p.IsHost, + CanMuteVideo = p.IsVideoCanMuteByHost, + CanUnmuteVideo = p.IsVideoCanUnmuteByHost, + AudioMuteFb = p.AudioStatusState == "AUDIO_MUTED", + VideoMuteFb = p.VideoStatusIsSending + }).ToList(); + } + } + + public class CallinCountryList + { + public int code { get; set; } + public string display_number { get; set; } + public string id { get; set; } + public string name { get; set; } + public string number { get; set; } + } + + public class CalloutCountryList + { + public int code { get; set; } + public string display_number { get; set; } + public string id { get; set; } + public string name { get; set; } + public string number { get; set; } + } + + public class TollFreeCallinList + { + public int code { get; set; } + public string display_number { get; set; } + public string id { get; set; } + public string name { get; set; } + public string number { get; set; } + } + + public class Info + { + public List callin_country_list { get; set; } + public List callout_country_list { get; set; } + public List toll_free_callin_list { get; set; } + } + + public class ThirdParty + { + public string h323_address { get; set; } + public string meeting_number { get; set; } + public string service_provider { get; set; } + public string sip_address { get; set; } + } + + public class MeetingListItem + { + public string accessRole { get; set; } + public string calendarChangeKey { get; set; } + public string calendarID { get; set; } + public bool checkIn { get; set; } + public string creatorEmail { get; set; } + public string creatorName { get; set; } + public string endTime { get; set; } + public string hostName { get; set; } + public bool isInstantMeeting { get; set; } + public bool isPrivate { get; set; } + public string location { get; set; } + public string meetingName { get; set; } + public string meetingNumber { get; set; } + public string scheduledFrom { get; set; } + public string startTime { get; set; } + public ThirdParty third_party { get; set; } + + public MeetingListItem() + { + third_party = new ThirdParty(); + } + } + + public class InfoResult + { + public Info Info { get; set; } + public bool am_i_original_host { get; set; } + public string default_callin_country { get; set; } + public string dialIn { get; set; } + public string international_url { get; set; } + public string invite_email_content { get; set; } + public string invite_email_subject { get; set; } + public bool is_callin_country_list_available { get; set; } + public bool is_calling_room_system_enabled { get; set; } + public bool is_toll_free_callin_list_available { get; set; } + public bool is_view_only { get; set; } + public bool is_waiting_room { get; set; } + public bool is_webinar { get; set; } + public string meeting_id { get; set; } + public MeetingListItem meeting_list_item { get; set; } + public string meeting_password { get; set; } + public string meeting_type { get; set; } + public int my_userid { get; set; } + public int participant_id { get; set; } + public string real_meeting_id { get; set; } + public string schedule_option { get; set; } + public string schedule_option2 { get; set; } + public string support_callout_type { get; set; } + public string toll_free_number { get; set; } + public string user_type { get; set; } + + public InfoResult() + { + Info = new Info(); + meeting_list_item = new MeetingListItem(); + } + } + + public class Phonebook + { + public List Contacts { get; set; } + public int Limit { get; set; } + public int Offset { get; set; } + } + } } \ No newline at end of file From f0a3b27e3b254b91f192c9d1a5c4b498bb1c807f Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 17 Dec 2020 14:28:27 -0700 Subject: [PATCH 47/59] Adds dummy source and room power on implementation --- .../Room/Config/EssentialsTechRoomConfig.cs | 3 +++ .../Room/Types/EssentialsTechRoom.cs | 26 +++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs index 292a6b7c..06e67f39 100644 --- a/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsTechRoomConfig.cs @@ -5,6 +5,9 @@ namespace PepperDash.Essentials.Room.Config { public class EssentialsTechRoomConfig { + [JsonProperty("dummySourceKey")] + public string DummySourceKey { get; set; } + [JsonProperty("displays")] public List Displays; diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index 515a4355..d0de145d 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -28,8 +28,6 @@ namespace PepperDash.Essentials private Dictionary _currentPresets; private ScheduledEventGroup _roomScheduledEventGroup; - private GenericSource DummySource = new GenericSource("$off", "Dummy Source"); - public EssentialsTechRoom(DeviceConfig config) : base(config) { _config = config.Properties.ToObject(); @@ -243,9 +241,17 @@ namespace PepperDash.Essentials public void RoomPowerOn() { + var dummySource = DeviceManager.GetDeviceForKey(_config.DummySourceKey) as IRoutingOutputs; + + if (dummySource == null) + { + Debug.Console(1, this, "Unable to get source with key: {0}", _config.DummySourceKey); + return; + } + foreach (var display in _displays) { - + RunDirectRoute(dummySource, display.Value); } } @@ -388,7 +394,7 @@ namespace PepperDash.Essentials return; } - if (source.Key.Equals("$off", StringComparison.OrdinalIgnoreCase)) + if (source == null) { dest.ReleaseRoute(); if (dest is IHasPowerControl) @@ -396,11 +402,6 @@ namespace PepperDash.Essentials } else { - if (source == null) - { - Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", source.Key, dest.Key); - return; - } dest.ReleaseAndMakeRoute(source, eRoutingSignalType.Video); } } @@ -418,11 +419,14 @@ namespace PepperDash.Essentials var source = DeviceManager.GetDeviceForKey(sourceKey) as IRoutingOutputs; + if (source == null || dest == null) + { + Debug.Console(1, this, "Cannot route unknown source or destination '{0}' to {1}", sourceKey, destinationKey); + return; + } RunDirectRoute(source, dest); } - - #endregion } From b2402402d9266e18fa396a356d5d5cbbbff0a9d2 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 17 Dec 2020 14:48:01 -0700 Subject: [PATCH 48/59] remove dummy device add --- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 2 -- .../PepperDashEssentialsBase/Display/DisplayBase.cs | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index d0de145d..f0191839 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -48,8 +48,6 @@ namespace PepperDash.Essentials SubscribeToDisplayFeedbacks(); CreateOrUpdateScheduledEvents(); - - DeviceManager.AddDevice(DummySource); } public Dictionary CurrentPresetsFeedbacks { get; private set; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/DisplayBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/DisplayBase.cs index e4a2cb26..f1b96ac4 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/DisplayBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Display/DisplayBase.cs @@ -81,8 +81,6 @@ namespace PepperDash.Essentials.Core } - - public abstract void PowerOn(); public abstract void PowerOff(); public abstract void PowerToggle(); @@ -99,7 +97,7 @@ namespace PepperDash.Essentials.Core } } - public abstract void ExecuteSwitch(object selector); + public abstract void ExecuteSwitch(object selector); protected void LinkDisplayToApi(DisplayBase displayDevice, BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) @@ -315,7 +313,5 @@ namespace PepperDash.Essentials.Core var newEvent = NumericSwitchChange; if (newEvent != null) newEvent(this, e); } - - } } \ No newline at end of file From aa61479adc50f992183b8d3cd57407f7400e5511 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 18 Dec 2020 09:16:40 -0700 Subject: [PATCH 49/59] remove device info stuff from DGE for now --- .../Essentials_DM/Endpoints/DGEs/Dge100Controller.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials DM/Essentials_DM/Endpoints/DGEs/Dge100Controller.cs b/essentials-framework/Essentials DM/Essentials_DM/Endpoints/DGEs/Dge100Controller.cs index d7996554..39e549cc 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Endpoints/DGEs/Dge100Controller.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Endpoints/DGEs/Dge100Controller.cs @@ -39,12 +39,12 @@ namespace PepperDash.Essentials.DM.Endpoints.DGEs { _dge = device; _dgeEthernetInfo = _dge.ExtenderEthernetReservedSigs; - _dgeEthernetInfo.DeviceExtenderSigChange += (extender, args) => UpdateDeviceInfo(); + //_dgeEthernetInfo.DeviceExtenderSigChange += (extender, args) => UpdateDeviceInfo(); _dgeEthernetInfo.Use(); DeviceInfo = new DeviceInfo(); - _dge.OnlineStatusChange += (currentDevice, args) => { if (args.DeviceOnLine) UpdateDeviceInfo(); }; + //_dge.OnlineStatusChange += (currentDevice, args) => { if (args.DeviceOnLine) UpdateDeviceInfo(); }; _dc = dc; From 870f2f8fa641d805999b594f8a460deb054adb48 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 18 Dec 2020 14:34:15 -0700 Subject: [PATCH 50/59] properly defines the IsWarming/Cooling FeedbackFuncs and fires feedbacks --- .../Room/Types/EssentialsTechRoom.cs | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index f0191839..a2943528 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -28,6 +28,33 @@ namespace PepperDash.Essentials private Dictionary _currentPresets; private ScheduledEventGroup _roomScheduledEventGroup; + /// + /// + /// + protected override Func IsWarmingFeedbackFunc + { + get + { + return () => + { + return _displays.All(kv => kv.Value.IsWarmingUpFeedback.BoolValue); + }; + } + } + /// + /// + /// + protected override Func IsCoolingFeedbackFunc + { + get + { + return () => + { + return _displays.All(kv => kv.Value.IsCoolingDownFeedback.BoolValue); + }; + } + } + public EssentialsTechRoom(DeviceConfig config) : base(config) { _config = config.Properties.ToObject(); @@ -111,7 +138,12 @@ namespace PepperDash.Essentials foreach (var display in _displays) { display.Value.PowerIsOnFeedback.OutputChange += - (sender, args) => RoomPowerIsOnFeedback.InvokeFireUpdate(); + (sender, args) => + { + RoomPowerIsOnFeedback.InvokeFireUpdate(); + IsWarmingUpFeedback.InvokeFireUpdate(); + IsCoolingDownFeedback.InvokeFireUpdate(); + }; } } @@ -281,16 +313,6 @@ namespace PepperDash.Essentials #region Overrides of EssentialsRoomBase - protected override Func IsWarmingFeedbackFunc - { - get { return () => false; } - } - - protected override Func IsCoolingFeedbackFunc - { - get { return () => false; } - } - protected override Func OnFeedbackFunc { get { return () => RoomPowerIsOn; } From 0f924360c11f60e39ec6527ef411908789a8bf77 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Dec 2020 10:51:12 -0700 Subject: [PATCH 51/59] fix issues in LinkToApi --- PepperDashEssentials/Room/Types/EssentialsTechRoom.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index a2943528..0a47933e 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -380,6 +380,8 @@ namespace PepperDash.Essentials feedback.Value.FireUpdate(); } }; + + return; } i = 0; @@ -388,6 +390,8 @@ namespace PepperDash.Essentials var tuner = setTopBox; trilist.SetStringSigAction(joinMap.CurrentPreset.JoinNumber + i, s => _tunerPresets.Dial(s, tuner.Value)); + + i++; } } From 0a43f43f665704ae8edf87f4732a1958508aaee1 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Dec 2020 12:31:00 -0700 Subject: [PATCH 52/59] add ICommunicationMonitor to EiscApiAdvanced --- .../Bridges/BridgeBase.cs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs index 86db81ba..33285bff 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs @@ -78,7 +78,7 @@ namespace PepperDash.Essentials.Core.Bridges /// /// Bridge API using EISC /// - public class EiscApiAdvanced : BridgeApi + public class EiscApiAdvanced : BridgeApi, ICommunicationMonitor { public EiscApiPropertiesConfig PropertiesConfig { get; private set; } @@ -89,6 +89,7 @@ namespace PepperDash.Essentials.Core.Bridges public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) : base(dc.Key) { + CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000); JoinMaps = new Dictionary(); PropertiesConfig = dc.Properties.ToObject(); @@ -100,6 +101,19 @@ namespace PepperDash.Essentials.Core.Bridges AddPostActivationAction(LinkDevices); AddPostActivationAction(LinkRooms); + AddPostActivationAction(RegisterEisc); + } + + public override bool CustomActivate() + { + CommunicationMonitor.Start(); + return base.CustomActivate(); + } + + public override bool Deactivate() + { + CommunicationMonitor.Stop(); + return base.Deactivate(); } private void LinkDevices() @@ -137,8 +151,6 @@ namespace PepperDash.Essentials.Core.Bridges bridge.LinkToApi(Eisc, d.JoinStart, d.JoinMapKey, this); } } - - RegisterEisc(); } private void RegisterEisc() @@ -182,8 +194,6 @@ namespace PepperDash.Essentials.Core.Bridges rm.LinkToApi(Eisc, room.JoinStart, room.JoinMapKey, this); } - - RegisterEisc(); } /// @@ -324,6 +334,12 @@ namespace PepperDash.Essentials.Core.Bridges Debug.Console(2, this, "Error in Eisc_SigChange handler: {0}", e); } } + + #region Implementation of ICommunicationMonitor + + public StatusMonitorBase CommunicationMonitor { get; private set; } + + #endregion } public class EiscApiPropertiesConfig From cc159e306e1295a2aa277f40dd4e0cc060f39148 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Dec 2020 14:40:19 -0700 Subject: [PATCH 53/59] update Essentials to use PepperDash Core 1.0.43 --- .../PepperDashEssentialsBase/PepperDash_Essentials_Core.nuspec | 2 +- packages.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.nuspec b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.nuspec index 5db86afc..dff167ed 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.nuspec +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.nuspec @@ -14,7 +14,7 @@ crestron 3series 4series - + diff --git a/packages.config b/packages.config index c138dd1b..67789ca5 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file From ae03b8cd7e1e368619fc32160fc577b89ec0b537 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Dec 2020 16:19:45 -0700 Subject: [PATCH 54/59] fix PresetsList saving to file --- .../PepperDashEssentialsBase/Presets/DevicePresets.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs index 85e5dfdb..d6a9fad0 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Presets/DevicePresets.cs @@ -266,14 +266,13 @@ namespace PepperDash.Essentials.Core.Presets try { _fileOps.Enter(); - var json = JsonConvert.SerializeObject(PresetsList); + var pl = new PresetsList {Channels = PresetsList, Name = Name}; + var json = JsonConvert.SerializeObject(pl, Formatting.Indented); using (var file = File.Open(_filePath, FileMode.Truncate)) { file.Write(json, Encoding.UTF8); } - - } finally { From 3b0a5285ab5d8d4f4e99397582a1337eade40a9a Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 21 Dec 2020 17:00:37 -0700 Subject: [PATCH 55/59] fix order for comm monitor --- .../PepperDashEssentialsBase/Bridges/BridgeBase.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs index 33285bff..11ede5a1 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/BridgeBase.cs @@ -89,7 +89,6 @@ namespace PepperDash.Essentials.Core.Bridges public EiscApiAdvanced(DeviceConfig dc, BasicTriList eisc) : base(dc.Key) { - CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000); JoinMaps = new Dictionary(); PropertiesConfig = dc.Properties.ToObject(); @@ -99,6 +98,8 @@ namespace PepperDash.Essentials.Core.Bridges Eisc.SigChange += Eisc_SigChange; + CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Eisc, 120000, 300000); + AddPostActivationAction(LinkDevices); AddPostActivationAction(LinkRooms); AddPostActivationAction(RegisterEisc); From 89990971001734da09d7a02a0ea6b15452e20a21 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 6 Jan 2021 16:12:12 -0700 Subject: [PATCH 56/59] Adds additional debug to help with room on/off events --- .../Room/Types/EssentialsTechRoom.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index 0a47933e..bfa56646 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -261,8 +261,16 @@ namespace PepperDash.Essentials CrestronInvoke.BeginInvoke((o) => { + Debug.Console(2, this, "There are {0} actions to execute for this event.", eventConfig.Actions.Count); + foreach (var a in eventConfig.Actions) { + Debug.Console(2, this, +@"Attempting to run action: +DeviceKey: {0} +MethodName: {1} +Params: {2}" + , a.DeviceKey, a.MethodName, a.Params); DeviceJsonApi.DoDeviceAction(a); } }); @@ -271,6 +279,8 @@ namespace PepperDash.Essentials public void RoomPowerOn() { + Debug.Console(2, this, "Room Powering On"); + var dummySource = DeviceManager.GetDeviceForKey(_config.DummySourceKey) as IRoutingOutputs; if (dummySource == null) @@ -287,6 +297,8 @@ namespace PepperDash.Essentials public void RoomPowerOff() { + Debug.Console(2, this, "Room Powering Off"); + foreach (var display in _displays) { display.Value.PowerOff(); From 3c1ed6e58aac601f4db9442ff8a8f654caa9d547 Mon Sep 17 00:00:00 2001 From: Trevor Payne Date: Thu, 7 Jan 2021 12:41:29 -0600 Subject: [PATCH 57/59] Added debug statements to ExecuteNumericSwitch in DmTx4kz302CController --- .../Endpoints/Transmitters/DmTx4kz302CController.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Transmitters/DmTx4kz302CController.cs b/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Transmitters/DmTx4kz302CController.cs index 1e44396c..1c5ce36e 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Transmitters/DmTx4kz302CController.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Transmitters/DmTx4kz302CController.cs @@ -282,6 +282,12 @@ namespace PepperDash.Essentials.DM ExecuteSwitch(eVst.AllDisabled, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); break; } + default: + { + Debug.Console(2, this, "Unable to execute numeric switch to input {0}", input); + break; + } + } @@ -289,6 +295,7 @@ namespace PepperDash.Essentials.DM public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType) { + Debug.Console(2, this, "Attempting to switch InputSelector {0}", ((eVst)inputSelector).ToString()); if ((signalType | eRoutingSignalType.Video) == eRoutingSignalType.Video) Tx.VideoSource = (eVst)inputSelector; From 82029894e47bc5a06ca07fe21ab3bdc9d1ae4794 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 7 Jan 2021 14:46:49 -0700 Subject: [PATCH 58/59] Changed to use passed in type value for signal type instead of assuming both audio and video --- .../Transmitters/DmTx4kz302CController.cs | 713 +++++++++--------- 1 file changed, 360 insertions(+), 353 deletions(-) diff --git a/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Transmitters/DmTx4kz302CController.cs b/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Transmitters/DmTx4kz302CController.cs index 1c5ce36e..fb8f3ac5 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Transmitters/DmTx4kz302CController.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Transmitters/DmTx4kz302CController.cs @@ -1,44 +1,44 @@ -using Crestron.SimplSharpPro; -using System; -using System.Linq; -//using Crestron.SimplSharpPro.DeviceSupport; -using Crestron.SimplSharpPro.DeviceSupport; -using Crestron.SimplSharpPro.DM; -using Crestron.SimplSharpPro.DM.Endpoints; -using Crestron.SimplSharpPro.DM.Endpoints.Transmitters; - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Bridges; - -namespace PepperDash.Essentials.DM -{ - using eVst = eX02VideoSourceType; - using eAst = eX02AudioSourceType; - - +using Crestron.SimplSharpPro; +using System; +using System.Linq; +//using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.DM; +using Crestron.SimplSharpPro.DM.Endpoints; +using Crestron.SimplSharpPro.DM.Endpoints.Transmitters; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Bridges; + +namespace PepperDash.Essentials.DM +{ + using eVst = eX02VideoSourceType; + using eAst = eX02AudioSourceType; + + [Description("Wrapper class for DM-TX-4K-Z-302-C")] - public class DmTx4kz302CController : DmTxControllerBase, ITxRoutingWithFeedback, IHasFeedback, - IIROutputPorts, IComPorts - { - public DmTx4kz302C Tx { get; private set; } - - public RoutingInputPortWithVideoStatuses HdmiIn1 { get; private set; } - public RoutingInputPortWithVideoStatuses HdmiIn2 { get; private set; } - public RoutingInputPortWithVideoStatuses DisplayPortIn { get; private set; } - public RoutingOutputPort DmOut { get; private set; } - public RoutingOutputPort HdmiLoopOut { get; private set; } - - public override StringFeedback ActiveVideoInputFeedback { get; protected set; } - public IntFeedback VideoSourceNumericFeedback { get; protected set; } - public IntFeedback AudioSourceNumericFeedback { get; protected set; } - public IntFeedback HdmiIn1HdcpCapabilityFeedback { get; protected set; } - public IntFeedback HdmiIn2HdcpCapabilityFeedback { get; protected set; } - public BoolFeedback Hdmi1VideoSyncFeedback { get; protected set; } - public BoolFeedback Hdmi2VideoSyncFeedback { get; protected set; } - public BoolFeedback DisplayPortVideoSyncFeedback { get; protected set; } - - //public override IntFeedback HdcpSupportAllFeedback { get; protected set; } + public class DmTx4kz302CController : DmTxControllerBase, ITxRoutingWithFeedback, IHasFeedback, + IIROutputPorts, IComPorts + { + public DmTx4kz302C Tx { get; private set; } + + public RoutingInputPortWithVideoStatuses HdmiIn1 { get; private set; } + public RoutingInputPortWithVideoStatuses HdmiIn2 { get; private set; } + public RoutingInputPortWithVideoStatuses DisplayPortIn { get; private set; } + public RoutingOutputPort DmOut { get; private set; } + public RoutingOutputPort HdmiLoopOut { get; private set; } + + public override StringFeedback ActiveVideoInputFeedback { get; protected set; } + public IntFeedback VideoSourceNumericFeedback { get; protected set; } + public IntFeedback AudioSourceNumericFeedback { get; protected set; } + public IntFeedback HdmiIn1HdcpCapabilityFeedback { get; protected set; } + public IntFeedback HdmiIn2HdcpCapabilityFeedback { get; protected set; } + public BoolFeedback Hdmi1VideoSyncFeedback { get; protected set; } + public BoolFeedback Hdmi2VideoSyncFeedback { get; protected set; } + public BoolFeedback DisplayPortVideoSyncFeedback { get; protected set; } + + //public override IntFeedback HdcpSupportAllFeedback { get; protected set; } //public override ushort HdcpSupportCapability { get; protected set; } //IroutingNumericEvent @@ -52,279 +52,286 @@ namespace PepperDash.Essentials.DM { var newEvent = NumericSwitchChange; if (newEvent != null) newEvent(this, e); - } - - /// - /// Helps get the "real" inputs, including when in Auto - /// - public eX02VideoSourceType ActualActiveVideoInput - { - get - { - if (Tx.VideoSourceFeedback != eVst.Auto) - return Tx.VideoSourceFeedback; - if (Tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue) - return eVst.Hdmi1; - if (Tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue) - return eVst.Hdmi2; - - return Tx.DisplayPortInput.SyncDetectedFeedback.BoolValue ? eVst.Vga : eVst.AllDisabled; - } - } - public RoutingPortCollection InputPorts - { - get - { - return new RoutingPortCollection - { - HdmiIn1, - HdmiIn2, - DisplayPortIn, - AnyVideoInput - }; - } - } - public RoutingPortCollection OutputPorts - { - get - { - return new RoutingPortCollection { DmOut, HdmiLoopOut }; - } - } - public DmTx4kz302CController(string key, string name, DmTx4kz302C tx) - : base(key, name, tx) - { - Tx = tx; - - HdmiIn1 = new RoutingInputPortWithVideoStatuses(DmPortName.HdmiIn1, - eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, eVst.Hdmi1, this, + } + + /// + /// Helps get the "real" inputs, including when in Auto + /// + public eX02VideoSourceType ActualActiveVideoInput + { + get + { + if (Tx.VideoSourceFeedback != eVst.Auto) + return Tx.VideoSourceFeedback; + if (Tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue) + return eVst.Hdmi1; + if (Tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue) + return eVst.Hdmi2; + + return Tx.DisplayPortInput.SyncDetectedFeedback.BoolValue ? eVst.Vga : eVst.AllDisabled; + } + } + public RoutingPortCollection InputPorts + { + get + { + return new RoutingPortCollection + { + HdmiIn1, + HdmiIn2, + DisplayPortIn, + AnyVideoInput + }; + } + } + public RoutingPortCollection OutputPorts + { + get + { + return new RoutingPortCollection { DmOut, HdmiLoopOut }; + } + } + public DmTx4kz302CController(string key, string name, DmTx4kz302C tx) + : base(key, name, tx) + { + Tx = tx; + + HdmiIn1 = new RoutingInputPortWithVideoStatuses(DmPortName.HdmiIn1, + eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, eVst.Hdmi1, this, VideoStatusHelper.GetHdmiInputStatusFuncs(tx.HdmiInputs[1])) { FeedbackMatchObject = eVst.Hdmi1 - }; - HdmiIn2 = new RoutingInputPortWithVideoStatuses(DmPortName.HdmiIn2, - eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, eVst.Hdmi2, this, + }; + HdmiIn2 = new RoutingInputPortWithVideoStatuses(DmPortName.HdmiIn2, + eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, eVst.Hdmi2, this, VideoStatusHelper.GetHdmiInputStatusFuncs(tx.HdmiInputs[2])) { FeedbackMatchObject = eVst.Hdmi2 - }; - DisplayPortIn = new RoutingInputPortWithVideoStatuses(DmPortName.DisplayPortIn, - eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.DisplayPort, eVst.DisplayPort, this, + }; + DisplayPortIn = new RoutingInputPortWithVideoStatuses(DmPortName.DisplayPortIn, + eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.DisplayPort, eVst.DisplayPort, this, VideoStatusHelper.GetDisplayPortInputStatusFuncs(tx.DisplayPortInput)) { FeedbackMatchObject = eVst.DisplayPort - }; - ActiveVideoInputFeedback = new StringFeedback("ActiveVideoInput", - () => ActualActiveVideoInput.ToString()); - - Tx.HdmiInputs[1].InputStreamChange += InputStreamChangeEvent; - Tx.HdmiInputs[2].InputStreamChange += InputStreamChangeEvent; - Tx.DisplayPortInput.InputStreamChange += DisplayPortInputStreamChange; - Tx.BaseEvent += Tx_BaseEvent; - Tx.OnlineStatusChange += Tx_OnlineStatusChange; - - VideoSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback); - AudioSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback); - - HdmiIn1HdcpCapabilityFeedback = new IntFeedback("HdmiIn1HdcpCapability", () => (int)tx.HdmiInputs[1].HdcpCapabilityFeedback); - - HdmiIn2HdcpCapabilityFeedback = new IntFeedback("HdmiIn2HdcpCapability", () => (int)tx.HdmiInputs[2].HdcpCapabilityFeedback); - - HdcpStateFeedback = - new IntFeedback( - () => - tx.HdmiInputs[1].HdcpCapabilityFeedback > tx.HdmiInputs[2].HdcpCapabilityFeedback - ? (int)tx.HdmiInputs[1].HdcpCapabilityFeedback - : (int)tx.HdmiInputs[2].HdcpCapabilityFeedback); - - HdcpSupportCapability = eHdcpCapabilityType.Hdcp2_2Support; - - Hdmi1VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue); - - Hdmi2VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue); - - DisplayPortVideoSyncFeedback = new BoolFeedback(() => (bool)tx.DisplayPortInput.SyncDetectedFeedback.BoolValue); - - - var combinedFuncs = new VideoStatusFuncsWrapper - { - HdcpActiveFeedbackFunc = () => - (ActualActiveVideoInput == eVst.Hdmi1 - && tx.HdmiInputs[1].VideoAttributes.HdcpActiveFeedback.BoolValue) - || (ActualActiveVideoInput == eVst.Hdmi2 - && tx.HdmiInputs[2].VideoAttributes.HdcpActiveFeedback.BoolValue), - - HdcpStateFeedbackFunc = () => - { - if (ActualActiveVideoInput == eVst.Hdmi1) - return tx.HdmiInputs[1].VideoAttributes.HdcpStateFeedback.ToString(); - return ActualActiveVideoInput == eVst.Hdmi2 ? tx.HdmiInputs[2].VideoAttributes.HdcpStateFeedback.ToString() : ""; - }, - - VideoResolutionFeedbackFunc = () => - { - if (ActualActiveVideoInput == eVst.Hdmi1) - return tx.HdmiInputs[1].VideoAttributes.GetVideoResolutionString(); - if (ActualActiveVideoInput == eVst.Hdmi2) - return tx.HdmiInputs[2].VideoAttributes.GetVideoResolutionString(); - return ActualActiveVideoInput == eVst.Vga ? tx.DisplayPortInput.VideoAttributes.GetVideoResolutionString() : ""; - }, - VideoSyncFeedbackFunc = () => - (ActualActiveVideoInput == eVst.Hdmi1 - && tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue) - || (ActualActiveVideoInput == eVst.Hdmi2 - && tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue) - || (ActualActiveVideoInput == eVst.Vga - && tx.DisplayPortInput.SyncDetectedFeedback.BoolValue) - - }; - - AnyVideoInput = new RoutingInputPortWithVideoStatuses(DmPortName.AnyVideoIn, - eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this, combinedFuncs); - - DmOut = new RoutingOutputPort(DmPortName.DmOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.DmCat, null, this); - HdmiLoopOut = new RoutingOutputPort(DmPortName.HdmiLoopOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, - eRoutingPortConnectionType.Hdmi, null, this); - - - AddToFeedbackList(ActiveVideoInputFeedback, VideoSourceNumericFeedback, AudioSourceNumericFeedback, - AnyVideoInput.VideoStatus.HasVideoStatusFeedback, AnyVideoInput.VideoStatus.HdcpActiveFeedback, - AnyVideoInput.VideoStatus.HdcpStateFeedback, AnyVideoInput.VideoStatus.VideoResolutionFeedback, - AnyVideoInput.VideoStatus.VideoSyncFeedback, HdmiIn1HdcpCapabilityFeedback, HdmiIn2HdcpCapabilityFeedback, - Hdmi1VideoSyncFeedback, Hdmi2VideoSyncFeedback, DisplayPortVideoSyncFeedback); - - // Set Ports for CEC - HdmiIn1.Port = Tx.HdmiInputs[1]; - HdmiIn2.Port = Tx.HdmiInputs[2]; - HdmiLoopOut.Port = Tx.HdmiOutput; - DmOut.Port = Tx.DmOutput; - } - - void DisplayPortInputStreamChange(EndpointInputStream inputStream, EndpointInputStreamEventArgs args) - { - Debug.Console(2, "{0} event {1} stream {2}", Tx.ToString(), inputStream.ToString(), args.EventId.ToString()); - - switch (args.EventId) - { - case EndpointInputStreamEventIds.SyncDetectedFeedbackEventId: - DisplayPortVideoSyncFeedback.FireUpdate(); - break; - } - } - - - - public override bool CustomActivate() - { - // Link up all of these damned events to the various RoutingPorts via a helper handler - Tx.HdmiInputs[1].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn1, a.EventId); - Tx.HdmiInputs[1].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn1, a.EventId); - - Tx.HdmiInputs[2].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn2, a.EventId); - Tx.HdmiInputs[2].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn2, a.EventId); - - Tx.DisplayPortInput.InputStreamChange += (o, a) => FowardInputStreamChange(DisplayPortIn, a.EventId); - Tx.DisplayPortInput.VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(DisplayPortIn, a.EventId); - - // Base does register and sets up comm monitoring. - return base.CustomActivate(); - } - - public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) - { - var joinMap = GetDmTxJoinMap(joinStart, joinMapKey); - - if (Hdmi1VideoSyncFeedback != null) - { - Hdmi1VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input1VideoSyncStatus.JoinNumber]); - } - if (Hdmi2VideoSyncFeedback != null) - { - Hdmi2VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input2VideoSyncStatus.JoinNumber]); - } - if (DisplayPortVideoSyncFeedback != null) - { - DisplayPortVideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input3VideoSyncStatus.JoinNumber]); - } - - LinkDmTxToApi(this, trilist, joinMap, bridge); - } - - public void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type) - { - Debug.Console(2, this, "Executing Numeric Switch to input {0}.", input); - - switch (input) - { - case 0: - { - ExecuteSwitch(eVst.Auto, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); - break; - } - case 1: - { - ExecuteSwitch(HdmiIn1.Selector, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); - break; - } - case 2: - { - ExecuteSwitch(HdmiIn2.Selector, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); - break; - } - case 3: - { - ExecuteSwitch(DisplayPortIn.Selector, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); - break; - } - case 4: - { - ExecuteSwitch(eVst.AllDisabled, null, eRoutingSignalType.Audio | eRoutingSignalType.Video); - break; - } + }; + ActiveVideoInputFeedback = new StringFeedback("ActiveVideoInput", + () => ActualActiveVideoInput.ToString()); + + Tx.HdmiInputs[1].InputStreamChange += InputStreamChangeEvent; + Tx.HdmiInputs[2].InputStreamChange += InputStreamChangeEvent; + Tx.DisplayPortInput.InputStreamChange += DisplayPortInputStreamChange; + Tx.BaseEvent += Tx_BaseEvent; + Tx.OnlineStatusChange += Tx_OnlineStatusChange; + + VideoSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback); + AudioSourceNumericFeedback = new IntFeedback(() => (int)Tx.VideoSourceFeedback); + + HdmiIn1HdcpCapabilityFeedback = new IntFeedback("HdmiIn1HdcpCapability", () => (int)tx.HdmiInputs[1].HdcpCapabilityFeedback); + + HdmiIn2HdcpCapabilityFeedback = new IntFeedback("HdmiIn2HdcpCapability", () => (int)tx.HdmiInputs[2].HdcpCapabilityFeedback); + + HdcpStateFeedback = + new IntFeedback( + () => + tx.HdmiInputs[1].HdcpCapabilityFeedback > tx.HdmiInputs[2].HdcpCapabilityFeedback + ? (int)tx.HdmiInputs[1].HdcpCapabilityFeedback + : (int)tx.HdmiInputs[2].HdcpCapabilityFeedback); + + HdcpSupportCapability = eHdcpCapabilityType.Hdcp2_2Support; + + Hdmi1VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue); + + Hdmi2VideoSyncFeedback = new BoolFeedback(() => (bool)tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue); + + DisplayPortVideoSyncFeedback = new BoolFeedback(() => (bool)tx.DisplayPortInput.SyncDetectedFeedback.BoolValue); + + + var combinedFuncs = new VideoStatusFuncsWrapper + { + HdcpActiveFeedbackFunc = () => + (ActualActiveVideoInput == eVst.Hdmi1 + && tx.HdmiInputs[1].VideoAttributes.HdcpActiveFeedback.BoolValue) + || (ActualActiveVideoInput == eVst.Hdmi2 + && tx.HdmiInputs[2].VideoAttributes.HdcpActiveFeedback.BoolValue), + + HdcpStateFeedbackFunc = () => + { + if (ActualActiveVideoInput == eVst.Hdmi1) + return tx.HdmiInputs[1].VideoAttributes.HdcpStateFeedback.ToString(); + return ActualActiveVideoInput == eVst.Hdmi2 ? tx.HdmiInputs[2].VideoAttributes.HdcpStateFeedback.ToString() : ""; + }, + + VideoResolutionFeedbackFunc = () => + { + if (ActualActiveVideoInput == eVst.Hdmi1) + return tx.HdmiInputs[1].VideoAttributes.GetVideoResolutionString(); + if (ActualActiveVideoInput == eVst.Hdmi2) + return tx.HdmiInputs[2].VideoAttributes.GetVideoResolutionString(); + return ActualActiveVideoInput == eVst.Vga ? tx.DisplayPortInput.VideoAttributes.GetVideoResolutionString() : ""; + }, + VideoSyncFeedbackFunc = () => + (ActualActiveVideoInput == eVst.Hdmi1 + && tx.HdmiInputs[1].SyncDetectedFeedback.BoolValue) + || (ActualActiveVideoInput == eVst.Hdmi2 + && tx.HdmiInputs[2].SyncDetectedFeedback.BoolValue) + || (ActualActiveVideoInput == eVst.Vga + && tx.DisplayPortInput.SyncDetectedFeedback.BoolValue) + + }; + + AnyVideoInput = new RoutingInputPortWithVideoStatuses(DmPortName.AnyVideoIn, + eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.None, 0, this, combinedFuncs); + + DmOut = new RoutingOutputPort(DmPortName.DmOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.DmCat, null, this); + HdmiLoopOut = new RoutingOutputPort(DmPortName.HdmiLoopOut, eRoutingSignalType.Audio | eRoutingSignalType.Video, + eRoutingPortConnectionType.Hdmi, null, this); + + + AddToFeedbackList(ActiveVideoInputFeedback, VideoSourceNumericFeedback, AudioSourceNumericFeedback, + AnyVideoInput.VideoStatus.HasVideoStatusFeedback, AnyVideoInput.VideoStatus.HdcpActiveFeedback, + AnyVideoInput.VideoStatus.HdcpStateFeedback, AnyVideoInput.VideoStatus.VideoResolutionFeedback, + AnyVideoInput.VideoStatus.VideoSyncFeedback, HdmiIn1HdcpCapabilityFeedback, HdmiIn2HdcpCapabilityFeedback, + Hdmi1VideoSyncFeedback, Hdmi2VideoSyncFeedback, DisplayPortVideoSyncFeedback); + + // Set Ports for CEC + HdmiIn1.Port = Tx.HdmiInputs[1]; + HdmiIn2.Port = Tx.HdmiInputs[2]; + HdmiLoopOut.Port = Tx.HdmiOutput; + DmOut.Port = Tx.DmOutput; + } + + void DisplayPortInputStreamChange(EndpointInputStream inputStream, EndpointInputStreamEventArgs args) + { + Debug.Console(2, "{0} event {1} stream {2}", Tx.ToString(), inputStream.ToString(), args.EventId.ToString()); + + switch (args.EventId) + { + case EndpointInputStreamEventIds.SyncDetectedFeedbackEventId: + DisplayPortVideoSyncFeedback.FireUpdate(); + break; + } + } + + + + public override bool CustomActivate() + { + // Link up all of these damned events to the various RoutingPorts via a helper handler + Tx.HdmiInputs[1].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn1, a.EventId); + Tx.HdmiInputs[1].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn1, a.EventId); + + Tx.HdmiInputs[2].InputStreamChange += (o, a) => FowardInputStreamChange(HdmiIn2, a.EventId); + Tx.HdmiInputs[2].VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(HdmiIn2, a.EventId); + + Tx.DisplayPortInput.InputStreamChange += (o, a) => FowardInputStreamChange(DisplayPortIn, a.EventId); + Tx.DisplayPortInput.VideoAttributes.AttributeChange += (o, a) => ForwardVideoAttributeChange(DisplayPortIn, a.EventId); + + // Base does register and sets up comm monitoring. + return base.CustomActivate(); + } + + public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) + { + var joinMap = GetDmTxJoinMap(joinStart, joinMapKey); + + if (Hdmi1VideoSyncFeedback != null) + { + Hdmi1VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input1VideoSyncStatus.JoinNumber]); + } + if (Hdmi2VideoSyncFeedback != null) + { + Hdmi2VideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input2VideoSyncStatus.JoinNumber]); + } + if (DisplayPortVideoSyncFeedback != null) + { + DisplayPortVideoSyncFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Input3VideoSyncStatus.JoinNumber]); + } + + LinkDmTxToApi(this, trilist, joinMap, bridge); + } + + public void ExecuteNumericSwitch(ushort input, ushort output, eRoutingSignalType type) + { + Debug.Console(2, this, "Executing Numeric Switch to input {0}.", input); + + switch (input) + { + case 0: + { + ExecuteSwitch(eVst.Auto, null, type); + break; + } + case 1: + { + ExecuteSwitch(HdmiIn1.Selector, null, type); + break; + } + case 2: + { + ExecuteSwitch(HdmiIn2.Selector, null, type); + break; + } + case 3: + { + ExecuteSwitch(DisplayPortIn.Selector, null, type); + break; + } + case 4: + { + ExecuteSwitch(eVst.AllDisabled, null, type); + break; + } default: { Debug.Console(2, this, "Unable to execute numeric switch to input {0}", input); break; - } - - } - - - } - - public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType) - { - Debug.Console(2, this, "Attempting to switch InputSelector {0}", ((eVst)inputSelector).ToString()); - if ((signalType | eRoutingSignalType.Video) == eRoutingSignalType.Video) - Tx.VideoSource = (eVst)inputSelector; - - // NOTE: It's possible that this particular TX model may not like the AudioSource property being set. - // The SIMPL definition only shows a single analog for AudioVideo Source - if ((signalType | eRoutingSignalType.Audio) == eRoutingSignalType.Audio) - //it doesn't - Debug.Console(2, this, "Unable to execute audio-only switch for tx {0}", Key); - //Tx.AudioSource = (eAst)inputSelector; - } - - void InputStreamChangeEvent(EndpointInputStream inputStream, EndpointInputStreamEventArgs args) - { - Debug.Console(2, "{0} event {1} stream {2}", Tx.ToString(), inputStream.ToString(), args.EventId.ToString()); - - switch (args.EventId) - { - case EndpointInputStreamEventIds.HdcpSupportOffFeedbackEventId: - case EndpointInputStreamEventIds.HdcpSupportOnFeedbackEventId: - case EndpointInputStreamEventIds.HdcpCapabilityFeedbackEventId: - if (inputStream == Tx.HdmiInputs[1]) HdmiIn1HdcpCapabilityFeedback.FireUpdate(); - if (inputStream == Tx.HdmiInputs[2]) HdmiIn2HdcpCapabilityFeedback.FireUpdate(); - HdcpStateFeedback.FireUpdate(); - break; - case EndpointInputStreamEventIds.SyncDetectedFeedbackEventId: - if (inputStream == Tx.HdmiInputs[1]) Hdmi1VideoSyncFeedback.FireUpdate(); - if (inputStream == Tx.HdmiInputs[2]) Hdmi2VideoSyncFeedback.FireUpdate(); - break; - } + } + + } + + + } + + public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType signalType) + { + try + { + Debug.Console(2, this, "Attempting to switch InputSelector {0}", ((eVst)inputSelector).ToString()); + if ((signalType | eRoutingSignalType.Video) == eRoutingSignalType.Video) + Tx.VideoSource = (eVst)inputSelector; + + // NOTE: It's possible that this particular TX model may not like the AudioSource property being set. + // The SIMPL definition only shows a single analog for AudioVideo Source + if ((signalType | eRoutingSignalType.Audio) == eRoutingSignalType.Audio) + //it doesn't + Debug.Console(2, this, "Unable to execute audio-only switch for tx {0}", Key); + //Tx.AudioSource = (eAst)inputSelector; + } + catch (Exception e) + { + Debug.Console(2, this, "Exception in ExecuteSwitch: {0}", e); + } + } + + void InputStreamChangeEvent(EndpointInputStream inputStream, EndpointInputStreamEventArgs args) + { + Debug.Console(2, "{0} event {1} stream {2}", Tx.ToString(), inputStream.ToString(), args.EventId.ToString()); + + switch (args.EventId) + { + case EndpointInputStreamEventIds.HdcpSupportOffFeedbackEventId: + case EndpointInputStreamEventIds.HdcpSupportOnFeedbackEventId: + case EndpointInputStreamEventIds.HdcpCapabilityFeedbackEventId: + if (inputStream == Tx.HdmiInputs[1]) HdmiIn1HdcpCapabilityFeedback.FireUpdate(); + if (inputStream == Tx.HdmiInputs[2]) HdmiIn2HdcpCapabilityFeedback.FireUpdate(); + HdcpStateFeedback.FireUpdate(); + break; + case EndpointInputStreamEventIds.SyncDetectedFeedbackEventId: + if (inputStream == Tx.HdmiInputs[1]) Hdmi1VideoSyncFeedback.FireUpdate(); + if (inputStream == Tx.HdmiInputs[2]) Hdmi2VideoSyncFeedback.FireUpdate(); + break; + } } void Tx_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) @@ -363,57 +370,57 @@ namespace PepperDash.Essentials.DM OnSwitchChange(new RoutingNumericEventArgs(1, AudioSourceNumericFeedback.UShortValue, OutputPorts.First(), localInputAudioPort, eRoutingSignalType.Audio)); break; } - } - - /// - /// Relays the input stream change to the appropriate RoutingInputPort. - /// - void FowardInputStreamChange(RoutingInputPortWithVideoStatuses inputPort, int eventId) - { - if (eventId != EndpointInputStreamEventIds.SyncDetectedFeedbackEventId) return; - inputPort.VideoStatus.VideoSyncFeedback.FireUpdate(); - AnyVideoInput.VideoStatus.VideoSyncFeedback.FireUpdate(); - } - - /// - /// Relays the VideoAttributes change to a RoutingInputPort - /// - void ForwardVideoAttributeChange(RoutingInputPortWithVideoStatuses inputPort, int eventId) - { - //// LOCATION: Crestron.SimplSharpPro.DM.VideoAttributeEventIds - //Debug.Console(2, this, "VideoAttributes_AttributeChange event id={0} from {1}", - // args.EventId, (sender as VideoAttributesEnhanced).Owner.GetType()); - switch (eventId) - { - case VideoAttributeEventIds.HdcpActiveFeedbackEventId: - inputPort.VideoStatus.HdcpActiveFeedback.FireUpdate(); - AnyVideoInput.VideoStatus.HdcpActiveFeedback.FireUpdate(); - break; - case VideoAttributeEventIds.HdcpStateFeedbackEventId: - inputPort.VideoStatus.HdcpStateFeedback.FireUpdate(); - AnyVideoInput.VideoStatus.HdcpStateFeedback.FireUpdate(); - break; - case VideoAttributeEventIds.HorizontalResolutionFeedbackEventId: - case VideoAttributeEventIds.VerticalResolutionFeedbackEventId: - inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate(); - AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate(); - break; - case VideoAttributeEventIds.FramesPerSecondFeedbackEventId: - inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate(); - AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate(); - break; - } - } - - - #region IIROutputPorts Members - public CrestronCollection IROutputPorts { get { return Tx.IROutputPorts; } } - public int NumberOfIROutputPorts { get { return Tx.NumberOfIROutputPorts; } } - #endregion - - #region IComPorts Members - public CrestronCollection ComPorts { get { return Tx.ComPorts; } } - public int NumberOfComPorts { get { return Tx.NumberOfComPorts; } } - #endregion - } + } + + /// + /// Relays the input stream change to the appropriate RoutingInputPort. + /// + void FowardInputStreamChange(RoutingInputPortWithVideoStatuses inputPort, int eventId) + { + if (eventId != EndpointInputStreamEventIds.SyncDetectedFeedbackEventId) return; + inputPort.VideoStatus.VideoSyncFeedback.FireUpdate(); + AnyVideoInput.VideoStatus.VideoSyncFeedback.FireUpdate(); + } + + /// + /// Relays the VideoAttributes change to a RoutingInputPort + /// + void ForwardVideoAttributeChange(RoutingInputPortWithVideoStatuses inputPort, int eventId) + { + //// LOCATION: Crestron.SimplSharpPro.DM.VideoAttributeEventIds + //Debug.Console(2, this, "VideoAttributes_AttributeChange event id={0} from {1}", + // args.EventId, (sender as VideoAttributesEnhanced).Owner.GetType()); + switch (eventId) + { + case VideoAttributeEventIds.HdcpActiveFeedbackEventId: + inputPort.VideoStatus.HdcpActiveFeedback.FireUpdate(); + AnyVideoInput.VideoStatus.HdcpActiveFeedback.FireUpdate(); + break; + case VideoAttributeEventIds.HdcpStateFeedbackEventId: + inputPort.VideoStatus.HdcpStateFeedback.FireUpdate(); + AnyVideoInput.VideoStatus.HdcpStateFeedback.FireUpdate(); + break; + case VideoAttributeEventIds.HorizontalResolutionFeedbackEventId: + case VideoAttributeEventIds.VerticalResolutionFeedbackEventId: + inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate(); + AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate(); + break; + case VideoAttributeEventIds.FramesPerSecondFeedbackEventId: + inputPort.VideoStatus.VideoResolutionFeedback.FireUpdate(); + AnyVideoInput.VideoStatus.VideoResolutionFeedback.FireUpdate(); + break; + } + } + + + #region IIROutputPorts Members + public CrestronCollection IROutputPorts { get { return Tx.IROutputPorts; } } + public int NumberOfIROutputPorts { get { return Tx.NumberOfIROutputPorts; } } + #endregion + + #region IComPorts Members + public CrestronCollection ComPorts { get { return Tx.ComPorts; } } + public int NumberOfComPorts { get { return Tx.NumberOfComPorts; } } + #endregion + } } \ No newline at end of file From 91abe4c09a78c904193a285692e6170c7922c22a Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 7 Jan 2021 15:23:35 -0700 Subject: [PATCH 59/59] Updates to IR files and Enter command --- IR Drivers/Comcast X1.ir | Bin 3757 -> 3757 bytes IR Drivers/DirecTV H21.ir | Bin 3854 -> 3872 bytes .../SetTopBox/IRSetTopBoxBase.cs | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/IR Drivers/Comcast X1.ir b/IR Drivers/Comcast X1.ir index bff5afff90cd427859f081cb3ae4b0ec91ce3004..4f6c638e63b27f78ee33fd30f295b789b8b7c2b0 100644 GIT binary patch delta 16 XcmZ20yH<8WD664?xsl<nYguCN_1FC Pby>>wSjsjo%Hab54CfFe delta 41 xcmZ1=*C!{!^1(BR