From f27965ac29fde1beff2102b4f69520858330b6d6 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 27 Oct 2025 17:35:38 -0600 Subject: [PATCH 1/5] feat: Add help request functionality to Fusion system controller Introduce `IFusionHelpRequest` interface for managing help requests, including `HelpRequestResponseFeedback` property and `SendHelpRequest` method. Enhance `EssentialsHuddleSpaceFusionSystemControllerBase` with new properties and methods to support help request tracking and management. Improve code organization and documentation throughout the affected files. --- ...lsHuddleSpaceFusionSystemControllerBase.cs | 149 ++++++++++++++++-- .../Fusion/IFusionHelpRequest.cs | 25 +++ 2 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs diff --git a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index e2638493..1497e164 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -1,6 +1,4 @@ - - -using Crestron.SimplSharp; +using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronXml; using Crestron.SimplSharp.CrestronXml.Serialization; @@ -21,7 +19,7 @@ namespace PepperDash.Essentials.Core.Fusion /// /// Represents a EssentialsHuddleSpaceFusionSystemControllerBase /// - public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider + public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider, IFusionHelpRequest { private readonly EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; @@ -31,13 +29,27 @@ namespace PepperDash.Essentials.Core.Fusion 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; @@ -60,6 +72,10 @@ namespace PepperDash.Essentials.Core.Fusion private string _roomOccupancyRemoteString; + private bool _helpRequestSent; + + public StringFeedback HelpRequestResponseFeedback { get; private set; } + #region System Info Sigs //StringSigData SystemName; @@ -93,6 +109,12 @@ namespace PepperDash.Essentials.Core.Fusion #endregion + /// + /// + /// + /// + /// + /// public EssentialsHuddleSpaceFusionSystemControllerBase(IEssentialsRoom room, uint ipId, string joinMapKey) : base(room.Key + "-fusion") { @@ -171,6 +193,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.InputSig.StringValue); + HelpRequestResponseFeedback.LinkInputSig(FusionRoom.Help.InputSig); + AddPostActivationAction(() => PostActivate(guidFilePath)); } @@ -194,6 +219,9 @@ namespace PepperDash.Essentials.Core.Fusion GenerateGuidFile(guidFilePath); } + /// + /// Gets the RoomGuid + /// protected string RoomGuid { get { return _guiDs.RoomGuid; } @@ -204,6 +232,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 +249,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; @@ -343,6 +380,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 +446,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 +458,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// GetSystemInfo method + /// protected void GetSystemInfo() { //SystemName.InputSig.StringValue = Room.Name; @@ -426,6 +474,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 +492,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 = @@ -489,6 +543,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// GetProcessorInfo method + /// protected void GetProcessorInfo() { _firmware = FusionRoom.CreateOffsetStringSig(JoinMap.ProcessorFirmware.JoinNumber, JoinMap.ProcessorFirmware.AttributeName, eSigIoMask.InputSigOnly); @@ -507,6 +564,9 @@ namespace PepperDash.Essentials.Core.Fusion _firmware.InputSig.StringValue = InitialParametersClass.FirmwareVersion; } + /// + /// GetCustomProperties method + /// protected void GetCustomProperties() { if (FusionRoom.IsOnline) @@ -524,6 +584,11 @@ 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) @@ -1065,6 +1130,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// SetUpSources method + /// protected virtual void SetUpSources() { // Sources @@ -1157,7 +1225,13 @@ 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}", @@ -1185,9 +1259,7 @@ namespace PepperDash.Essentials.Core.Fusion } } - /// - /// - /// + private void SetUpCommunitcationMonitors() { uint displayNum = 0; @@ -1285,6 +1357,9 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// SetUpDisplay method + /// protected virtual void SetUpDisplay() { try @@ -1588,12 +1663,25 @@ namespace PepperDash.Essentials.Core.Fusion } } + /// + /// Event handler for Fusion state changes + /// + /// + /// protected void FusionRoom_FusionStateChange(FusionBase device, FusionStateEventArgs args) { + if (args.EventId == FusionEventIds.HelpMessageReceivedEventId) + { + Debug.LogMessage(LogEventLevel.Information, this, "Help message received from Fusion for room '{0}'", + Room.Name); + // Fire help request event + HelpRequestResponseFeedback.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 +1720,40 @@ namespace PepperDash.Essentials.Core.Fusion (outSig.UserObject as Action).Invoke(outSig.StringValue); } } + + /// + /// Sends a help request to Fusion with room name and timestamp + /// + /// + public void SendHelpRequest(bool isHtml) + { + var now = DateTime.Now; + + var breakString = !isHtml ? "\r\n" : "
"; + + var requestString = $"HR00: {breakString} Assistance has been requested from room {Room.Name}{breakString}on {now.ToLongDateString()} at {now.ToLongTimeString()}"; + + FusionRoom.Help.InputSig.StringValue = requestString; + + Debug.LogMessage(LogEventLevel.Information, this, "Help request sent to Fusion from room '{0}'", Room.Name); + + _helpRequestSent = true; + } + + public void CancelHelpRequest() + { + if (_helpRequestSent) + { + FusionRoom.Help.InputSig.StringValue = ""; + _helpRequestSent = false; + Debug.LogMessage(LogEventLevel.Information, this, "Help request cancelled in Fusion for room '{0}'", Room.Name); + } + } } - + /// + /// Extensions to enhance Fusion room, asset and signal creation. + /// public static class FusionRoomExtensions { /// @@ -1803,6 +1922,9 @@ namespace PepperDash.Essentials.Core.Fusion /// public class RoomInformation { + /// + /// Constructor + /// public RoomInformation() { FusionCustomProperties = new List(); @@ -1855,10 +1977,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/IFusionHelpRequest.cs b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs new file mode 100644 index 00000000..30033779 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs @@ -0,0 +1,25 @@ +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 + { + /// + /// Gets the HelpRequstResponseFeedback + /// + StringFeedback HelpRequestResponseFeedback { get; } + + /// + /// Sends a help request + /// + /// + void SendHelpRequest(bool isHtml); + } +} From 2e95f5337e8283a77e845a274129eab4dde099e8 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Tue, 28 Oct 2025 16:49:29 -0600 Subject: [PATCH 2/5] feat: Add IEssentialsRoomFusionController and related configurations - Introduced IEssentialsRoomFusionControllerFactory for creating Fusion Room Controller devices. - Added IEssentialsRoomFusionControllerPropertiesConfig to define configuration properties for the Fusion Room Controller. - Updated IFusionHelpRequest interface to include methods for cancelling and toggling help requests. - Refactored RoomOnToDefaultSourceWhenOccupied to use IEssentialsRoomFusionController instead of EssentialsHuddleSpaceFusionSystemControllerBase. - Modified EssentialsRoomBase to check for IEssentialsRoomFusionController in occupancy status provider. --- .gitignore | 1 + ....cs => IEssentialsRoomFusionController.cs} | 147 ++++++++++++------ .../IEssentialsRoomFusionControllerFactory.cs | 33 ++++ ...alsRoomFusionControllerPropertiesConfig.cs | 25 +++ .../Fusion/IFusionHelpRequest.cs | 17 +- .../RoomOnToDefaultSourceWhenOccupied.cs | 4 +- .../Room/EssentialsRoomBase.cs | 2 +- 7 files changed, 179 insertions(+), 50 deletions(-) rename src/PepperDash.Essentials.Core/Fusion/{EssentialsHuddleSpaceFusionSystemControllerBase.cs => IEssentialsRoomFusionController.cs} (96%) create mode 100644 src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs create mode 100644 src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerPropertiesConfig.cs 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/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs similarity index 96% rename from src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs rename to src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs index 1497e164..fa7c36a4 100644 --- a/src/PepperDash.Essentials.Core/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs @@ -19,12 +19,12 @@ namespace PepperDash.Essentials.Core.Fusion /// /// Represents a EssentialsHuddleSpaceFusionSystemControllerBase /// - public class EssentialsHuddleSpaceFusionSystemControllerBase : Device, IOccupancyStatusProvider, IFusionHelpRequest + public class IEssentialsRoomFusionController : EssentialsDevice, IOccupancyStatusProvider, IFusionHelpRequest { - private readonly EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; + private EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; private const string RemoteOccupancyXml = "Local{0}"; - private readonly bool _guidFileExists; + private bool _guidFileExists; private readonly Dictionary _sourceToFeedbackSigs = new Dictionary(); @@ -52,7 +52,7 @@ namespace PepperDash.Essentials.Core.Fusion /// protected Dictionary FusionStaticAssets; private readonly long PushNotificationTimeout = 5000; - private readonly IEssentialsRoom Room; + private IEssentialsRoom Room; private readonly long SchedulePollInterval = 300000; private Event _currentMeeting; @@ -74,8 +74,12 @@ namespace PepperDash.Essentials.Core.Fusion private bool _helpRequestSent; + /// public StringFeedback HelpRequestResponseFeedback { get; private set; } + /// + public BoolFeedback HelpRequestSentFeedback { get; private set; } + #region System Info Sigs //StringSigData SystemName; @@ -109,14 +113,48 @@ namespace PepperDash.Essentials.Core.Fusion #endregion + /// + /// Constructor + /// + public IEssentialsRoomFusionController(IEssentialsRoomFusionControllerPropertiesConfig config) + : base("FusionRoomController") + { + AddPostActivationAction(() => + { + var room = DeviceManager.GetDeviceForKey(config.RoomKey); + + if (room == null) + { + Debug.LogMessage(LogEventLevel.Error, this, + "Error Creating Fusion Room Controller. No room found with key '{0}'", config.RoomKey); + return; + } + + ConstructorHelper(room, config.IpId, config.JoinMapKey); + + var guidFilePath = GetGuidFilePath(config.IpId); + + PostActivate(guidFilePath); + }); + } + /// /// /// /// /// /// - public EssentialsHuddleSpaceFusionSystemControllerBase(IEssentialsRoom room, uint ipId, string joinMapKey) + public IEssentialsRoomFusionController(IEssentialsRoom room, uint ipId, string joinMapKey) : base(room.Key + "-fusion") + { + ConstructorHelper(room, ipId, joinMapKey); + + var guidFilePath = GetGuidFilePath(ipId); + + AddPostActivationAction(() => PostActivate(guidFilePath)); + } + + private void ConstructorHelper(IEssentialsRoom room, uint ipId, string joinMapKey) { try { @@ -132,7 +170,7 @@ namespace PepperDash.Essentials.Core.Fusion JoinMap.SetCustomJoinData(customJoins); } } - + Room = room; _ipId = ipId; @@ -141,41 +179,7 @@ namespace PepperDash.Essentials.Core.Fusion _guiDs = new FusionRoomGuids(); - 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); - } if (Room is IRoomOccupancy occupancyRoom) @@ -197,13 +201,53 @@ namespace PepperDash.Essentials.Core.Fusion HelpRequestResponseFeedback.LinkInputSig(FusionRoom.Help.InputSig); - AddPostActivationAction(() => PostActivate(guidFilePath)); } catch (Exception e) { Debug.LogMessage(LogEventLevel.Information, this, "Error Building Fusion System Controller: {0}", e); } } + + private string GetGuidFilePath(uint 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, _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); + } + + return guidFilePath; + } private void PostActivate(string guidFilePath) { @@ -1721,11 +1765,8 @@ namespace PepperDash.Essentials.Core.Fusion } } - /// - /// Sends a help request to Fusion with room name and timestamp - /// - /// - public void SendHelpRequest(bool isHtml) + /// + public void SendHelpRequest(bool isHtml = false) { var now = DateTime.Now; @@ -1740,6 +1781,7 @@ namespace PepperDash.Essentials.Core.Fusion _helpRequestSent = true; } + /// public void CancelHelpRequest() { if (_helpRequestSent) @@ -1749,6 +1791,19 @@ namespace PepperDash.Essentials.Core.Fusion Debug.LogMessage(LogEventLevel.Information, this, "Help request cancelled in Fusion for room '{0}'", Room.Name); } } + + /// + public void ToggleHelpRequest(bool isHtml = false) + { + if (_helpRequestSent) + { + CancelHelpRequest(); + } + else + { + SendHelpRequest(isHtml); + } + } } /// diff --git a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs new file mode 100644 index 00000000..4a598cc8 --- /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(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..b7183b17 --- /dev/null +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerPropertiesConfig.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +/// +/// Config properties for an IEssentialsRoomFusionController device +/// +public class IEssentialsRoomFusionControllerPropertiesConfig +{ + /// + /// Gets or sets the IP ID of the Fusion Room Controller + /// + [JsonProperty("ipId")] + public uint IpId { get; set; } + + /// + /// 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; } +} \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs index 30033779..f17f4c9a 100644 --- a/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs @@ -12,14 +12,29 @@ namespace PepperDash.Essentials.Core.Fusion public interface IFusionHelpRequest { /// - /// Gets the HelpRequstResponseFeedback + /// Feedback containing the response to a help request /// StringFeedback HelpRequestResponseFeedback { get; } + /// + /// Indicates whether a help request has been sent + /// + BoolFeedback HelpRequestSentFeedback { get; } + /// /// Sends a help request /// /// void SendHelpRequest(bool isHtml); + + /// + /// Clears the current help request status + /// + void CancelHelpRequest(); + + /// + /// Toggles between sending and cancelling a help request + /// + void ToggleHelpRequest(bool isHtml); } } 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) From da0f28a10c65c08bb7f5aedbfb128380441e999b Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 29 Oct 2025 16:47:18 -0600 Subject: [PATCH 3/5] feat: Enhance IEssentialsRoomFusionController with additional properties and logging --- ...entialsHuddleSpaceRoomFusionRoomJoinMap.cs | 90 ++++++- .../Fusion/IEssentialsRoomFusionController.cs | 241 +++++++++++------- .../IEssentialsRoomFusionControllerFactory.cs | 2 +- ...alsRoomFusionControllerPropertiesConfig.cs | 36 ++- .../Fusion/IFusionHelpRequest.cs | 4 +- 5 files changed, 277 insertions(+), 96 deletions(-) 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/IEssentialsRoomFusionController.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs index fa7c36a4..ee439b12 100644 --- a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs @@ -6,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,6 +22,8 @@ namespace PepperDash.Essentials.Core.Fusion /// public class IEssentialsRoomFusionController : EssentialsDevice, IOccupancyStatusProvider, IFusionHelpRequest { + private IEssentialsRoomFusionControllerPropertiesConfig _config; + private EssentialsHuddleSpaceRoomFusionRoomJoinMap JoinMap; private const string RemoteOccupancyXml = "Local{0}"; @@ -60,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; @@ -116,25 +118,25 @@ namespace PepperDash.Essentials.Core.Fusion /// /// Constructor /// - public IEssentialsRoomFusionController(IEssentialsRoomFusionControllerPropertiesConfig config) - : base("FusionRoomController") + public IEssentialsRoomFusionController(string key, string name, IEssentialsRoomFusionControllerPropertiesConfig config) + : base(key, name) { + _config = config; + AddPostActivationAction(() => { - var room = DeviceManager.GetDeviceForKey(config.RoomKey); + var room = DeviceManager.GetDeviceForKey(_config.RoomKey); if (room == null) { - Debug.LogMessage(LogEventLevel.Error, this, - "Error Creating Fusion Room Controller. No room found with key '{0}'", config.RoomKey); + this.LogError("Error Creating Fusion Room Controller. No room found with key '{0}'", _config.RoomKey); return; } - ConstructorHelper(room, config.IpId, config.JoinMapKey); + this.LogInformation("Creating Fusion Room Controller for room '{0}' at IPID: {1:X2}", room.Key, _config.IpIdInt); - var guidFilePath = GetGuidFilePath(config.IpId); + ConstructorHelper(room, _config.IpIdInt, _config.JoinMapKey); - PostActivate(guidFilePath); }); } @@ -144,26 +146,57 @@ namespace PepperDash.Essentials.Core.Fusion /// /// /// - public IEssentialsRoomFusionController(IEssentialsRoom room, uint ipId, string joinMapKey) + public IEssentialsRoomFusionController(IEssentialsRoom room, string ipId, string joinMapKey) : base(room.Key + "-fusion") { - ConstructorHelper(room, ipId, joinMapKey); + _config = new IEssentialsRoomFusionControllerPropertiesConfig() + { + IpId = ipId, + RoomKey = room.Key, + JoinMapKey = joinMapKey + }; - var guidFilePath = GetGuidFilePath(ipId); - - AddPostActivationAction(() => PostActivate(guidFilePath)); + 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) { @@ -173,17 +206,19 @@ namespace PepperDash.Essentials.Core.Fusion Room = room; - _ipId = ipId; + this.LogDebug("Room found: {0}", Room.Key); FusionStaticAssets = new Dictionary(); - _guiDs = new FusionRoomGuids(); - + this.LogDebug("FusionStaticAssets dictionary created"); + _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) @@ -197,9 +232,7 @@ namespace PepperDash.Essentials.Core.Fusion } } - HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.InputSig.StringValue); - HelpRequestResponseFeedback.LinkInputSig(FusionRoom.Help.InputSig); - + this.LogDebug("Occupancy setup complete"); } catch (Exception e) @@ -207,37 +240,37 @@ namespace PepperDash.Essentials.Core.Fusion Debug.LogMessage(LogEventLevel.Information, this, "Error Building Fusion System Controller: {0}", e); } } - + private string GetGuidFilePath(uint ipId) { - 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; + var slot = Global.ControlSystem.ProgramNumber; - var guidFilePath = Global.FilePathPrefix + - string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _ipId); + 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); + 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"); + 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.Copy(oldGuidFilePath, guidFilePath); - File.Delete(oldGuidFilePath); - } + File.Delete(oldGuidFilePath); + } - _guidFileExists = File.Exists(guidFilePath); + _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), + _guids = new FusionRoomGuids(Room.Name, ipId, _guids.GenerateNewRoomGuid(slot, mac), FusionStaticAssets); } else @@ -245,13 +278,17 @@ namespace PepperDash.Essentials.Core.Fusion // Exists. Read GUIDs ReadGuidFile(guidFilePath); } - + return guidFilePath; } - private void PostActivate(string guidFilePath) + /// + public override void Initialize() { - CreateSymbolAndBasicSigs(_ipId); + + GenerateGuidFile(GetGuidFilePath(_config.IpIdInt)); + + CreateSymbolAndBasicSigs(_config.IpIdInt); SetUpSources(); SetUpCommunitcationMonitors(); SetUpDisplay(); @@ -260,7 +297,11 @@ namespace PepperDash.Essentials.Core.Fusion FusionRVI.GenerateFileForAllFusionDevices(); - GenerateGuidFile(guidFilePath); + HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.InputSig.StringValue); + HelpRequestResponseFeedback.LinkInputSig(FusionRoom.Help.InputSig); + + HelpRequestSentFeedback = new BoolFeedback("HelpRequestSent", () => _helpRequestSent); + } /// @@ -268,7 +309,7 @@ namespace PepperDash.Essentials.Core.Fusion /// protected string RoomGuid { - get { return _guiDs.RoomGuid; } + get { return _guids.RoomGuid; } } /// @@ -339,11 +380,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)) { @@ -393,17 +434,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) { @@ -573,7 +614,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( @@ -600,7 +641,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); } } @@ -637,7 +678,7 @@ namespace PepperDash.Essentials.Core.Fusion { if (args.DeviceOnLine) { - CrestronInvoke.BeginInvoke( (o) => + CrestronInvoke.BeginInvoke((o) => { CrestronEnvironment.Sleep(200); @@ -785,7 +826,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); } @@ -893,11 +934,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) { @@ -954,9 +995,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()); } @@ -1186,10 +1227,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 { @@ -1198,10 +1239,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 { @@ -1210,10 +1251,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??? { @@ -1223,7 +1264,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; } } @@ -1278,14 +1319,22 @@ namespace PepperDash.Essentials.Core.Fusion /// 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(() => @@ -1298,7 +1347,7 @@ 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); } } @@ -1390,6 +1439,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; @@ -1416,7 +1467,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; } @@ -1529,7 +1580,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 => { @@ -1540,7 +1591,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 => { @@ -1558,7 +1609,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 => { @@ -1626,7 +1677,7 @@ namespace PepperDash.Essentials.Core.Fusion //if (Room.OccupancyObj != null) //{ - var tempOccAsset = _guiDs.OccupancyAsset; + var tempOccAsset = _guids.OccupancyAsset; if (tempOccAsset == null) { @@ -1651,7 +1702,7 @@ namespace PepperDash.Essentials.Core.Fusion occRoom.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange; } RoomOccupancyRemoteStringFeedback = new StringFeedback(() => _roomOccupancyRemoteString); - + RoomOccupancyRemoteStringFeedback.LinkInputSig(occSensorAsset.RoomOccupancyInfo.InputSig); //} @@ -1766,13 +1817,21 @@ namespace PepperDash.Essentials.Core.Fusion } /// - public void SendHelpRequest(bool isHtml = false) + public void SendHelpRequest() { + var now = DateTime.Now; - var breakString = !isHtml ? "\r\n" : "
"; + var breakString = _config.UseHtmlFormatForHelpRequests ? "
" : "\r\n"; - var requestString = $"HR00: {breakString} Assistance has been requested from room {Room.Name}{breakString}on {now.ToLongDateString()} at {now.ToLongTimeString()}"; + 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; @@ -1793,7 +1852,7 @@ namespace PepperDash.Essentials.Core.Fusion } /// - public void ToggleHelpRequest(bool isHtml = false) + public void ToggleHelpRequest() { if (_helpRequestSent) { @@ -1801,11 +1860,13 @@ namespace PepperDash.Essentials.Core.Fusion } else { - SendHelpRequest(isHtml); + SendHelpRequest(); } } + } + /// /// Extensions to enhance Fusion room, asset and signal creation. /// @@ -1822,6 +1883,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"); @@ -1842,6 +1905,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"); @@ -1862,6 +1927,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"); @@ -2032,9 +2099,9 @@ namespace PepperDash.Essentials.Core.Fusion /// public class FusionCustomProperty { - /// - /// Constructor - /// + /// + /// Constructor + /// public FusionCustomProperty() { } diff --git a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs index 4a598cc8..e874762c 100644 --- a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerFactory.cs @@ -28,6 +28,6 @@ public class IEssentialsRoomFusionControllerFactory : EssentialsDeviceFactory(); - return new IEssentialsRoomFusionController(properties); + 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 index b7183b17..4dc4a834 100644 --- a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerPropertiesConfig.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionControllerPropertiesConfig.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using PepperDash.Core; /// /// Config properties for an IEssentialsRoomFusionController device @@ -9,7 +10,28 @@ public class IEssentialsRoomFusionControllerPropertiesConfig /// Gets or sets the IP ID of the Fusion Room Controller /// [JsonProperty("ipId")] - public uint IpId { get; set; } + 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 @@ -22,4 +44,16 @@ public class IEssentialsRoomFusionControllerPropertiesConfig /// [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 index f17f4c9a..7dcc6009 100644 --- a/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs @@ -25,7 +25,7 @@ namespace PepperDash.Essentials.Core.Fusion /// Sends a help request /// /// - void SendHelpRequest(bool isHtml); + void SendHelpRequest(); /// /// Clears the current help request status @@ -35,6 +35,6 @@ namespace PepperDash.Essentials.Core.Fusion /// /// Toggles between sending and cancelling a help request /// - void ToggleHelpRequest(bool isHtml); + void ToggleHelpRequest(); } } From 071174fa7d2fa65cf9497e34967b205c50148e17 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 30 Oct 2025 14:13:02 -0600 Subject: [PATCH 4/5] feat: Implement help request status tracking in Fusion system --- .../Fusion/IEssentialsRoomFusionController.cs | 72 +++++++++++++++++-- .../Fusion/IFusionHelpRequest.cs | 6 +- .../Fusion/eFusionHelpResponse.cs | 37 ++++++++++ 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 src/PepperDash.Essentials.Core/Fusion/eFusionHelpResponse.cs diff --git a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs index ee439b12..11c19bce 100644 --- a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs @@ -76,12 +76,18 @@ namespace PepperDash.Essentials.Core.Fusion 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; @@ -297,11 +303,10 @@ namespace PepperDash.Essentials.Core.Fusion FusionRVI.GenerateFileForAllFusionDevices(); - HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.InputSig.StringValue); - HelpRequestResponseFeedback.LinkInputSig(FusionRoom.Help.InputSig); + HelpRequestResponseFeedback = new StringFeedback("HelpRequestResponse", () => FusionRoom.Help.OutputSig.StringValue); HelpRequestSentFeedback = new BoolFeedback("HelpRequestSent", () => _helpRequestSent); - + HelpRequestStatusFeedback = new StringFeedback("HelpRequestStatus", () => _helpRequestStatus.ToString()); } /// @@ -1767,10 +1772,59 @@ namespace PepperDash.Essentials.Core.Fusion { if (args.EventId == FusionEventIds.HelpMessageReceivedEventId) { - Debug.LogMessage(LogEventLevel.Information, this, "Help message received from Fusion for room '{0}'", + 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(); } @@ -1835,9 +1889,14 @@ namespace PepperDash.Essentials.Core.Fusion FusionRoom.Help.InputSig.StringValue = requestString; - Debug.LogMessage(LogEventLevel.Information, this, "Help request sent to Fusion from room '{0}'", Room.Name); + 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(); } /// @@ -1847,6 +1906,9 @@ namespace PepperDash.Essentials.Core.Fusion { 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); } } diff --git a/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs index 7dcc6009..de4cca17 100644 --- a/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IFusionHelpRequest.cs @@ -21,10 +21,14 @@ namespace PepperDash.Essentials.Core.Fusion /// BoolFeedback HelpRequestSentFeedback { get; } + /// + /// Feedback containing the current status of the help request + /// + StringFeedback HelpRequestStatusFeedback { get; } + /// /// Sends a help request /// - /// void SendHelpRequest(); /// 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 From c852f87a2710c0fa7787ab18d6b6afe2b8f40f35 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 30 Oct 2025 14:33:58 -0600 Subject: [PATCH 5/5] refactor: Comment out logging statements in help request handling --- .../Fusion/IEssentialsRoomFusionController.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs index 11c19bce..1f21cbe6 100644 --- a/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs +++ b/src/PepperDash.Essentials.Core/Fusion/IEssentialsRoomFusionController.cs @@ -1784,30 +1784,30 @@ namespace PepperDash.Essentials.Core.Fusion 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); + // 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; + // 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); + // 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); + // 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); + // this.LogInformation("Unknown help request code received from Fusion for room '{0}'", + // Room.Name); _helpRequestStatus = eFusionHelpResponse.None; break;