From daa0427b5300f03935c30643639bd9dde7f66545 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 12 Mar 2020 10:05:24 -0600 Subject: [PATCH 1/3] Adds logic to enable button actions on MPC3 series keypads --- .../Factory/DeviceFactory.cs | 33 ++++++-- .../PepperDash_Essentials_Core.csproj | 1 + .../Touchpanels/Mpc3Touchpanel.cs | 80 +++++++++++++++++++ 3 files changed, 106 insertions(+), 8 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Touchpanels/Mpc3Touchpanel.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs index 8bc89bd4..45779dd9 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs @@ -9,6 +9,7 @@ using PepperDash.Core; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.CrestronIO; +using PepperDash.Essentials.Core.Touchpanels; namespace PepperDash.Essentials.Core { @@ -47,13 +48,21 @@ namespace PepperDash.Essentials.Core var typeName = dc.Type.ToLower(); - // Check "core" types first + + // Check for types that have been added by plugin dlls. + if (FactoryMethods.ContainsKey(typeName)) + { + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading '{0}' from plugin", dc.Type); + return FactoryMethods[typeName](dc); + } + + // Check "core" types if (typeName == "genericcomm") { Debug.Console(1, "Factory Attempting to create new Generic Comm Device"); return new GenericComm(dc); } - else if (typeName == "ceniodigin104") + if (typeName == "ceniodigin104") { var control = CommFactory.GetControlPropertiesConfig(dc); var ipid = control.IpIdInt; @@ -74,13 +83,21 @@ namespace PepperDash.Essentials.Core return new C2nRthsController(key, name, new C2nRths(cresnetId, Global.ControlSystem)); } + if (typeName.StartsWith("mpc3")) + { + var butToken = dc.Properties["buttons"]; + if (butToken != null) + { + var buttons = butToken.ToObject>(); + return new Mpc3TouchpanelController(key, name, Global.ControlSystem, buttons); + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Unable to deserialize buttons collection for device: {0}", key); + } + } - // then check for types that have been added by plugin dlls. - if (FactoryMethods.ContainsKey(typeName)) - { - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Loading '{0}' from plugin", dc.Type); - return FactoryMethods[typeName](dc); - } + return null; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index cc3c6d74..28128a65 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -236,6 +236,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Touchpanels/Mpc3Touchpanel.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Touchpanels/Mpc3Touchpanel.cs new file mode 100644 index 00000000..dd266c24 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Touchpanels/Mpc3Touchpanel.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; + +using PepperDash.Core; + +namespace PepperDash.Essentials.Core.Touchpanels +{ + public class Mpc3TouchpanelController : Device + { + MPC3Basic _Touchpanel; + + Dictionary _Buttons; + + public Mpc3TouchpanelController(string key, string name, CrestronControlSystem processor, Dictionary buttons) + : base(key, name) + { + _Touchpanel = processor.ControllerTouchScreenSlotDevice as MPC3Basic; + _Buttons = buttons; + + + _Touchpanel.ButtonStateChange += new Crestron.SimplSharpPro.DeviceSupport.ButtonEventHandler(_Touchpanel_ButtonStateChange); + } + + void _Touchpanel_ButtonStateChange(GenericBase device, Crestron.SimplSharpPro.DeviceSupport.ButtonEventArgs args) + { + Debug.Console(1, this, "Button {0}, {1}", args.Button.Number, args.NewButtonState); + if (_Buttons.ContainsKey(args.Button.Number)) + { + var type = args.NewButtonState.ToString(); + Press(args.Button.Number, type); + } + } + + /// + /// Runs the function associated with this button/type. One of the following strings: + /// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased + /// + /// + /// + public void Press(uint number, string type) + { + if (!_Buttons.ContainsKey(number)) { return; } + var but = _Buttons[number]; + if (but.EventTypes.ContainsKey(type)) + { + foreach (var a in but.EventTypes[type]) { DeviceJsonApi.DoDeviceAction(a); } + } + } + + + } + + /// + /// + /// + public class KeypadButton + { + public Dictionary EventTypes { get; set; } + public KeypadButtonFeedback Feedback { get; set; } + + public KeypadButton() + { + EventTypes = new Dictionary(); + Feedback = new KeypadButtonFeedback(); + } + } + + /// + /// + /// + public class KeypadButtonFeedback + { + public string Type { get; set; } + public string LinkToKey { get; set; } + } +} \ No newline at end of file From 7afcbaee61e905deb4dc17ec3e4834f46300d030 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 12 Mar 2020 12:35:13 -0600 Subject: [PATCH 2/3] Adds necessary updates to allow feedback for keypad buttons to be defined in config and linked up at runtime --- .../Devices/DeviceFeedbackExtensions.cs | 32 +++++++++++++ .../Devices/DeviceJsonApi.cs | 30 +++++++++++- .../Feedbacks/BoolFeedback.cs | 42 +++++++++++++++++ .../PepperDash_Essentials_Core.csproj | 1 + .../Touchpanels/Mpc3Touchpanel.cs | 46 ++++++++++++++++--- 5 files changed, 143 insertions(+), 8 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceFeedbackExtensions.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceFeedbackExtensions.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceFeedbackExtensions.cs new file mode 100644 index 00000000..1ef59b0f --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceFeedbackExtensions.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; + +namespace PepperDash.Essentials.Core +{ + public static class DeviceFeedbackExtensions + { + /// + /// Attempts to get and return a feedback property from a device by name. + /// If unsuccessful, returns null. + /// + /// + /// + /// + public static Feedback GetFeedbackProperty(this Device device, string propertyName) + { + var feedback = DeviceJsonApi.GetPropertyByName(device.Key, propertyName) as Feedback; + + if (feedback != null) + { + return feedback; + } + + return null; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceJsonApi.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceJsonApi.cs index 32d53388..c7bc7c68 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceJsonApi.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceJsonApi.cs @@ -59,7 +59,7 @@ namespace PepperDash.Essentials.Core } /// - /// + /// Gets the properties on a device /// /// /// @@ -75,8 +75,34 @@ namespace PepperDash.Essentials.Core return JsonConvert.SerializeObject(props, Formatting.Indented); } + /// + /// Gets a property from a device path by name + /// + /// + /// + /// + public static object GetPropertyByName(string deviceObjectPath, string propertyName) + { + var obj = FindObjectOnPath(deviceObjectPath); + if(obj == null) + return "{ \"error\":\"No Device\"}"; + + CType t = obj.GetType(); + + var prop = t.GetProperty(propertyName); + if (prop != null) + { + return prop; + } + else + { + Debug.Console(1, "Unable to find Property: {0} on Device with path: {1}", propertyName, deviceObjectPath); + return null; + } + } + /// - /// + /// Gets the methods on a device /// /// /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs index 9fb4c1e1..60a09df8 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs @@ -32,6 +32,8 @@ namespace PepperDash.Essentials.Core List LinkedInputSigs = new List(); List LinkedComplementInputSigs = new List(); + List LinkedCrestronFeedbacks = new List(); + public BoolFeedback(Func valueFunc) : this(null, valueFunc) { @@ -56,28 +58,63 @@ namespace PepperDash.Essentials.Core } } + /// + /// Links an input sig + /// + /// public void LinkInputSig(BoolInputSig sig) { LinkedInputSigs.Add(sig); UpdateSig(sig); } + /// + /// Unlinks an inputs sig + /// + /// public void UnlinkInputSig(BoolInputSig sig) { LinkedInputSigs.Remove(sig); } + /// + /// Links an input sig to the complement value + /// + /// public void LinkComplementInputSig(BoolInputSig sig) { LinkedComplementInputSigs.Add(sig); UpdateComplementSig(sig); } + /// + /// Unlinks an input sig to the complement value + /// + /// public void UnlinkComplementInputSig(BoolInputSig sig) { LinkedComplementInputSigs.Remove(sig); } + /// + /// Links a Crestron Feedback object + /// + /// + public void LinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) + { + LinkedCrestronFeedbacks.Add(feedback); + UpdateCrestronFeedback(feedback); + } + + /// + /// + /// + /// + public void UnlinkCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) + { + LinkedCrestronFeedbacks.Remove(feedback); + } + public override string ToString() { return (InTestMode ? "TEST -- " : "") + BoolValue.ToString(); @@ -103,6 +140,11 @@ namespace PepperDash.Essentials.Core { sig.BoolValue = !_BoolValue; } + + void UpdateCrestronFeedback(Crestron.SimplSharpPro.DeviceSupport.Feedback feedback) + { + feedback.State = _BoolValue; + } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 28128a65..61d1ffce 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -131,6 +131,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Touchpanels/Mpc3Touchpanel.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Touchpanels/Mpc3Touchpanel.cs index dd266c24..01bae32d 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Touchpanels/Mpc3Touchpanel.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Touchpanels/Mpc3Touchpanel.cs @@ -6,9 +6,14 @@ using Crestron.SimplSharp; using Crestron.SimplSharpPro; using PepperDash.Core; +using PepperDash.Essentials.Core; namespace PepperDash.Essentials.Core.Touchpanels { + /// + /// A wrapper class for the touchpanel portion of an MPC3 class process to allow for configurable + /// behavior of the keybad buttons + /// public class Mpc3TouchpanelController : Device { MPC3Basic _Touchpanel; @@ -21,13 +26,40 @@ namespace PepperDash.Essentials.Core.Touchpanels _Touchpanel = processor.ControllerTouchScreenSlotDevice as MPC3Basic; _Buttons = buttons; - _Touchpanel.ButtonStateChange += new Crestron.SimplSharpPro.DeviceSupport.ButtonEventHandler(_Touchpanel_ButtonStateChange); + + + AddPostActivationAction(() => + { + // Link up the button feedbacks to the specified BoolFeedbacks + foreach (var button in _Buttons) + { + var feedbackConfig = button.Value.Feedback; + var device = DeviceManager.GetDeviceForKey(feedbackConfig.DeviceKey) as Device; + if (device != null) + { + var feedback = device.GetFeedbackProperty(feedbackConfig.BoolFeedbackName) as BoolFeedback; + if (feedback != null) + { + // Link to the Crestron Feedback corresponding to the button number + feedback.LinkCrestronFeedback(_Touchpanel.Feedbacks[button.Key]); + } + else + { + Debug.Console(1, this, "Unable to get BoolFeedback with name: {0} from device: {1}", feedbackConfig.BoolFeedbackName, device.Key); + } + } + else + { + Debug.Console(1, this, "Unable to get device with key: {0}", feedbackConfig.DeviceKey); + } + } + }); } void _Touchpanel_ButtonStateChange(GenericBase device, Crestron.SimplSharpPro.DeviceSupport.ButtonEventArgs args) { - Debug.Console(1, this, "Button {0}, {1}", args.Button.Number, args.NewButtonState); + Debug.Console(1, this, "Button {0} ({1}), {2}", args.Button.Number, args.Button.Name, args.NewButtonState); if (_Buttons.ContainsKey(args.Button.Number)) { var type = args.NewButtonState.ToString(); @@ -37,12 +69,14 @@ namespace PepperDash.Essentials.Core.Touchpanels /// /// Runs the function associated with this button/type. One of the following strings: - /// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased + /// Pressed, Released, Tapped, DoubleTapped, Held, HeldReleased /// /// /// public void Press(uint number, string type) { + // TODO: In future, consider modifying this to generate actions at device activation time + // to prevent the need to dynamically call the method via reflection on each button press if (!_Buttons.ContainsKey(number)) { return; } var but = _Buttons[number]; if (but.EventTypes.ContainsKey(type)) @@ -55,7 +89,7 @@ namespace PepperDash.Essentials.Core.Touchpanels } /// - /// + /// Represents the configuration of a keybad buggon /// public class KeypadButton { @@ -74,7 +108,7 @@ namespace PepperDash.Essentials.Core.Touchpanels /// public class KeypadButtonFeedback { - public string Type { get; set; } - public string LinkToKey { get; set; } + public string DeviceKey { get; set; } + public string BoolFeedbackName { get; set; } } } \ No newline at end of file From 1b096de377529a648c4a14a64e7a6595b7ec1c7e Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 12 Mar 2020 12:46:21 -0600 Subject: [PATCH 3/3] Moved generation of Mpc3TouchpanelController device from core device factory into ControlSystem LoadDevices() method. --- PepperDashEssentials/ControlSystem.cs | 19 +++++++++++++++++++ .../Factory/DeviceFactory.cs | 15 --------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index a88d932b..5b8579f5 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -428,11 +428,30 @@ namespace PepperDash.Essentials DeviceManager.AddDevice(dmpsRoutingController); } + else if (this.ControllerPrompt.IndexOf("mpc3", StringComparison.OrdinalIgnoreCase) > -1) + { + Debug.Console(2, "MPC3 processor type detected. Adding Mpc3TouchpanelController."); + + var butToken = devConf.Properties["buttons"]; + if (butToken != null) + { + var buttons = butToken.ToObject>(); + var tpController = new Essentials.Core.Touchpanels.Mpc3TouchpanelController(devConf.Key, devConf.Name, Global.ControlSystem, buttons); + DeviceManager.AddDevice(tpController); + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Unable to deserialize buttons collection for device: {0}", devConf.Key); + } + + } else { Debug.Console(2, "************Processor is not DMPS type***************"); } + + continue; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs index 45779dd9..c07bc010 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Factory/DeviceFactory.cs @@ -83,21 +83,6 @@ namespace PepperDash.Essentials.Core return new C2nRthsController(key, name, new C2nRths(cresnetId, Global.ControlSystem)); } - if (typeName.StartsWith("mpc3")) - { - var butToken = dc.Properties["buttons"]; - if (butToken != null) - { - var buttons = butToken.ToObject>(); - return new Mpc3TouchpanelController(key, name, Global.ControlSystem, buttons); - } - else - { - Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Unable to deserialize buttons collection for device: {0}", key); - } - } - - return null; }