diff --git a/.gitignore b/.gitignore index db1e92a3..d64977d6 100644 --- a/.gitignore +++ b/.gitignore @@ -396,3 +396,4 @@ _site/ api/ *.DS_Store /._PepperDash.Essentials.4Series.sln +dotnet diff --git a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs index d6a7bffa..ba638623 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs +++ b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceRoomFusionRoomJoinMap.cs @@ -16,121 +16,201 @@ namespace PepperDash.Essentials.Core.Fusion { // Processor Attributes + /// + /// Processor IP 1 + /// [JoinName("ProcessorIp1")] public JoinDataComplete ProcessorIp1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Info - Processor - IP 1" }, new JoinMetadata { Description = "Info - Processor - IP 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor IP 2 + /// [JoinName("ProcessorIp2")] public JoinDataComplete ProcessorIp2 = new JoinDataComplete(new JoinData { JoinNumber = 51, JoinSpan = 1, AttributeName = "Info - Processor - IP 2" }, new JoinMetadata { Description = "Info - Processor - IP 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor Gateway + /// [JoinName("ProcessorGateway")] public JoinDataComplete ProcessorGateway = new JoinDataComplete(new JoinData { JoinNumber = 52, JoinSpan = 1, AttributeName = "Info - Processor - Gateway" }, new JoinMetadata { Description = "Info - Processor - Gateway", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor Hostname + /// [JoinName("ProcessorHostname")] public JoinDataComplete ProcessorHostname = new JoinDataComplete(new JoinData { JoinNumber = 53, JoinSpan = 1, AttributeName = "Info - Processor - Hostname" }, new JoinMetadata { Description = "Info - Processor - Hostname", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor Domain + /// [JoinName("ProcessorDomain")] public JoinDataComplete ProcessorDomain = new JoinDataComplete(new JoinData { JoinNumber = 54, JoinSpan = 1, AttributeName = "Info - Processor - Domain" }, new JoinMetadata { Description = "Info - Processor - Domain", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor DNS 1 + /// [JoinName("ProcessorDns1")] public JoinDataComplete ProcessorDns1 = new JoinDataComplete(new JoinData { JoinNumber = 55, JoinSpan = 1, AttributeName = "Info - Processor - DNS 1" }, new JoinMetadata { Description = "Info - Processor - DNS 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor DNS 2 + /// [JoinName("ProcessorDns2")] public JoinDataComplete ProcessorDns2 = new JoinDataComplete(new JoinData { JoinNumber = 56, JoinSpan = 1, AttributeName = "Info - Processor - DNS 2" }, new JoinMetadata { Description = "Info - Processor - DNS 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor MAC 1 + /// [JoinName("ProcessorMac1")] public JoinDataComplete ProcessorMac1 = new JoinDataComplete(new JoinData { JoinNumber = 57, JoinSpan = 1, AttributeName = "Info - Processor - MAC 1" }, new JoinMetadata { Description = "Info - Processor - MAC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor MAC 2 + /// [JoinName("ProcessorMac2")] public JoinDataComplete ProcessorMac2 = new JoinDataComplete(new JoinData { JoinNumber = 58, JoinSpan = 1, AttributeName = "Info - Processor - MAC 2" }, new JoinMetadata { Description = "Info - Processor - MAC 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor Net Mask 1 + /// [JoinName("ProcessorNetMask1")] public JoinDataComplete ProcessorNetMask1 = new JoinDataComplete(new JoinData { JoinNumber = 59, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 1" }, new JoinMetadata { Description = "Info - Processor - Net Mask 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor Net Mask 2 + /// [JoinName("ProcessorNetMask2")] public JoinDataComplete ProcessorNetMask2 = new JoinDataComplete(new JoinData { JoinNumber = 60, JoinSpan = 1, AttributeName = "Info - Processor - Net Mask 2" }, new JoinMetadata { Description = "Info - Processor - Net Mask 2", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor Firmware + /// [JoinName("ProcessorFirmware")] public JoinDataComplete ProcessorFirmware = new JoinDataComplete(new JoinData { JoinNumber = 61, JoinSpan = 1, AttributeName = "Info - Processor - Firmware" }, new JoinMetadata { Description = "Info - Processor - Firmware", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Program Name Start + /// [JoinName("ProgramNameStart")] public JoinDataComplete ProgramNameStart = new JoinDataComplete(new JoinData { JoinNumber = 62, JoinSpan = 10, AttributeName = "Info - Processor - Program" }, new JoinMetadata { Description = "Info - Processor - Program", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// Processor Reboot + /// [JoinName("ProcessorReboot")] public JoinDataComplete ProcessorReboot = new JoinDataComplete(new JoinData { JoinNumber = 74, JoinSpan = 1, AttributeName = "Processor - Reboot" }, new JoinMetadata { Description = "Processor - Reboot", JoinCapabilities = eJoinCapabilities.FromFusion, JoinType = eJoinType.Digital }); // Volume Controls + /// + /// Volume Fader 1 + /// [JoinName("VolumeFader1")] public JoinDataComplete VolumeFader1 = new JoinDataComplete(new JoinData { JoinNumber = 50, JoinSpan = 1, AttributeName = "Volume - Fader01" }, new JoinMetadata { Description = "Volume - Fader01", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Analog }); // Codec Info + /// + /// VC Codec In Call + /// [JoinName("VcCodecInCall")] public JoinDataComplete VcCodecInCall = new JoinDataComplete(new JoinData { JoinNumber = 69, JoinSpan = 1, AttributeName = "Conf - VC 1 In Call" }, new JoinMetadata { Description = "Conf - VC 1 In Call", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + /// + /// VC Codec Online + /// [JoinName("VcCodecOnline")] public JoinDataComplete VcCodecOnline = new JoinDataComplete(new JoinData { JoinNumber = 122, JoinSpan = 1, AttributeName = "Online - VC 1" }, new JoinMetadata { Description = "Online - VC 1", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + /// + /// VC Codec IP Address + /// [JoinName("VcCodecIpAddress")] public JoinDataComplete VcCodecIpAddress = new JoinDataComplete(new JoinData { JoinNumber = 121, JoinSpan = 1, AttributeName = "IP Address - VC" }, new JoinMetadata { Description = "IP Address - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); + /// + /// VC Codec IP Port + /// [JoinName("VcCodecIpPort")] public JoinDataComplete VcCodecIpPort = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 1, AttributeName = "IP Port - VC" }, new JoinMetadata { Description = "IP Port - VC", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); // Source Attributes + /// + /// Display 1 Current Source Name + /// [JoinName("Display1CurrentSourceName")] public JoinDataComplete Display1CurrentSourceName = new JoinDataComplete(new JoinData { JoinNumber = 84, JoinSpan = 1, AttributeName = "Display 1 - Current Source" }, new JoinMetadata { Description = "Display 1 - Current Source", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Serial }); // Device Online Status + /// + /// Touchpanel Online Start + /// [JoinName("TouchpanelOnlineStart")] public JoinDataComplete TouchpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 150, JoinSpan = 10, AttributeName = "Online - Touch Panel" }, new JoinMetadata { Description = "Online - Touch Panel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + /// + /// Xpanel Online Start + /// [JoinName("XpanelOnlineStart")] public JoinDataComplete XpanelOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 160, JoinSpan = 5, AttributeName = "Online - XPanel" }, new JoinMetadata { Description = "Online - XPanel", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + /// + /// Display Online Start + /// [JoinName("DisplayOnlineStart")] public JoinDataComplete DisplayOnlineStart = new JoinDataComplete(new JoinData { JoinNumber = 170, JoinSpan = 10, AttributeName = "Online - Display" }, new JoinMetadata { Description = "Online - Display", JoinCapabilities = eJoinCapabilities.ToFusion, JoinType = eJoinType.Digital }); + /// + /// Display 1 Laptop Source Start + /// [JoinName("Display1LaptopSourceStart")] - public JoinDataComplete Display1LaptopSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 166, JoinSpan = 5, AttributeName = "Display 1 - Source Laptop" }, + public JoinDataComplete Display1LaptopSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 165, JoinSpan = 5, AttributeName = "Display 1 - Source Laptop" }, new JoinMetadata { Description = "Display 1 - Source Laptop", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); + /// + /// Display 1 Disc Player Source Start + /// [JoinName("Display1DiscPlayerSourceStart")] - public JoinDataComplete Display1DiscPlayerSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 181, JoinSpan = 5, AttributeName = "Display 1 - Source Disc Player" }, + public JoinDataComplete Display1DiscPlayerSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 180, JoinSpan = 5, AttributeName = "Display 1 - Source Disc Player" }, new JoinMetadata { Description = "Display 1 - Source Disc Player", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); + /// + /// Display 1 Set Top Box Source Start + /// [JoinName("Display1SetTopBoxSourceStart")] - public JoinDataComplete Display1SetTopBoxSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 188, JoinSpan = 5, AttributeName = "Display 1 - Source TV" }, + public JoinDataComplete Display1SetTopBoxSourceStart = new JoinDataComplete(new JoinData { JoinNumber = 185, JoinSpan = 5, AttributeName = "Display 1 - Source TV" }, new JoinMetadata { Description = "Display 1 - Source TV", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); // Display 1 + /// + /// Display 1 Start + /// [JoinName("Display1Start")] - public JoinDataComplete Display1Start = new JoinDataComplete(new JoinData { JoinNumber = 158, JoinSpan = 1 }, + public JoinDataComplete Display1Start = new JoinDataComplete(new JoinData { JoinNumber = 190, JoinSpan = 1 }, new JoinMetadata { Description = "Display 1 Start", JoinCapabilities = eJoinCapabilities.ToFromFusion, JoinType = eJoinType.Digital }); - /// /// Constructor to use when instantiating this Join Map without inheriting from it /// diff --git a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs similarity index 82% rename from src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs rename to src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs index e2638493..1f21cbe6 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs @@ -1,6 +1,4 @@ - - -using Crestron.SimplSharp; +using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronXml; using Crestron.SimplSharp.CrestronXml.Serialization; @@ -8,6 +6,7 @@ using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.Fusion; using Newtonsoft.Json; using PepperDash.Core; +using PepperDash.Core.Logging; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using Serilog.Events; @@ -21,26 +20,42 @@ namespace PepperDash.Essentials.Core.Fusion /// /// Represents a EssentialsHuddleSpaceFusionSystemControllerBase /// - public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider + public class IEssentialsRoomFusionController : EssentialsDevice, IOccupancyStatusProvider, IFusionHelpRequest { - private readonly EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; + private IEssentialsRoomFusionControllerPropertiesConfig _config; + + private EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; private const string RemoteOccupancyXml = "Local{0}"; - private readonly bool _guidFileExists; + private bool _guidFileExists; private readonly Dictionary _sourceToFeedbackSigs = new Dictionary(); + /// + /// Gets or sets the CurrentRoomSourceNameSig + /// protected StringSigData CurrentRoomSourceNameSig; private readonly FusionCustomPropertiesBridge CustomPropertiesBridge = new FusionCustomPropertiesBridge(); + + /// + /// Gets or sets the FusionOccSensor + /// protected FusionOccupancySensorAsset FusionOccSensor; private readonly FusionRemoteOccupancySensor FusionRemoteOccSensor; + /// + /// Gets or sets the FusionRoom + /// protected FusionRoom FusionRoom; + + /// + /// Gets or sets the FusionStaticAssets + /// protected Dictionary FusionStaticAssets; private readonly long PushNotificationTimeout = 5000; - private readonly IEssentialsRoom Room; + private IEssentialsRoom Room; private readonly long SchedulePollInterval = 300000; private Event _currentMeeting; @@ -48,8 +63,7 @@ namespace PepperDash.Essentials.Core.Fusion private CTimer _dailyTimeRequestTimer; private StatusMonitorCollection _errorMessageRollUp; - private FusionRoomGuids _guiDs; - private uint _ipId; + private FusionRoomGuids _guids; private bool _isRegisteredForSchedulePushNotifications; private Event _nextMeeting; @@ -60,6 +74,20 @@ namespace PepperDash.Essentials.Core.Fusion private string _roomOccupancyRemoteString; + private bool _helpRequestSent; + + private eFusionHelpResponse _helpRequestStatus; + + /// + public StringFeedback HelpRequestResponseFeedback { get; private set; } + + /// + public BoolFeedback HelpRequestSentFeedback { get; private set; } + + /// + public StringFeedback HelpRequestStatusFeedback { get; private set; } + + #region System Info Sigs //StringSigData SystemName; @@ -93,71 +121,110 @@ namespace PepperDash.Essentials.Core.Fusion #endregion - public EssentialsHuddleSpaceFusionSystemControllerBase(IEssentialsRoom room, uint ipId, string joinMapKey) + /// + /// Constructor + /// + public IEssentialsRoomFusionController(string key, string name, IEssentialsRoomFusionControllerPropertiesConfig config) + : base(key, name) + { + _config = config; + + AddPostActivationAction(() => + { + var room = DeviceManager.GetDeviceForKey(_config.RoomKey); + + if (room == null) + { + this.LogError("Error Creating Fusion Room Controller. No room found with key '{0}'", _config.RoomKey); + return; + } + + this.LogInformation("Creating Fusion Room Controller for room '{0}' at IPID: {1:X2}", room.Key, _config.IpIdInt); + + ConstructorHelper(room, _config.IpIdInt, _config.JoinMapKey); + + }); + } + + /// + /// + /// + /// + /// + /// + public IEssentialsRoomFusionController(IEssentialsRoom room, string ipId, string joinMapKey) : base(room.Key + "-fusion") + { + _config = new IEssentialsRoomFusionControllerPropertiesConfig() + { + IpId = ipId, + RoomKey = room.Key, + JoinMapKey = joinMapKey + }; + + ConstructorHelper(room, _config.IpIdInt, joinMapKey); + } + + private void ConstructorHelper(IEssentialsRoom room, uint ipId, string joinMapKey) { try { + this.LogDebug("ConstructorHelper called for Fusion Room Controller for room '{0}' with IPID {1:X2}", room.Key, ipId); + + this.LogDebug("JoinMap Key: {0}", joinMapKey); + JoinMap = new EssentialsHuddleSpaceRoomFusionRoomJoinMap(1); - CrestronConsole.AddNewConsoleCommand((o) => JoinMap.PrintJoinMapInfo(), string.Format("ptjnmp-{0}", Key), "Prints Attribute Join Map", ConsoleAccessLevelEnum.AccessOperator); + this.LogDebug("JoinMap created"); + + CrestronConsole.AddNewConsoleCommand((o) => + { + if (o is string deviceKey) + { + if (string.IsNullOrEmpty(deviceKey) || deviceKey == "?") + { + CrestronConsole.ConsoleCommandResponse("Please provide a device key for a Fusion Room instance"); + return; + } + else if (deviceKey != this.Key) + { + return; + } + } + else + { + CrestronConsole.ConsoleCommandResponse("Invalid parameter. Please provide a device key for a Fusion Room instance"); + return; + } + + JoinMap.PrintJoinMapInfo(); + }, "printfusionjoinmap", "Prints Attribute Join Map", ConsoleAccessLevelEnum.AccessOperator); if (!string.IsNullOrEmpty(joinMapKey)) { + // this.LogDebug("Attempting to get custom join map for key: {0}", joinMapKey); var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey); if (customJoins != null) { JoinMap.SetCustomJoinData(customJoins); } } - + Room = room; - _ipId = ipId; + this.LogDebug("Room found: {0}", Room.Key); FusionStaticAssets = new Dictionary(); - _guiDs = new FusionRoomGuids(); + this.LogDebug("FusionStaticAssets dictionary created"); - var mac = - CrestronEthernetHelper.GetEthernetParameter( - CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); - - var slot = Global.ControlSystem.ProgramNumber; - - var guidFilePath = Global.FilePathPrefix + - string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _ipId); - - var oldGuidFilePath = Global.FilePathPrefix + - string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); - - if (File.Exists(oldGuidFilePath)) - { - Debug.LogMessage(LogEventLevel.Information, this, "Migrating from old Fusion GUID file to new Fusion GUID File"); - - File.Copy(oldGuidFilePath, guidFilePath); - - File.Delete(oldGuidFilePath); - } - - _guidFileExists = File.Exists(guidFilePath); - - // Check if file exists - if (!_guidFileExists) - { - // Does not exist. Create GUIDs - _guiDs = new FusionRoomGuids(Room.Name, ipId, _guiDs.GenerateNewRoomGuid(slot, mac), - FusionStaticAssets); - } - else - { - // Exists. Read GUIDs - ReadGuidFile(guidFilePath); - } + _guids = new FusionRoomGuids(); + this.LogDebug("FusionRoomGuids created"); if (Room is IRoomOccupancy occupancyRoom) { + Debug.LogDebug(this, "Room '{0}' supports IRoomOccupancy", Room.Key); if (occupancyRoom.RoomOccupancy != null) { if (occupancyRoom.OccupancyStatusProviderIsRemote) @@ -171,8 +238,8 @@ namespace PepperDash.Essentials.Core.Fusion } } + this.LogDebug("Occupancy setup complete"); - AddPostActivationAction(() => PostActivate(guidFilePath)); } catch (Exception e) { @@ -180,9 +247,54 @@ namespace PepperDash.Essentials.Core.Fusion } } - private void PostActivate(string guidFilePath) + private string GetGuidFilePath(uint ipId) { - CreateSymbolAndBasicSigs(_ipId); + var mac = + CrestronEthernetHelper.GetEthernetParameter( + CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0); + + var slot = Global.ControlSystem.ProgramNumber; + + var guidFilePath = Global.FilePathPrefix + + string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _config.IpIdInt); + + var oldGuidFilePath = Global.FilePathPrefix + + string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); + + if (File.Exists(oldGuidFilePath)) + { + Debug.LogMessage(LogEventLevel.Information, this, "Migrating from old Fusion GUID file to new Fusion GUID File"); + + File.Copy(oldGuidFilePath, guidFilePath); + + File.Delete(oldGuidFilePath); + } + + _guidFileExists = File.Exists(guidFilePath); + + // Check if file exists + if (!_guidFileExists) + { + // Does not exist. Create GUIDs + _guids = new FusionRoomGuids(Room.Name, ipId, _guids.GenerateNewRoomGuid(slot, mac), + FusionStaticAssets); + } + else + { + // Exists. Read GUIDs + ReadGuidFile(guidFilePath); + } + + return guidFilePath; + } + + /// + public override void Initialize() + { + + GenerateGuidFile(GetGuidFilePath(_config.IpIdInt)); + + CreateSymbolAndBasicSigs(_config.IpIdInt); SetUpSources(); SetUpCommunitcationMonitors(); SetUpDisplay(); @@ -191,12 +303,18 @@ namespace PepperDash.Essentials.Core.Fusion FusionRVI.GenerateFileForAllFusionDevices(); - GenerateGuidFile(guidFilePath); + HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.OutputSig.StringValue); + + HelpRequestSentFeedback = new BoolFeedback("HelpRequestSent", () => _helpRequestSent); + HelpRequestStatusFeedback = new StringFeedback("HelpRequestStatus", () => _helpRequestStatus.ToString()); } + /// + /// Gets the RoomGuid + /// protected string RoomGuid { - get { return _guiDs.RoomGuid; } + get { return _guids.RoomGuid; } } /// @@ -204,6 +322,9 @@ namespace PepperDash.Essentials.Core.Fusion /// public StringFeedback RoomOccupancyRemoteStringFeedback { get; private set; } + /// + /// Gets the RoomIsOccupiedFeedbackFunc + /// protected Func RoomIsOccupiedFeedbackFunc { get { return () => FusionRemoteOccSensor.RoomOccupied.OutputSig.BoolValue; } @@ -218,10 +339,16 @@ namespace PepperDash.Essentials.Core.Fusion #endregion + /// + /// ScheduleChange event + /// public event EventHandler ScheduleChange; //public event EventHandler MeetingEndWarning; //public event EventHandler NextMeetingBeginWarning; + /// + /// RoomInfoChange event + /// public event EventHandler RoomInfoChange; //ScheduleResponseEvent NextMeeting; @@ -258,11 +385,11 @@ namespace PepperDash.Essentials.Core.Fusion Debug.LogMessage(LogEventLevel.Debug, this, "Writing GUIDs to file"); - _guiDs = FusionOccSensor == null - ? new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets) - : new FusionRoomGuids(Room.Name, _ipId, RoomGuid, FusionStaticAssets, FusionOccSensor); + _guids = FusionOccSensor == null + ? new FusionRoomGuids(Room.Name, _config.IpIdInt, RoomGuid, FusionStaticAssets) + : new FusionRoomGuids(Room.Name, _config.IpIdInt, RoomGuid, FusionStaticAssets, FusionOccSensor); - var json = JsonConvert.SerializeObject(_guiDs, Newtonsoft.Json.Formatting.Indented); + var json = JsonConvert.SerializeObject(_guids, Newtonsoft.Json.Formatting.Indented); using (var sw = new StreamWriter(filePath)) { @@ -312,17 +439,17 @@ namespace PepperDash.Essentials.Core.Fusion { var json = File.ReadToEnd(filePath, Encoding.ASCII); - _guiDs = JsonConvert.DeserializeObject(json); + _guids = JsonConvert.DeserializeObject(json); - _ipId = _guiDs.IpId; + // _config.IpId = _guids.IpId; - FusionStaticAssets = _guiDs.StaticAssets; + FusionStaticAssets = _guids.StaticAssets; } Debug.LogMessage(LogEventLevel.Information, this, "Fusion Guids successfully read from file: {0}", filePath); - Debug.LogMessage(LogEventLevel.Debug, this, "\r\n********************\r\n\tRoom Name: {0}\r\n\tIPID: {1:X}\r\n\tRoomGuid: {2}\r\n*******************", Room.Name, _ipId, RoomGuid); + Debug.LogMessage(LogEventLevel.Debug, this, "\r\n********************\r\n\tRoom Name: {0}\r\n\tIPID: {1:X}\r\n\tRoomGuid: {2}\r\n*******************", Room.Name, _config.IpIdInt, RoomGuid); foreach (var item in FusionStaticAssets) { @@ -343,6 +470,10 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// CreateSymbolAndBasicSigs method + /// + /// protected virtual void CreateSymbolAndBasicSigs(uint ipId) { Debug.LogMessage(LogEventLevel.Information, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId); @@ -405,6 +536,10 @@ namespace PepperDash.Essentials.Core.Fusion CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } + /// + /// CrestronEnvironment_EthernetEventHandler method + /// + /// protected void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) { if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp) @@ -413,6 +548,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// GetSystemInfo method + /// protected void GetSystemInfo() { //SystemName.InputSig.StringValue = Room.Name; @@ -426,6 +564,9 @@ namespace PepperDash.Essentials.Core.Fusion () => CrestronConsole.SendControlSystemCommand("reboot", ref response)); } + /// + /// SetUpEthernetValues method + /// protected void SetUpEthernetValues() { _ip1 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorIp1.JoinNumber, JoinMap.ProcessorIp1.AttributeName, eSigIoMask.InputSigOnly); @@ -441,6 +582,9 @@ namespace PepperDash.Essentials.Core.Fusion _netMask2 = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorNetMask2.JoinNumber, JoinMap.ProcessorNetMask2.AttributeName, eSigIoMask.InputSigOnly); } + /// + /// GetProcessorEthernetValues method + /// protected void GetProcessorEthernetValues() { _ip1.InputSig.StringValue = @@ -475,7 +619,7 @@ namespace PepperDash.Essentials.Core.Fusion // Interface 1 if (InitialParametersClass.NumberOfEthernetInterfaces > 1) - // Only get these values if the processor has more than 1 NIC + // Only get these values if the processor has more than 1 NIC { _ip2.InputSig.StringValue = CrestronEthernetHelper.GetEthernetParameter( @@ -489,6 +633,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// GetProcessorInfo method + /// protected void GetProcessorInfo() { _firmware = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorFirmware.JoinNumber, JoinMap.ProcessorFirmware.AttributeName, eSigIoMask.InputSigOnly); @@ -499,7 +646,7 @@ namespace PepperDash.Essentials.Core.Fusion { var join = JoinMap.ProgramNameStart.JoinNumber + i; var progNum = i + 1; - _program[i] = FusionRoom.CreateOffsetStringSig((uint) join, + _program[i] = FusionRoom.CreateOffsetStringSig((uint)join, string.Format("{0} {1}", JoinMap.ProgramNameStart.AttributeName, progNum), eSigIoMask.InputSigOnly); } } @@ -507,6 +654,9 @@ namespace PepperDash.Essentials.Core.Fusion _firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion; } + /// + /// GetCustomProperties method + /// protected void GetCustomProperties() { if (FusionRoom.IsOnline) @@ -524,11 +674,16 @@ namespace PepperDash.Essentials.Core.Fusion // TODO: Get IP and Project Name from TP } + /// + /// FusionRoom_OnlineStatusChange method + /// + /// + /// protected void FusionRoom_OnlineStatusChange(GenericBase currentDevice, OnlineOfflineEventArgs args) { if (args.DeviceOnLine) { - CrestronInvoke.BeginInvoke( (o) => + CrestronInvoke.BeginInvoke((o) => { CrestronEnvironment.Sleep(200); @@ -676,7 +831,7 @@ namespace PepperDash.Essentials.Core.Fusion var extendTime = _currentMeeting.dtEnd - DateTime.Now; var extendMinutesRaw = extendTime.TotalMinutes; - extendMinutes += (int) Math.Round(extendMinutesRaw); + extendMinutes += (int)Math.Round(extendMinutesRaw); } @@ -784,11 +939,11 @@ namespace PepperDash.Essentials.Core.Fusion var parameters = actionResponse["Parameters"]; foreach (var isRegistered in from XmlElement parameter in parameters - where parameter.HasAttributes - select parameter.Attributes + where parameter.HasAttributes + select parameter.Attributes into attributes - where attributes["ID"].Value == "Registered" - select Int32.Parse(attributes["Value"].Value)) + where attributes["ID"].Value == "Registered" + select Int32.Parse(attributes["Value"].Value)) { switch (isRegistered) { @@ -845,9 +1000,9 @@ namespace PepperDash.Essentials.Core.Fusion Debug.LogMessage(LogEventLevel.Debug, 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.LogMessage(LogEventLevel.Debug, this, "Processor time set to {0}", CrestronEnvironment.GetLocalTime()); } @@ -1065,6 +1220,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// SetUpSources method + /// protected virtual void SetUpSources() { // Sources @@ -1074,10 +1232,10 @@ namespace PepperDash.Essentials.Core.Fusion // 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; + uint i = 0; foreach (var kvp in setTopBoxes) { - TryAddRouteActionSigs(JoinMap.Display1SetTopBoxSourceStart.AttributeName + " " + i, JoinMap.Display1SetTopBoxSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); + TryAddRouteActionSigs(JoinMap.Display1SetTopBoxSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1SetTopBoxSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); i++; if (i > JoinMap.Display1SetTopBoxSourceStart.JoinSpan) // We only have five spots { @@ -1086,10 +1244,10 @@ namespace PepperDash.Essentials.Core.Fusion } var discPlayers = dict.Where(d => d.Value.SourceDevice is IDiscPlayerControls); - i = 1; + i = 0; foreach (var kvp in discPlayers) { - TryAddRouteActionSigs(JoinMap.Display1DiscPlayerSourceStart.AttributeName + " " + i, JoinMap.Display1DiscPlayerSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); + TryAddRouteActionSigs(JoinMap.Display1DiscPlayerSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1DiscPlayerSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); i++; if (i > JoinMap.Display1DiscPlayerSourceStart.JoinSpan) // We only have five spots { @@ -1098,10 +1256,10 @@ namespace PepperDash.Essentials.Core.Fusion } var laptops = dict.Where(d => d.Value.SourceDevice is IRoutingSource); - i = 1; + i = 0; foreach (var kvp in laptops) { - TryAddRouteActionSigs(JoinMap.Display1LaptopSourceStart.AttributeName + " " + i, JoinMap.Display1LaptopSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); + TryAddRouteActionSigs(JoinMap.Display1LaptopSourceStart.AttributeName + " " + (i + 1), JoinMap.Display1LaptopSourceStart.JoinNumber + i, kvp.Key, kvp.Value.SourceDevice); i++; if (i > JoinMap.Display1LaptopSourceStart.JoinSpan) // We only have ten spots??? { @@ -1111,7 +1269,7 @@ namespace PepperDash.Essentials.Core.Fusion foreach (var usageDevice in dict.Select(kvp => kvp.Value.SourceDevice).OfType()) { - usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) {UsageIsTracked = true}; + usageDevice.UsageTracker = new UsageTracking(usageDevice as Device) { UsageIsTracked = true }; usageDevice.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; } } @@ -1157,17 +1315,31 @@ namespace PepperDash.Essentials.Core.Fusion Debug.LogMessage(LogEventLevel.Debug, this, "Device usage string: {0}", deviceUsage); } - + /// + /// Tries to add route action sigs for a source + /// + /// + /// + /// + /// protected void TryAddRouteActionSigs(string attrName, uint attrNum, string routeKey, Device pSrc) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Creating attribute '{0}' with join {1} for source {2}", + this.LogVerbose("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); + if (!_sourceToFeedbackSigs.ContainsKey(pSrc)) + { + _sourceToFeedbackSigs.Add(pSrc, sigD.InputSig); + } + else + { + this.LogWarning("Source '{0}' already has a feedback sig mapped. Overwriting.", pSrc.Key); + _sourceToFeedbackSigs[pSrc] = sigD.InputSig; + } // And respond to selection in Fusion sigD.OutputSig.SetSigFalseAction(() => @@ -1180,14 +1352,12 @@ namespace PepperDash.Essentials.Core.Fusion } catch (Exception) { - Debug.LogMessage(LogEventLevel.Verbose, this, "Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING", + this.LogVerbose("Error creating Fusion signal {0} {1} for device '{2}'. THIS NEEDS REWORKING", attrNum, attrName, pSrc.Key); } } - /// - /// - /// + private void SetUpCommunitcationMonitors() { uint displayNum = 0; @@ -1274,6 +1444,8 @@ namespace PepperDash.Essentials.Core.Fusion if (attrName != null) { + this.LogDebug("Linking communication monitor for device '{0}' to Fusion attribute '{1}' at join {2}", + dev.Key, attrName, attrNum); // Link comm status to sig and update var sigD = FusionRoom.CreateOffsetBoolSig(attrNum, attrName, eSigIoMask.InputSigOnly); var smd = dev as ICommunicationMonitor; @@ -1285,6 +1457,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// SetUpDisplay method + /// protected virtual void SetUpDisplay() { try @@ -1297,7 +1472,7 @@ namespace PepperDash.Essentials.Core.Fusion foreach (var display in displays.Cast()) { - display.UsageTracker = new UsageTracking(display as Device) {UsageIsTracked = true}; + display.UsageTracker = new UsageTracking(display as Device) { UsageIsTracked = true }; display.UsageTracker.DeviceUsageEnded += UsageTracker_DeviceUsageEnded; } @@ -1410,7 +1585,7 @@ namespace PepperDash.Essentials.Core.Fusion // Power on - var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint) joinOffset, displayName + "Power On", + var defaultDisplayPowerOn = FusionRoom.CreateOffsetBoolSig((uint)joinOffset, displayName + "Power On", eSigIoMask.InputOutputSig); defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => { @@ -1421,7 +1596,7 @@ namespace PepperDash.Essentials.Core.Fusion }); // Power Off - var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 1, displayName + "Power Off", + var defaultDisplayPowerOff = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 1, displayName + "Power Off", eSigIoMask.InputOutputSig); defaultDisplayPowerOn.OutputSig.UserObject = new Action(b => { @@ -1439,7 +1614,7 @@ namespace PepperDash.Essentials.Core.Fusion } // Current Source - var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint) joinOffset + 8, + var defaultDisplaySourceNone = FusionRoom.CreateOffsetBoolSig((uint)joinOffset + 8, displayName + "Source None", eSigIoMask.InputOutputSig); defaultDisplaySourceNone.OutputSig.UserObject = new Action(b => { @@ -1507,7 +1682,7 @@ namespace PepperDash.Essentials.Core.Fusion //if (Room.OccupancyObj != null) //{ - var tempOccAsset = _guiDs.OccupancyAsset; + var tempOccAsset = _guids.OccupancyAsset; if (tempOccAsset == null) { @@ -1532,7 +1707,7 @@ namespace PepperDash.Essentials.Core.Fusion occRoom.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; } RoomOccupancyRemoteStringFeedback = new StringFeedback(() => _roomOccupancyRemoteString); - + RoomOccupancyRemoteStringFeedback.LinkInputSig(occSensorAsset.RoomOccupancyInfo.InputSig); //} @@ -1588,12 +1763,74 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// Event handler for Fusion state changes + /// + /// + /// protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args) { + if (args.EventId == FusionEventIds.HelpMessageReceivedEventId) + { + this.LogInformation( "Help message received from Fusion for room '{0}'", + Room.Name); + + this.LogDebug("Help message content: {0}", FusionRoom.Help.OutputSig.StringValue); + // Fire help request event + HelpRequestResponseFeedback.FireUpdate(); + + if (!string.IsNullOrEmpty(FusionRoom.Help.OutputSig.StringValue)) + { + switch (FusionRoom.Help.OutputSig.StringValue) + { + case "Please wait, a technician is on his / her way.": + // this.LogInformation("Please wait, a technician is on his / her way.", + // Room.Name); + + _helpRequestStatus = eFusionHelpResponse.HelpOnTheWay; + break; + case "Please call the helpdesk.": + // this.LogInformation("Please call the helpdesk."); + // _helpRequestStatus = eFusionHelpResponse.CallHelpDesk; + break; + case "Please wait, I will reschedule your meeting to a different room.": + // this.LogInformation("Please wait, I will reschedule your meeting to a different room.", + // Room.Name); + + _helpRequestStatus = eFusionHelpResponse.ReschedulingMeeting; + break; + case "I will be taking control of your system. Please be patient while I adjust the settings.": + // this.LogInformation("I will be taking control of your system. Please be patient while I adjust the settings.", + // Room.Name); + + _helpRequestStatus = eFusionHelpResponse.TakingControl; + break; + default: + // this.LogInformation("Unknown help request code received from Fusion for room '{0}'", + // Room.Name); + + _helpRequestStatus = eFusionHelpResponse.None; + break; + } + } + else + { + _helpRequestStatus = eFusionHelpResponse.None; + } + + if(_helpRequestStatus == eFusionHelpResponse.None) + { + _helpRequestSent = false; + HelpRequestSentFeedback.FireUpdate(); + } + + HelpRequestStatusFeedback.FireUpdate(); + } + + // The sig/UO method: Need separate handlers for fixed and user sigs, all flavors, // even though they all contain sigs. - BoolOutputSig outSig; if (args.UserConfiguredSigDetail is BooleanSigDataFixedName sigData) { @@ -1632,9 +1869,69 @@ namespace PepperDash.Essentials.Core.Fusion (outSig.UserObject as Action).Invoke(outSig.StringValue); } } + + /// + public void SendHelpRequest() + { + + var now = DateTime.Now; + + var breakString = _config.UseHtmlFormatForHelpRequests ? "
" : "\r\n"; + + var date = now.ToString("MMMM dd, yyyy"); + var time = now.ToString("hh:mm tt"); + if (_config.Use24HourTimeFormat) + { + time = now.ToString("HH:mm"); + } + + var requestString = $"HR00: {breakString} Assistance has been requested from room {Room.Name}{breakString}on {date} at {time}"; + + FusionRoom.Help.InputSig.StringValue = requestString; + + this.LogInformation("Help request sent to Fusion from room '{0}'", Room.Name); + this.LogDebug("Help request content: {0}", FusionRoom.Help.InputSig.StringValue); + + _helpRequestSent = true; + HelpRequestSentFeedback.FireUpdate(); + + _helpRequestStatus = eFusionHelpResponse.HelpRequested; + HelpRequestStatusFeedback.FireUpdate(); + } + + /// + public void CancelHelpRequest() + { + if (_helpRequestSent) + { + FusionRoom.Help.InputSig.StringValue = ""; + _helpRequestSent = false; + HelpRequestSentFeedback.FireUpdate(); + _helpRequestStatus = eFusionHelpResponse.None; + HelpRequestStatusFeedback.FireUpdate(); + Debug.LogMessage(LogEventLevel.Information, this, "Help request cancelled in Fusion for room '{0}'", Room.Name); + } + } + + /// + public void ToggleHelpRequest() + { + if (_helpRequestSent) + { + CancelHelpRequest(); + } + else + { + SendHelpRequest(); + } + } + } + /// + /// Extensions to enhance Fusion room, asset and signal creation. + /// public static class FusionRoomExtensions { /// @@ -1648,6 +1945,8 @@ namespace PepperDash.Essentials.Core.Fusion /// public static BooleanSigData CreateOffsetBoolSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) { + Debug.LogDebug("Creating Offset Bool Sig: {0} at Join {1}", name, number); + if (number < 50) { throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); @@ -1668,6 +1967,8 @@ namespace PepperDash.Essentials.Core.Fusion /// public static UShortSigData CreateOffsetUshortSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) { + Debug.LogDebug("Creating Offset UShort Sig: {0} at Join {1}", name, number); + if (number < 50) { throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); @@ -1688,6 +1989,8 @@ namespace PepperDash.Essentials.Core.Fusion /// public static StringSigData CreateOffsetStringSig(this FusionRoom fr, uint number, string name, eSigIoMask mask) { + Debug.LogDebug("Creating Offset String Sig: {0} at Join {1}", name, number); + if (number < 50) { throw new ArgumentOutOfRangeException("number", "Cannot be less than 50"); @@ -1803,6 +2106,9 @@ namespace PepperDash.Essentials.Core.Fusion /// public class RoomInformation { + /// + /// Constructor + /// public RoomInformation() { FusionCustomProperties = new List(); @@ -1855,10 +2161,17 @@ namespace PepperDash.Essentials.Core.Fusion /// public class FusionCustomProperty { + /// + /// Constructor + /// public FusionCustomProperty() { } + /// + /// Constructor with id + /// + /// public FusionCustomProperty(string id) { ID = id; diff --git a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs new file mode 100644 index 00000000..e874762c --- /dev/null +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Fusion; + +/// +/// Factory for creating IEssentialsRoomFusionController devices +/// +public class IEssentialsRoomFusionControllerFactory : EssentialsDeviceFactory +{ + /// + /// Constructor + /// + public IEssentialsRoomFusionControllerFactory() + { + TypeNames = new List() { "fusionRoom" }; + } + + /// + /// Builds the device + /// + /// + /// + public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc) + { + Debug.LogDebug("Factory Attempting to create new IEssentialsRoomFusionController Device"); + + + var properties = dc.Properties.ToObject(); + + return new IEssentialsRoomFusionController(dc.Key, dc.Name, properties); + } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerPropertiesConfig.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerPropertiesConfig.cs new file mode 100644 index 00000000..4dc4a834 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerPropertiesConfig.cs @@ -0,0 +1,59 @@ +using Newtonsoft.Json; +using PepperDash.Core; + +/// +/// Config properties for an IEssentialsRoomFusionController device +/// +public class IEssentialsRoomFusionControllerPropertiesConfig +{ + /// + /// Gets or sets the IP ID of the Fusion Room Controller + /// + [JsonProperty("ipId")] + public string IpId { get; set; } + + /// + /// Gets the IP ID as a UInt16 + /// + [JsonIgnore] + public uint IpIdInt + { + get + { + // Try to parse the IpId string to UInt16 as hex + if (ushort.TryParse(IpId, System.Globalization.NumberStyles.HexNumber, null, out ushort result)) + { + return result; + } + else + { + Debug.LogWarning( "Failed to parse IpId '{0}' as UInt16", IpId); + return 0; + } + } + } + + /// + /// Gets or sets the join map key + /// + [JsonProperty("joinMapKey")] + public string JoinMapKey { get; set; } + + /// + /// Gets or sets the room key associated with this Fusion Room Controller + /// + [JsonProperty("roomKey")] + public string RoomKey { get; set; } + + /// + /// Gets or sets whether to use HTML format for help requests + /// + [JsonProperty("useHtmlFormatForHelpRequests")] + public bool UseHtmlFormatForHelpRequests { get; set; } = false; + + /// + /// Gets or sets whether to use 24-hour time format + /// + [JsonProperty("use24HourTimeFormat")] + public bool Use24HourTimeFormat { get; set; } = false; +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs new file mode 100644 index 00000000..de4cca17 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Core.Fusion +{ + /// + /// Represents Fusion Help Request functionality + /// + public interface IFusionHelpRequest + { + /// + /// Feedback containing the response to a help request + /// + StringFeedback HelpRequestResponseFeedback { get; } + + /// + /// Indicates whether a help request has been sent + /// + BoolFeedback HelpRequestSentFeedback { get; } + + /// + /// Feedback containing the current status of the help request + /// + StringFeedback HelpRequestStatusFeedback { get; } + + /// + /// Sends a help request + /// + void SendHelpRequest(); + + /// + /// Clears the current help request status + /// + void CancelHelpRequest(); + + /// + /// Toggles between sending and cancelling a help request + /// + void ToggleHelpRequest(); + } +} diff --git a/src/PepperDash.Essentials.Core/Fusion/eFusionHelpResponse.cs b/src/PepperDash.Essentials.Core/Fusion/eFusionHelpResponse.cs new file mode 100644 index 00000000..6a5bbcd8 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Fusion/eFusionHelpResponse.cs @@ -0,0 +1,37 @@ + + +namespace PepperDash.Essentials.Core.Fusion +{ + /// + /// Enumeration of possible Fusion Help Responses based on the standard responses from Fusion + /// + public enum eFusionHelpResponse + { + /// + /// No help response + /// + None, + /// + /// Help has been requested + /// + HelpRequested, + /// + /// Help is on the way + /// + HelpOnTheWay, + /// + /// Please call the helpdesk. + /// + CallHelpDesk, + /// + /// Rescheduling meeting. + /// + ReschedulingMeeting, + + /// + /// Technician taking control. + /// + TakingControl, + } + +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs b/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs index 49b51f67..d6f3c503 100644 --- a/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs +++ b/src/PepperDash.Essentials.Core/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs @@ -49,7 +49,7 @@ namespace PepperDash.Essentials.Core /// public IRoomOccupancy Room { get; private set; } - private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom; + private Fusion.IEssentialsRoomFusionController FusionRoom; public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) : base (config) @@ -74,7 +74,7 @@ namespace PepperDash.Essentials.Core var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion"; - FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase; + FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Core.Fusion.IEssentialsRoomFusionController; if (FusionRoom == null) Debug.LogMessage(LogEventLevel.Debug, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey); diff --git a/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs b/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs index dfb8b5a1..38e4456e 100644 --- a/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs +++ b/src/PepperDash.Essentials.Core/Room/EssentialsRoomBase.cs @@ -408,7 +408,7 @@ namespace PepperDash.Essentials.Core Debug.LogMessage(LogEventLevel.Information, this, "Timeout Minutes from Config is: {0}", timeoutMinutes); // If status provider is fusion, set flag to remote - if (statusProvider is Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase) + if (statusProvider is Core.Fusion.IEssentialsRoomFusionController) OccupancyStatusProviderIsRemote = true; if(timeoutMinutes > 0)