From 6b8aa0afe6ce11ea41af094d18876bb2b5d5d22d Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Thu, 2 Jul 2020 15:11:07 -0600 Subject: [PATCH] refactoring Fusion room classes added DualDisplay Fusion support --- .../EssentialsHuddleVtc1FusionController.cs | 768 ++++--- ...lsHuddleSpaceFusionSystemControllerBase.cs | 1845 +++++++++-------- .../EssentialsHuddleVtc1FusionController.cs | 225 ++ .../Fusion/FusionCustomPropertiesBridge.cs | 22 +- 4 files changed, 1641 insertions(+), 1219 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleVtc1FusionController.cs diff --git a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs index 0716775e..722698a7 100644 --- a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs +++ b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs @@ -1,341 +1,429 @@ -using System; -using System.Linq; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.Fusion; - - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.Fusion; - -namespace PepperDash.Essentials.Fusion -{ - public class EssentialsHuddleVtc1FusionController : EssentialsHuddleSpaceFusionSystemControllerBase - { - BooleanSigData CodecIsInCall; - - public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId) - : base(room, ipId) - { - - } - - /// - /// Called in base class constructor before RVI and GUID files are built - /// - protected override void ExecuteCustomSteps() - { - SetUpCodec(); - } - - /// - /// Creates a static asset for the codec and maps the joins to the main room symbol - /// - void SetUpCodec() - { - try - { - var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec; - - if (codec == null) - { - Debug.Console(1, this, "Cannot link codec to Fusion because codec is null"); - return; - } - - codec.UsageTracker = new UsageTracking(codec); - codec.UsageTracker.UsageIsTracked = true; - codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; - - var codecPowerOnAction = new Action(b => { if (!b) codec.StandbyDeactivate(); }); - var codecPowerOffAction = new Action(b => { if (!b) codec.StandbyActivate(); }); - - // Map FusionRoom Attributes: - - // Codec volume - var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig); - codecVolume.OutputSig.UserObject = new Action(b => (codec as IBasicVolumeWithFeedback).SetVolume(b)); - (codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig); - - // In Call Status - CodecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly); - codec.CallStatusChange += new EventHandler(codec_CallStatusChange); - - // Online status - if (codec is ICommunicationMonitor) - { - var c = codec as ICommunicationMonitor; - var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly); - codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk; - c.CommunicationMonitor.StatusChange += (o, a) => - { - codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; - }; - Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key, "Online - VC 1"); - } - - // Codec IP Address - bool codecHasIpInfo = false; - var codecComm = codec.Communication; - - string codecIpAddress = string.Empty; - int codecIpPort = 0; - - StringSigData codecIpAddressSig; - StringSigData codecIpPortSig; - - if(codecComm is GenericSshClient) - { - codecIpAddress = (codecComm as GenericSshClient).Hostname; - codecIpPort = (codecComm as GenericSshClient).Port; - codecHasIpInfo = true; - } - else if (codecComm is GenericTcpIpClient) - { - codecIpAddress = (codecComm as GenericTcpIpClient).Hostname; - codecIpPort = (codecComm as GenericTcpIpClient).Port; - codecHasIpInfo = true; - } - - if (codecHasIpInfo) - { - codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC", eSigIoMask.InputSigOnly); - codecIpAddressSig.InputSig.StringValue = codecIpAddress; - - codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC", eSigIoMask.InputSigOnly); - codecIpPortSig.InputSig.StringValue = codecIpPort.ToString(); - } - - var tempAsset = new FusionAsset(); - - var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key)); - - if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) - { - tempAsset = FusionStaticAssets[deviceConfig.Uid]; - } - else - { - // Create a new asset - tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name, "Codec", ""); - FusionStaticAssets.Add(deviceConfig.Uid, tempAsset); - } - - var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", tempAsset.InstanceId); - codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction; - codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction; - codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig); - - // TODO: Map relevant attributes on asset symbol - - codecAsset.TrySetMakeModel(codec); - codecAsset.TryLinkAssetErrorToCommunication(codec); - } - catch (Exception e) - { - Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e); - } - } - - void codec_CallStatusChange(object sender, Core.Devices.Codec.CodecCallStatusItemChangeEventArgs e) - { - var codec = (Room as EssentialsHuddleVtc1Room).VideoCodec; - - CodecIsInCall.InputSig.BoolValue = codec.IsInCall; - } - - // These methods are overridden because they access the room class which is of a different type - - protected override void CreateSymbolAndBasicSigs(uint ipId) - { - Debug.Console(1, this, "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.FusionStateChange += FusionRoom_FusionStateChange; - - 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); - - // 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 EssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange; - - - FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource); - FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction(() => (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey)); - // NO!! room.RoomIsOn.LinkComplementInputSig(FusionRoom.SystemPowerOff.InputSig); - - - CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; - } - - protected override void SetUpSources() - { - // Sources - var dict = ConfigReader.ConfigObject.GetSourceListForKey((Room as EssentialsHuddleVtc1Room).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 Core.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) - { - var usageDevice = kvp.Value.SourceDevice as IUsageTracking; - - if (usageDevice != null) - { - usageDevice.UsageTracker = new UsageTracking(usageDevice as Device); - usageDevice.UsageTracker.UsageIsTracked = true; - usageDevice.UsageTracker.DeviceUsageEnded += new EventHandler(UsageTracker_DeviceUsageEnded); - } - } - - } - else - { - Debug.Console(1, this, "WARNING: Config source list '{0}' not found for room '{1}'", - (Room as EssentialsHuddleVtc1Room).SourceListKey, Room.Key); - } - } - - protected override void SetUpDisplay() - { - try - { - //Setup Display Usage Monitoring - - var displays = DeviceManager.AllDevices.Where(d => d is DisplayBase); - - // Consider updating this in multiple display systems - - foreach (DisplayBase display in displays) - { - display.UsageTracker = new UsageTracking(display); - display.UsageTracker.UsageIsTracked = true; - display.UsageTracker.DeviceUsageEnded += new EventHandler(UsageTracker_DeviceUsageEnded); - } - - var defaultDisplay = (Room as EssentialsHuddleVtc1Room).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(); }); - - // Display to fusion room sigs - FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction; - FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction; - defaultDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig); - if (defaultDisplay is IDisplayUsage) - (defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig); - - - - MapDisplayToRoomJoins(1, 158, defaultDisplay); - - - var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); - - //Check for existing asset in GUIDs collection - - var tempAsset = new FusionAsset(); - - if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) - { - tempAsset = FusionStaticAssets[deviceConfig.Uid]; - } - else - { - // Create a new asset - 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); - dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; - dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; - defaultDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig); - // NO!! display.PowerIsOn.LinkComplementInputSig(dispAsset.PowerOff.InputSig); - // Use extension methods - dispAsset.TrySetMakeModel(defaultDisplay); - dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay); - } - catch (Exception e) - { - Debug.Console(1, this, "Error setting up display in Fusion: {0}", e); - } - - } - - protected override void MapDisplayToRoomJoins(int displayIndex, int joinOffset, DisplayBase display) - { - string displayName = string.Format("Display {0} - ", displayIndex); - - - if (display == (Room as EssentialsHuddleVtc1Room).DefaultDisplay) - { - // Power on - var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig); - defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => { if (!b) display.PowerOn(); }); - display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); - - // Power Off - var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 1, displayName + "Power Off", eSigIoMask.InputOutputSig); - defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => { if (!b) display.PowerOff(); }); ; - display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); - - // Current Source - var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig); - defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { if (!b) (Room as EssentialsHuddleVtc1Room).RunRouteAction("roomOff", Room.SourceListKey); }); ; - } - } - } +using System; +using System.Linq; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.Fusion; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.Fusion; + +namespace PepperDash.Essentials.Fusion +{ + public class EssentialsHuddleVtc1FusionController : EssentialsHuddleSpaceFusionSystemControllerBase + { + private BooleanSigData _codecIsInCall; + + public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId) + : base(room, ipId) + { + } + + /// + /// Called in base class constructor before RVI and GUID files are built + /// + protected override void ExecuteCustomSteps() + { + SetUpCodec(); + } + + /// + /// Creates a static asset for the codec and maps the joins to the main room symbol + /// + private void SetUpCodec() + { + try + { + var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room; + if (essentialsHuddleVtc1Room == null) + { + return; + } + + var codec = essentialsHuddleVtc1Room.VideoCodec; + + if (codec == null) + { + Debug.Console(1, this, "Cannot link codec to Fusion because codec is null"); + return; + } + + codec.UsageTracker = new UsageTracking(codec) {UsageIsTracked = true}; + codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; + + var codecPowerOnAction = new Action(b => + { + if (!b) + { + codec.StandbyDeactivate(); + } + }); + var codecPowerOffAction = new Action(b => + { + if (!b) + { + codec.StandbyActivate(); + } + }); + + // Map FusionRoom Attributes: + + // Codec volume + var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig); + codecVolume.OutputSig.UserObject = + new Action(b => (codec as IBasicVolumeWithFeedback).SetVolume(b)); + (codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig); + + // In Call Status + _codecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly); + codec.CallStatusChange += codec_CallStatusChange; + + // Online status + if (codec is ICommunicationMonitor) + { + var c = codec as ICommunicationMonitor; + var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly); + codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk; + c.CommunicationMonitor.StatusChange += + (o, a) => { codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; }; + Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key, + "Online - VC 1"); + } + + // Codec IP Address + bool codecHasIpInfo = false; + var codecComm = codec.Communication; + + string codecIpAddress = string.Empty; + int codecIpPort = 0; + + if (codecComm is GenericSshClient) + { + codecIpAddress = (codecComm as GenericSshClient).Hostname; + codecIpPort = (codecComm as GenericSshClient).Port; + codecHasIpInfo = true; + } + else if (codecComm is GenericTcpIpClient) + { + codecIpAddress = (codecComm as GenericTcpIpClient).Hostname; + codecIpPort = (codecComm as GenericTcpIpClient).Port; + codecHasIpInfo = true; + } + + if (codecHasIpInfo) + { + StringSigData codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC", + eSigIoMask.InputSigOnly); + codecIpAddressSig.InputSig.StringValue = codecIpAddress; + + StringSigData codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC", + eSigIoMask.InputSigOnly); + codecIpPortSig.InputSig.StringValue = codecIpPort.ToString(); + } + + FusionAsset tempAsset; + + var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key)); + + if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) + { + tempAsset = FusionStaticAssets[deviceConfig.Uid]; + } + else + { + // Create a new asset + tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name, + "Codec", ""); + FusionStaticAssets.Add(deviceConfig.Uid, tempAsset); + } + + var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", + tempAsset.InstanceId); + codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction; + codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction; + codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig); + + // TODO: Map relevant attributes on asset symbol + + codecAsset.TrySetMakeModel(codec); + codecAsset.TryLinkAssetErrorToCommunication(codec); + } + catch (Exception e) + { + Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e); + } + } + + private void codec_CallStatusChange(object sender, Core.Devices.Codec.CodecCallStatusItemChangeEventArgs e) + { + var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room; + if (essentialsHuddleVtc1Room == null) + { + return; + } + var codec = essentialsHuddleVtc1Room.VideoCodec; + + _codecIsInCall.InputSig.BoolValue = codec.IsInCall; + } + + // These methods are overridden because they access the room class which is of a different type + + protected override void CreateSymbolAndBasicSigs(uint ipId) + { + Debug.Console(1, this, "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.FusionStateChange += FusionRoom_FusionStateChange; + + 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(CreateAdHocMeeting, "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); + + // 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. + + var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room; + if (essentialsHuddleVtc1Room != null) + { + essentialsHuddleVtc1Room.CurrentSourceChange += Room_CurrentSourceInfoChange; + FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction( + essentialsHuddleVtc1Room.PowerOnToDefaultOrLastSource); + FusionRoom.SystemPowerOff.OutputSig.SetSigFalseAction( + () => essentialsHuddleVtc1Room.RunRouteAction("roomOff", Room.SourceListKey)); + } + + CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; + } + + protected override void SetUpSources() + { + // Sources + var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room; + + if (essentialsHuddleVtc1Room == null) + { + return; + } + + var dict = ConfigReader.ConfigObject.GetSourceListForKey(essentialsHuddleVtc1Room.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 Core.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}'", + essentialsHuddleVtc1Room.SourceListKey, Room.Key); + } + } + + protected override void SetUpDisplay() + { + try + { + //Setup Display Usage Monitoring + + var displays = DeviceManager.AllDevices.Where(d => d is DisplayBase); + + // Consider updating this in multiple display systems + + foreach (var display in displays.Cast()) + { + display.UsageTracker = new UsageTracking(display) {UsageIsTracked = true}; + display.UsageTracker.DeviceUsageEnded += + UsageTracker_DeviceUsageEnded; + } + + var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room; + if (essentialsHuddleVtc1Room == null) + { + return; + } + + var defaultDisplay = essentialsHuddleVtc1Room.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(); + } + }); + + // Display to fusion room sigs + FusionRoom.DisplayPowerOn.OutputSig.UserObject = dispPowerOnAction; + FusionRoom.DisplayPowerOff.OutputSig.UserObject = dispPowerOffAction; + defaultDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig); + if (defaultDisplay is IDisplayUsage) + { + (defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig); + } + + + MapDisplayToRoomJoins(1, 158, defaultDisplay); + + + var deviceConfig = + ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); + + //Check for existing asset in GUIDs collection + + FusionAsset tempAsset; + + if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) + { + tempAsset = FusionStaticAssets[deviceConfig.Uid]; + } + else + { + // Create a new asset + 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); + dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; + dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; + defaultDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig); + // NO!! display.PowerIsOn.LinkComplementInputSig(dispAsset.PowerOff.InputSig); + // Use extension methods + dispAsset.TrySetMakeModel(defaultDisplay); + dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay); + } + catch (Exception e) + { + Debug.Console(1, this, "Error setting up display in Fusion: {0}", e); + } + } + + protected override void MapDisplayToRoomJoins(int displayIndex, int joinOffset, DisplayBase display) + { + var displayName = string.Format("Display {0} - ", displayIndex); + + + var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room; + if (essentialsHuddleVtc1Room == null || display != essentialsHuddleVtc1Room.DefaultDisplay) + { + return; + } + // Power on + var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint) joinOffset, displayName + "Power On", + eSigIoMask.InputOutputSig); + defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => + { + if (!b) + { + display.PowerOn(); + } + }); + display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); + + // Power Off + + FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 1, + displayName + "Power Off", eSigIoMask.InputOutputSig); + defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => + { + if (!b) + { + display.PowerOff(); + } + }); + + display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); + + // Current Source + var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 8, + displayName + "Source None", eSigIoMask.InputOutputSig); + defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => + { + if (b) + { + return; + } + var huddleVtc1Room = Room as EssentialsHuddleVtc1Room; + if (huddleVtc1Room != null) + { + huddleVtc1Room.RunRouteAction("roomOff", Room.SourceListKey); + } + }); + } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index c46290a2..d2ead037 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -2,164 +2,120 @@ 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; using PepperDash.Essentials.Core.Rooms; - 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 : EssentialsDevice, IOccupancyStatusProvider + { + private const string RemoteOccupancyXml = "Local{0}"; + private readonly bool _guidFileExists; - public event EventHandler RoomInfoChange; + private readonly Dictionary _sourceToFeedbackSigs = + new Dictionary(); + private Event _currentMeeting; + + protected StringSigData CurrentRoomSourceNameSig; + + private RoomSchedule _currentSchedule; public FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge(); + private CTimer _dailyTimeRequestTimer; + protected FusionOccupancySensorAsset FusionOccSensor; + protected FusionRemoteOccupancySensor FusionRemoteOccSensor; + protected FusionRoom FusionRoom; + protected Dictionary FusionStaticAssets; - protected FusionRoom FusionRoom; - protected EssentialsRoomBase Room; - Dictionary SourceToFeedbackSigs = - new Dictionary(); + private FusionRoomGuids _guiDs; + private uint _ipId; - StatusMonitorCollection ErrorMessageRollUp; + private bool _isRegisteredForSchedulePushNotifications; + private Event _nextMeeting; - protected StringSigData CurrentRoomSourceNameSig; + private CTimer _pollTimer; + public long PushNotificationTimeout = 5000; + + private CTimer _pushNotificationTimer; + protected EssentialsRoomBase Room; + + // Default poll time is 5 min unless overridden by config value + public long SchedulePollInterval = 300000; + private StatusMonitorCollection _errorMessageRollUp; + + 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 { @@ -167,52 +123,79 @@ namespace PepperDash.Essentials.Core.Fusion ReadGuidFile(guidFilePath); } + Initialize(); + if (Room.RoomOccupancy != null) { if (Room.OccupancyStatusProviderIsRemote) + { SetUpRemoteOccupancy(); + } else { SetUpLocalOccupancy(); } } - - - AddPostActivationAction(() => - { - CreateSymbolAndBasicSigs(IpId); - SetUpSources(); - SetUpCommunitcationMonitors(); - SetUpDisplay(); - SetUpError(); - ExecuteCustomSteps(); - - FusionRVI.GenerateFileForAllFusionDevices(); - - GenerateGuidFile(guidFilePath); - }); + // Make it so! + FusionRVI.GenerateFileForAllFusionDevices(); + 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() { + } + protected void Initialize() + { + CreateSymbolAndBasicSigs(_ipId); + SetUpSources(); + SetUpCommunitcationMonitors(); + SetUpDisplay(); + SetUpError(); + 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 +203,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 +236,10 @@ namespace PepperDash.Essentials.Core.Fusion } finally { - if (_fileLock != null && !_fileLock.Disposed) - _fileLock.Leave(); + if (!fileLock.Disposed) + { + fileLock.Leave(); + } } } @@ -262,42 +247,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 +294,68 @@ 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(CreateAdHocMeeting, "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 +365,8 @@ namespace PepperDash.Essentials.Core.Fusion GetProcessorInfo(); - CrestronEnvironment.EthernetEventHandler += new EthernetEventHandler(CrestronEnvironment_EthernetEventHandler); + CrestronEnvironment.EthernetEventHandler += + CrestronEnvironment_EthernetEventHandler; } protected void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) @@ -372,82 +383,106 @@ 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 +495,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 +533,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 +551,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 +562,79 @@ 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]; + //var meetingId = tokens[0]; never used, commenting out for now 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,47 +644,45 @@ namespace PepperDash.Essentials.Core.Fusion { Debug.Console(1, this, "Invalid time specified"); } - - } /// /// Creates and Ad Hoc meeting with a duration of 1 hour, or until the next meeting if in less than 1 hour. /// - public void CreateAsHocMeeting(string command) + public void CreateAdHocMeeting(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 +692,6 @@ namespace PepperDash.Essentials.Core.Fusion //Debug.Console(1, this, "Sending CreateMeeting Request: \n{0}", command); //FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = command; - } /// @@ -667,73 +699,71 @@ 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; + } + var requestId = actionResponse["RequestID"]; - if (requestID.InnerText == "InitialPushRequest") + 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 +776,7 @@ namespace PepperDash.Essentials.Core.Fusion { try { - XmlDocument message = new XmlDocument(); + var message = new XmlDocument(); message.LoadXml(args.Sig.StringValue); @@ -759,13 +789,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 +812,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 +826,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,11 +840,11 @@ namespace PepperDash.Essentials.Core.Fusion { foreach (XmlElement el in e) { - FusionCustomProperty customProperty = new FusionCustomProperty(); + var customProperty = new FusionCustomProperty(); if (el.Name == "CustomField") { - customProperty.ID = el.Attributes["ID"].Value; + customProperty.Id = el.Attributes["ID"].Value; } foreach (XmlElement elm in el) @@ -838,7 +870,9 @@ namespace PepperDash.Essentials.Core.Fusion var handler = RoomInfoChange; if (handler != null) + { handler(this, new EventArgs()); + } CustomPropertiesBridge.EvaluateRoomInfo(Room.Key, roomInformation); } @@ -851,7 +885,6 @@ namespace PepperDash.Essentials.Core.Fusion //getRoomInfoBusy = false; //_DynFusion.API.EISC.BooleanInput[Constants.GetRoomInfo].BoolValue = getRoomInfoBusy; } - } /// @@ -859,130 +892,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 +1025,63 @@ 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 +1089,33 @@ 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)); + //var configDevice = ConfigReader.ConfigObject.Devices.Where(d => d.Key.Equals(deviceTracker.Parent)); never used... - string group = ConfigReader.GetGroupForDeviceKey(deviceTracker.Parent.Key); + if (deviceTracker == null) + { + return; + } - string currentMeetingId = "-"; + var group = ConfigReader.GetGroupForDeviceKey(deviceTracker.Parent.Key); - if (CurrentMeeting != null) - currentMeetingId = CurrentMeeting.MeetingID; + var currentMeetingId = "-"; + + 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 +1123,52 @@ 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 +1191,9 @@ namespace PepperDash.Essentials.Core.Fusion attrNum = attrNum + touchpanelNum; if (attrNum > 10) + { continue; + } attrName = "Online - XPanel " + attrNum; attrNum += 160; @@ -1152,7 +1204,9 @@ namespace PepperDash.Essentials.Core.Fusion attrNum = attrNum + xpanelNum; if (attrNum > 10) + { continue; + } attrName = "Online - Touch Panel " + attrNum; attrNum += 150; @@ -1160,45 +1214,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,418 +1263,471 @@ 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; + defaultDisplay.PowerIsOnFeedback.LinkInputSig(FusionRoom.DisplayPowerOn.InputSig); + if (defaultDisplay is IDisplayUsage) + { + (defaultDisplay as IDisplayUsage).LampHours.LinkInputSig(FusionRoom.DisplayUsage.InputSig); + } + MapDisplayToRoomJoins(1, 158, defaultDisplay); - var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); - - //Check for existing asset in GUIDs collection - - var tempAsset = new FusionAsset(); - - if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) - { - tempAsset = FusionStaticAssets[deviceConfig.Uid]; - } - else - { - // Create a new asset - 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); - dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; - dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; - - var defaultTwoWayDisplay = defaultDisplay as IHasPowerControlWithFeedback; - if (defaultTwoWayDisplay != null) - { - 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 - dispAsset.TrySetMakeModel(defaultDisplay); - dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay); + } catch (Exception e) { 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) - { - 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) (Room as IRunRouteAction).RunRouteAction("roomOff", Room.SourceListKey); }); ; + 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) + { + basicVolumeWithFeedback.SetVolume(b); + } + }); + var volumeWithFeedback = display as IBasicVolumeWithFeedback; + if (volumeWithFeedback != null) + { + volumeWithFeedback.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(); + } + }); + display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); + + // Power Off + //var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 1,displayName + "Power Off", eSigIoMask.InputOutputSig); //not used + defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => + { + if (!b) + { + display.PowerOff(); + } + }); + + display.PowerIsOnFeedback.LinkInputSig(defaultDisplayPowerOn.InputSig); + + // Current Source + var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 8, + displayName + "Source None", eSigIoMask.InputOutputSig); + defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => + { + if (b) + { + return; + } + 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 md in DeviceManager.GetDevices().OfType()) + { + _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); //not used + + // 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; + } - /// - /// 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; + return Convert.ToInt32(capture.Groups[1].Value); + } - 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; + /// + /// 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 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); + if (sigData != null) + { + var outSig = sigData.OutputSig; + if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.BoolValue); + } + else if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.UShortValue); + } + else if (outSig.UserObject is Action) + { + (outSig.UserObject as Action).Invoke(outSig.StringValue); + } + return; + } - var sigData = (args.UserConfiguredSigDetail as BooleanSigDataFixedName); - if (sigData != null) - { - var outSig = sigData.OutputSig; - if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.BoolValue); - else if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.UShortValue); - else if (outSig.UserObject is Action) - (outSig.UserObject as Action).Invoke(outSig.StringValue); - return; - } + var attrData = (args.UserConfiguredSigDetail as BooleanSigData); + if (attrData == null) + { + 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 aOutSig = attrData.OutputSig; + if (aOutSig.UserObject is Action) + { + (aOutSig.UserObject as Action).Invoke(aOutSig.BoolValue); + } + else if (aOutSig.UserObject is Action) + { + (aOutSig.UserObject as Action).Invoke(aOutSig.UShortValue); + } + else if (aOutSig.UserObject is Action) + { + (aOutSig.UserObject as Action).Invoke(aOutSig.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 string ID { get; set; } - public string Name { get; set; } - public string Location { get; set; } - public string Description { get; set; } - public string TimeZone { get; set; } - public string WebcamURL { get; set; } - public string BacklogMsg { get; set; } - public string SubErrorMsg { get; set; } - public string EmailInfo { get; set; } - public List FusionCustomProperties { get; set; } - public RoomInformation() { FusionCustomProperties = new List(); } + + public string Id { get; set; } + public string Name { get; set; } + public string Location { get; set; } + public string Description { get; set; } + public string TimeZone { get; set; } + public string WebcamUrl { get; set; } + public string BacklogMsg { get; set; } + public string SubErrorMsg { get; set; } + public string EmailInfo { get; set; } + public List FusionCustomProperties { get; set; } } + 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; + 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 diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleVtc1FusionController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleVtc1FusionController.cs new file mode 100644 index 00000000..84adc0f8 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleVtc1FusionController.cs @@ -0,0 +1,225 @@ +using System; +using System.Linq; +using Crestron.SimplSharpPro; +using PepperDash.Core; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials.Core.Fusion +{ + public class EssentialsHuddleVtc1FusionController : EssentialsHuddleSpaceFusionSystemControllerBase + { + private BooleanSigData _codecIsInCall; + + private readonly EssentialsHuddleVtc1Room _room; + + public EssentialsHuddleVtc1FusionController(EssentialsHuddleVtc1Room room, uint ipId) + : base(room, ipId) + { + _room = room; + } + + /// + /// Called in base class constructor before RVI and GUID files are built + /// + protected override void ExecuteCustomSteps() + { + SetUpCodec(); + base.ExecuteCustomSteps(); + } + + /// + /// Creates a static asset for the codec and maps the joins to the main room symbol + /// + private void SetUpCodec() + { + try + { + var essentialsHuddleVtc1Room = Room as EssentialsHuddleVtc1Room; + if (essentialsHuddleVtc1Room == null) + { + return; + } + + var codec = essentialsHuddleVtc1Room.VideoCodec; + + if (codec == null) + { + Debug.Console(1, this, "Cannot link codec to Fusion because codec is null"); + return; + } + + codec.UsageTracker = new UsageTracking(codec) {UsageIsTracked = true}; + codec.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; + + var codecPowerOnAction = new Action(b => + { + if (!b) + { + codec.StandbyDeactivate(); + } + }); + var codecPowerOffAction = new Action(b => + { + if (!b) + { + codec.StandbyActivate(); + } + }); + + // Map FusionRoom Attributes: + + // Codec volume + var codecVolume = FusionRoom.CreateOffsetUshortSig(50, "Volume - Fader01", eSigIoMask.InputOutputSig); + codecVolume.OutputSig.UserObject = + new Action(b => (codec as IBasicVolumeWithFeedback).SetVolume(b)); + (codec as IBasicVolumeWithFeedback).VolumeLevelFeedback.LinkInputSig(codecVolume.InputSig); + + // In Call Status + _codecIsInCall = FusionRoom.CreateOffsetBoolSig(69, "Conf - VC 1 In Call", eSigIoMask.InputSigOnly); + codec.CallStatusChange += codec_CallStatusChange; + + // Online status + if (codec is ICommunicationMonitor) + { + var c = codec as ICommunicationMonitor; + var codecOnline = FusionRoom.CreateOffsetBoolSig(122, "Online - VC 1", eSigIoMask.InputSigOnly); + codecOnline.InputSig.BoolValue = c.CommunicationMonitor.Status == MonitorStatus.IsOk; + c.CommunicationMonitor.StatusChange += + (o, a) => { codecOnline.InputSig.BoolValue = a.Status == MonitorStatus.IsOk; }; + Debug.Console(0, this, "Linking '{0}' communication monitor to Fusion '{1}'", codec.Key, + "Online - VC 1"); + } + + // Codec IP Address + var codecHasIpInfo = false; + var codecComm = codec.Communication; + + var codecIpAddress = string.Empty; + var codecIpPort = 0; + + if (codecComm is GenericSshClient) + { + codecIpAddress = (codecComm as GenericSshClient).Hostname; + codecIpPort = (codecComm as GenericSshClient).Port; + codecHasIpInfo = true; + } + else if (codecComm is GenericTcpIpClient) + { + codecIpAddress = (codecComm as GenericTcpIpClient).Hostname; + codecIpPort = (codecComm as GenericTcpIpClient).Port; + codecHasIpInfo = true; + } + + if (codecHasIpInfo) + { + var codecIpAddressSig = FusionRoom.CreateOffsetStringSig(121, "IP Address - VC", + eSigIoMask.InputSigOnly); + codecIpAddressSig.InputSig.StringValue = codecIpAddress; + + var codecIpPortSig = FusionRoom.CreateOffsetStringSig(150, "IP Port - VC", + eSigIoMask.InputSigOnly); + codecIpPortSig.InputSig.StringValue = codecIpPort.ToString(); + } + + FusionAsset tempAsset; + + var deviceConfig = ConfigReader.ConfigObject.Devices.FirstOrDefault(c => c.Key.Equals(codec.Key)); + + if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) + { + tempAsset = FusionStaticAssets[deviceConfig.Uid]; + } + else + { + // Create a new asset + tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), codec.Name, + "Codec", ""); + FusionStaticAssets.Add(deviceConfig.Uid, tempAsset); + } + + var codecAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", + tempAsset.InstanceId); + codecAsset.PowerOn.OutputSig.UserObject = codecPowerOnAction; + codecAsset.PowerOff.OutputSig.UserObject = codecPowerOffAction; + codec.StandbyIsOnFeedback.LinkComplementInputSig(codecAsset.PowerOn.InputSig); + + // TODO: Map relevant attributes on asset symbol + + codecAsset.TrySetMakeModel(codec); + codecAsset.TryLinkAssetErrorToCommunication(codec); + } + catch (Exception e) + { + Debug.Console(1, this, "Error setting up codec in Fusion: {0}", e); + } + } + + #region Overrides of EssentialsHuddleSpaceFusionSystemControllerBase + + protected override void SetUpDisplay() + { + base.SetUpDisplay(); + + var defaultDisplay = _room.DefaultDisplay as DisplayBase; + + if (defaultDisplay == null) + { + Debug.Console(1, this, "Cannot link null display to Fusion because default display is null"); + return; + } + + var deviceConfig = + ConfigReader.ConfigObject.Devices.FirstOrDefault(d => d.Key.Equals(defaultDisplay.Key)); + + //Check for existing asset in GUIDs collection + + FusionAsset tempAsset; + + if (FusionStaticAssets.ContainsKey(deviceConfig.Uid)) + { + tempAsset = FusionStaticAssets[deviceConfig.Uid]; + } + else + { + // Create a new asset + tempAsset = new FusionAsset(FusionRoomGuids.GetNextAvailableAssetNumber(FusionRoom), + defaultDisplay.Name, "Display", ""); + FusionStaticAssets.Add(deviceConfig.Uid, tempAsset); + } + + var dispPowerOnAction = new Action(b => + { + if (!b) + { + defaultDisplay.PowerOn(); + } + }); + var dispPowerOffAction = new Action(b => + { + if (!b) + { + defaultDisplay.PowerOff(); + } + }); + + var dispAsset = FusionRoom.CreateStaticAsset(tempAsset.SlotNumber, tempAsset.Name, "Display", + tempAsset.InstanceId); + dispAsset.PowerOn.OutputSig.UserObject = dispPowerOnAction; + dispAsset.PowerOff.OutputSig.UserObject = dispPowerOffAction; + defaultDisplay.PowerIsOnFeedback.LinkInputSig(dispAsset.PowerOn.InputSig); + // NO!! display.PowerIsOn.LinkComplementInputSig(dispAsset.PowerOff.InputSig); + // Use extension methods + dispAsset.TrySetMakeModel(defaultDisplay); + dispAsset.TryLinkAssetErrorToCommunication(defaultDisplay); + } + + #endregion + + private void codec_CallStatusChange(object sender, Devices.Codec.CodecCallStatusItemChangeEventArgs e) + { + var codec = _room.VideoCodec; + + _codecIsInCall.InputSig.BoolValue = codec.IsInCall; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs index 99ced5ea..a650354d 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/FusionCustomPropertiesBridge.cs @@ -41,43 +41,43 @@ namespace PepperDash.Essentials.Core.Fusion var devProps = JsonConvert.DeserializeObject(deviceConfig.Properties.ToString()); - var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupied")); + var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupied")); if (enableFeature != null) devProps.EnableRoomOnWhenOccupied = bool.Parse(enableFeature.CustomFieldValue); - var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedStartTime")); + var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("RoomOnWhenOccupiedStartTime")); if (enableTime != null) devProps.OccupancyStartTime = enableTime.CustomFieldValue; - var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedEndTime")); + var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("RoomOnWhenOccupiedEndTime")); if (disableTime != null) devProps.OccupancyEndTime = disableTime.CustomFieldValue; - var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSun")); + var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedSun")); if (enableSunday != null) devProps.EnableSunday = bool.Parse(enableSunday.CustomFieldValue); - var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedMon")); + var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedMon")); if (enableMonday != null) devProps.EnableMonday = bool.Parse(enableMonday.CustomFieldValue); - var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedTue")); + var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedTue")); if (enableTuesday != null) devProps.EnableTuesday = bool.Parse(enableTuesday.CustomFieldValue); - var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedWed")); + var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedWed")); if (enableWednesday != null) devProps.EnableWednesday = bool.Parse(enableWednesday.CustomFieldValue); - var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedThu")); + var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedThu")); if (enableThursday != null) devProps.EnableThursday = bool.Parse(enableThursday.CustomFieldValue); - var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedFri")); + var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedFri")); if (enableFriday != null) devProps.EnableFriday = bool.Parse(enableFriday.CustomFieldValue); - var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSat")); + var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("EnRoomOnWhenOccupiedSat")); if (enableSaturday != null) devProps.EnableSaturday = bool.Parse(enableSaturday.CustomFieldValue); @@ -96,7 +96,7 @@ namespace PepperDash.Essentials.Core.Fusion } // Set the help message - var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage")); + var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.Id.Equals("RoomHelpMessage")); if (helpMessage != null) { //Debug.Console(1, "Current Help Message: {0}. New Help Message: {1}", deviceConfig.Properties["help"]["message"].Value(ToString()), helpMessage.CustomFieldValue);