From 4c50d6980fbbe86c53bbf45e7c4ec55f0b02c4c8 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 14 Jul 2021 14:38:18 -0600 Subject: [PATCH 01/27] #740 Adds IPartitionStateProvider interface and adds to GlsParitionSensorController --- .../GlsPartitionSensorController.cs | 2 +- .../PartitionSensor/IPartitionStateProvider.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index b0b58f34..768e476b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -13,7 +13,7 @@ using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { [Description("Wrapper class for GLS Cresnet Partition Sensor")] - public class GlsPartitionSensorController : CrestronGenericBridgeableBaseDevice + public class GlsPartitionSensorController : CrestronGenericBridgeableBaseDevice, IPartitionStateProvider { private GlsPartCn _partitionSensor; diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs new file mode 100644 index 00000000..0080e472 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + /// + /// Describes the functionality of a device that senses and provides partition state + /// + public interface IPartitionStateProvider + { + BoolFeedback PartitionSensedFeedback { get; } + } +} \ No newline at end of file From d97ca6d5a437b8be80b8cca25518de7f16476670 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 14 Jul 2021 14:42:13 -0600 Subject: [PATCH 02/27] #741 Adds EssentialsRoomCombinerPropertiesConfig --- .../PepperDash_Essentials_Core.csproj | 2 + .../EssentialsRoomCombinerPropertiesConfig.cs | 72 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index 6e48fd66..7e18606f 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -233,6 +233,7 @@ + @@ -287,6 +288,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs new file mode 100644 index 00000000..5f1adcfa --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; + +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core.Room +{ + /// + /// Config properties for an EssentialsRoomCombiner device + /// + public class EssentialsRoomCombinerPropertiesConfig + { + [JsonProperty("partitions")] + public List Partitions {get; set;} + + [JsonProperty("scenarios")] + public List Scenarios { get; set; } + + [JsonProperty("rooms")] + public List Rooms {get; set;} + } + + /// + /// Config properties for a partition that separates rooms + /// + public class PartitionConfig : IKeyName + { + /// + /// Key of the device that implements IPartitionStateProvider to provide the state of the partition + /// + [JsonProperty("deviceKey")] + public string DeviceKey { get; set; } + + /// + /// Keys of the rooms that this partion would be located between + /// + [JsonProperty("roomKeys")] + public List RoomKeys { get; set; } + } + + /// + /// Config propeties for a room combination scenario + /// + public class RoomCombinationScenario : IKeyName + { + [JsonProperty("partitionStates")] + public List PartitionStates { get; set; } + + [JsonProperty("enabledRoomKeys")] + public List EnabledRoomKeys { get; set; } + + [JsonProperty("actions")] + public List Actions { get; set; } + } + + /// + /// Config properties to represent the state of a partition sensor in a RoomCombinationScenario + /// + public class PartitionState + { + [JsonProperty("partitionKey")] + public string PartitionKey { get; set; } + + [JsonProperty("partitionSensedState")] + public bool PartitionSensedState { get; set; } + } +} \ No newline at end of file From 06a3dda2e47983d40d8a278dff60ff7e3f8872e3 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Wed, 14 Jul 2021 22:12:41 -0600 Subject: [PATCH 03/27] Starts on interfaces for room combination --- .../IPartitionStateProvider.cs | 13 +++++- .../PepperDash_Essentials_Core.csproj | 2 + .../EssentialsRoomCombinerPropertiesConfig.cs | 21 +++++++--- .../Room/Combining/IEssentialsRoomCombiner.cs | 41 +++++++++++++++++++ .../Room/Combining/RoomCombinationScenario.cs | 17 ++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs index 0080e472..08b8012b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs @@ -4,13 +4,24 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using PepperDash.Core; + namespace PepperDash.Essentials.Core { /// /// Describes the functionality of a device that senses and provides partition state /// - public interface IPartitionStateProvider + public interface IPartitionStateProvider : IKeyName { BoolFeedback PartitionSensedFeedback { get; } } + + public interface IManualPartitionSensor : IPartitionStateProvider + { + void SetPartitionStatePresent(); + + void SetPartitionStateNotPresent(); + + void ToggglePartitionState(); + } } \ 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 7e18606f..b65cfd62 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -289,6 +289,8 @@ + + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 5f1adcfa..74d5ebda 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -8,21 +8,30 @@ using PepperDash.Core; using Newtonsoft.Json; -namespace PepperDash.Essentials.Core.Room +namespace PepperDash.Essentials.Core { /// /// Config properties for an EssentialsRoomCombiner device /// public class EssentialsRoomCombinerPropertiesConfig { + /// + /// The list of partitions that device the rooms + /// [JsonProperty("partitions")] public List Partitions {get; set;} + /// + /// The list of combinations scenarios for the rooms + /// [JsonProperty("scenarios")] - public List Scenarios { get; set; } + public List Scenarios { get; set; } - [JsonProperty("rooms")] - public List Rooms {get; set;} + /// + /// The list of rooms that can be combined + /// + [JsonProperty("roomMap")] + public Dictionary RoomMap {get; set;} } /// @@ -46,7 +55,7 @@ namespace PepperDash.Essentials.Core.Room /// /// Config propeties for a room combination scenario /// - public class RoomCombinationScenario : IKeyName + public class RoomCombinationScenarioConfig : IKeyName { [JsonProperty("partitionStates")] public List PartitionStates { get; set; } @@ -67,6 +76,6 @@ namespace PepperDash.Essentials.Core.Room public string PartitionKey { get; set; } [JsonProperty("partitionSensedState")] - public bool PartitionSensedState { get; set; } + public bool PartitionPresent { get; set; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs new file mode 100644 index 00000000..894dd098 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; + +namespace PepperDash.Essentials.Core +{ + /// + /// Describes the functionality for an EssentailsRoomCombiner device + /// + public interface IEssentialsRoomCombiner + { + // TODO: Update the EventArgs class as needed to specify scenario change + event EventHandler RoomCombinationScenarioChanged; + + BoolFeedback IsInAutoModeFeedback {get;} + + void SetAutoMode(); + + void SetManualMode(); + + void ToggleMode(); + + List Scenarios { get; } + + List Partitions { get; } + + void TogglePartitionState(string partitionKey); + } + + public interface IRoomCombinationScenario : IKeyName + { + BoolFeedback IsActive { get; } + + void Activate(); + } + +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs new file mode 100644 index 00000000..965428cb --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + /// + /// Represents a room combination scenario + /// + public class RoomCombinationScenario: IRoomCombinationScenario + { + + } + +} \ No newline at end of file From 7fd52814a012efb10cfdab442836571a247f0797 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 15 Jul 2021 10:11:27 -0600 Subject: [PATCH 04/27] implements IKeyName as required on config classes --- .../EssentialsRoomCombinerPropertiesConfig.cs | 12 ++++++++++++ .../Room/Combining/RoomCombinationScenario.cs | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 74d5ebda..4576ac4d 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -39,6 +39,12 @@ namespace PepperDash.Essentials.Core /// public class PartitionConfig : IKeyName { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + /// /// Key of the device that implements IPartitionStateProvider to provide the state of the partition /// @@ -57,6 +63,12 @@ namespace PepperDash.Essentials.Core /// public class RoomCombinationScenarioConfig : IKeyName { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + [JsonProperty("partitionStates")] public List PartitionStates { get; set; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs index 965428cb..94e2ed0a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Core { /// @@ -11,6 +13,18 @@ namespace PepperDash.Essentials.Core /// public class RoomCombinationScenario: IRoomCombinationScenario { + [JsonProperty("key")] + public string Key { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + public BoolFeedback IsActive { get; private set; } + + public void Activate() + { + + } } From c2e5bd290a01675cee4488266f00ef8c90416572 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Thu, 15 Jul 2021 16:40:25 -0600 Subject: [PATCH 05/27] #742 Adding EssentialsRoomCombiner device (in progress) --- .../PepperDash_Essentials_Core.csproj | 1 + .../Room/Combining/EssentialsRoomCombiner.cs | 133 ++++++++++++++++++ .../EssentialsRoomCombinerPropertiesConfig.cs | 31 ++-- .../Room/Combining/IEssentialsRoomCombiner.cs | 49 ++++++- .../Room/Combining/RoomCombinationScenario.cs | 58 +++++++- 5 files changed, 257 insertions(+), 15 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index b65cfd62..38a532ba 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -288,6 +288,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs new file mode 100644 index 00000000..6e9a0afb --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner + { + private EssentialsRoomCombinerPropertiesConfig _propertiesConfig; + + private IRoomCombinationScenario _currentScenario; + + private List _rooms; + + private bool isInAutoMode; + + public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props) + : base(key) + { + _propertiesConfig = props; + + IsInAutoModeFeedback = new BoolFeedback(() => isInAutoMode); + + // default to auto mode + isInAutoMode = true; + + if (_propertiesConfig.defaultToManualMode) + { + isInAutoMode = false; + } + + IsInAutoModeFeedback.FireUpdate(); + + CreateScenarios(); + + SetupPartitionStateProviders(); + + SetRooms(); + } + + void CreateScenarios() + { + foreach (var scenarioConfig in _propertiesConfig.Scenarios) + { + var scenario = new RoomCombinationScenario(scenarioConfig); + } + } + + void SetRooms() + { + foreach (var roomKey in _propertiesConfig.RoomKeys) + { + var room = DeviceManager.GetDeviceForKey(roomKey) as IEssentialsRoom; + if (room != null) + { + _rooms.Add(room); + } + } + } + + void SetupPartitionStateProviders() + { + + } + + #region IEssentialsRoomCombiner Members + + public event EventHandler RoomCombinationScenarioChanged; + + public IRoomCombinationScenario CurrentScenario + { + get + { + return _currentScenario; + } + set + { + if (value != _currentScenario) + { + _currentScenario = value; + var handler = RoomCombinationScenarioChanged; + if (handler != null) + { + handler(this, new EventArgs()); + } + } + } + } + + public BoolFeedback IsInAutoModeFeedback { get; private set; } + + public void SetAutoMode() + { + isInAutoMode = true; + IsInAutoModeFeedback.FireUpdate(); + } + + public void SetManualMode() + { + isInAutoMode = false; + IsInAutoModeFeedback.FireUpdate(); + } + + public void ToggleMode() + { + isInAutoMode = !isInAutoMode; + IsInAutoModeFeedback.FireUpdate(); + } + + public List RoomCombinationScenarios { get; private set; } + + public List PartitionStateProviders { get; private set; } + + public void TogglePartitionState(string partitionKey) + { + var partition = PartitionStateProviders.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IManualPartitionSensor; + + if (partition != null) + { + partition.ToggglePartitionState(); + } + } + + public void SetRoomCombinationScenario(string scenarioKey) + { + + } + + #endregion + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 4576ac4d..95b97c35 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -28,10 +28,22 @@ namespace PepperDash.Essentials.Core public List Scenarios { get; set; } /// - /// The list of rooms that can be combined + /// The list of rooms keys that can be combined /// [JsonProperty("roomMap")] - public Dictionary RoomMap {get; set;} + public List RoomKeys {get; set;} + + /// + /// Set to true to default to manual mode + /// + [JsonProperty("defaultToManualMode")] + public bool defaultToManualMode { get; set; } + + /// + /// The key of the scenario to default to at system startup if in manual mode + /// + [JsonProperty("defaultScenarioKey")] + public string defaultScenarioKey { get; set; } } /// @@ -54,8 +66,8 @@ namespace PepperDash.Essentials.Core /// /// Keys of the rooms that this partion would be located between /// - [JsonProperty("roomKeys")] - public List RoomKeys { get; set; } + [JsonProperty("adjacentRoomKeys")] + public List AdjacentRoomKeys { get; set; } } /// @@ -72,11 +84,14 @@ namespace PepperDash.Essentials.Core [JsonProperty("partitionStates")] public List PartitionStates { get; set; } - [JsonProperty("enabledRoomKeys")] - public List EnabledRoomKeys { get; set; } + [JsonProperty("roomMap")] + public Dictionary RoomMap { get; set; } - [JsonProperty("actions")] - public List Actions { get; set; } + [JsonProperty("activationActions")] + public List ActivationActions { get; set; } + + [JsonProperty("deactivationActions")] + public List DeactivationActions { get; set; } } /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs index 894dd098..142e066c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs @@ -13,28 +13,69 @@ namespace PepperDash.Essentials.Core /// public interface IEssentialsRoomCombiner { - // TODO: Update the EventArgs class as needed to specify scenario change + /// + /// Indicates that the room combination scenario has changed + /// event EventHandler RoomCombinationScenarioChanged; + /// + /// The current room combination scenario + /// + IRoomCombinationScenario CurrentScenario { get; } + + /// + /// When true, indicates the current mode is auto mode + /// BoolFeedback IsInAutoModeFeedback {get;} + /// + /// Sets auto mode + /// void SetAutoMode(); + /// + /// Sets manual mode + /// void SetManualMode(); + /// + /// Toggles the current mode between auto and manual + /// void ToggleMode(); - List Scenarios { get; } + /// + /// The available room combinatino scenarios + /// + List RoomCombinationScenarios { get; } - List Partitions { get; } + /// + /// The partition + /// + List PartitionStateProviders { get; } + /// + /// Toggles the state of a manual partition sensor + /// + /// void TogglePartitionState(string partitionKey); + + /// + /// Sets the room combination scenario (if in manual mode) + /// + /// + void SetRoomCombinationScenario(string scenarioKey); } public interface IRoomCombinationScenario : IKeyName { - BoolFeedback IsActive { get; } + /// + /// When true, indicates that this room combination scenario is active + /// + BoolFeedback IsActiveFeedback { get; } + /// + /// Activates this room combination scenario + /// void Activate(); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs index 94e2ed0a..c1d75c3e 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs @@ -13,17 +13,69 @@ namespace PepperDash.Essentials.Core /// public class RoomCombinationScenario: IRoomCombinationScenario { - [JsonProperty("key")] + private RoomCombinationScenarioConfig _config; + public string Key { get; set; } - [JsonProperty("name")] public string Name { get; set; } - public BoolFeedback IsActive { get; private set; } + public List PartitionStates { get; private set; } + + public Dictionary EnabledRoomMap { get; set; } + + private bool _isActive; + + public BoolFeedback IsActiveFeedback { get; private set; } + + List activationActions; + + List deactivationActions; + + public RoomCombinationScenario(RoomCombinationScenarioConfig config) + { + Key = config.Key; + + Name = config.Name; + + PartitionStates = config.PartitionStates; + + EnabledRoomMap = config.RoomMap; + + activationActions = config.ActivationActions; + + deactivationActions = config.DeactivationActions; + + _config = config; + + IsActiveFeedback = new BoolFeedback(() => _isActive); + } public void Activate() { + if (activationActions != null) + { + foreach (var action in activationActions) + { + DeviceJsonApi.DoDeviceAction(action); + } + } + _isActive = true; + IsActiveFeedback.FireUpdate(); + } + + public void Deactivate() + { + if (deactivationActions != null) + { + foreach (var action in deactivationActions) + { + DeviceJsonApi.DoDeviceAction(action); + } + } + + _isActive = false; + IsActiveFeedback.FireUpdate(); } } From e3920132bfa5acbd0b6c00ba9fd7458dc3d32f73 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 14:11:27 -0600 Subject: [PATCH 06/27] #743 Adds SetValueFunc() to all Feedback types --- .../PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs | 5 +++++ .../PepperDashEssentialsBase/Feedbacks/IntFeedback.cs | 6 ++++++ .../PepperDashEssentialsBase/Feedbacks/StringFeedback.cs | 5 ++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs index f46b4767..055ed5b6 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolFeedback.cs @@ -62,6 +62,11 @@ namespace PepperDash.Essentials.Core ValueFunc = valueFunc; } + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } + public override void FireUpdate() { bool newValue = InTestMode ? TestValue : ValueFunc.Invoke(); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/IntFeedback.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/IntFeedback.cs index 25390c2c..53bae09a 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/IntFeedback.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/IntFeedback.cs @@ -51,6 +51,12 @@ namespace PepperDash.Essentials.Core ValueFunc = valueFunc; } + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } + + public override void FireUpdate() { var newValue = InTestMode ? TestValue : ValueFunc.Invoke(); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/StringFeedback.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/StringFeedback.cs index 56251a2e..fb5cccb5 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/StringFeedback.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/StringFeedback.cs @@ -52,7 +52,10 @@ namespace PepperDash.Essentials.Core ValueFunc = valueFunc; } - + public void SetValueFunc(Func newFunc) + { + ValueFunc = newFunc; + } public override void FireUpdate() { From 7b7ec533558ee74d93b13f6b035ffa65d2ecce9e Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 15:35:52 -0600 Subject: [PATCH 07/27] #742 Updates to room combination interfaces and EssentialsRoomCombiner and EssentialsPartitionController --- .../EssentialsPartitionController.cs | 149 ++++++++++++++++++ .../GlsPartitionSensorController.cs | 10 +- .../IPartitionStateProvider.cs | 13 +- .../PepperDash_Essentials_Core.csproj | 1 + .../Room/Combining/EssentialsRoomCombiner.cs | 38 ++++- .../EssentialsRoomCombinerPropertiesConfig.cs | 4 +- .../Room/Combining/IEssentialsRoomCombiner.cs | 14 +- .../Room/Combining/RoomCombinationScenario.cs | 4 +- 8 files changed, 218 insertions(+), 15 deletions(-) create mode 100644 essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/EssentialsPartitionController.cs diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/EssentialsPartitionController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/EssentialsPartitionController.cs new file mode 100644 index 00000000..7066be0e --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/EssentialsPartitionController.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +namespace PepperDash.Essentials.Core +{ + /// + /// Represents an abstract controller device for a partition dividing rooms that are combinable + /// + /// In Auto mode, it can use a partition sensor to automatically determine whether the partition is present. + /// + /// In Manual mode it accepts user input to tell it whether the partition is present. + /// + public class EssentialsPartitionController : IPartitionController + { + private IPartitionStateProvider _partitionSensor; + + private bool isInAutoMode; + + private bool partitionPresent; + + public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List adjacentRoomKeys) + { + Key = key; + + Name = name; + + AdjacentRoomKeys = adjacentRoomKeys; + + if (sensor != null) + { + _partitionSensor = sensor; + + if (!defaultToManualMode) + { + SetAutoMode(); + } + else + { + SetManualMode(); + } + } + else + { + SetManualMode(); + } + + PartitionPresentFeedback.FireUpdate(); + } + + void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + if (isInAutoMode) + { + PartitionPresentFeedback.FireUpdate(); + } + } + + #region IPartitionController Members + + public List AdjacentRoomKeys { get; private set; } + + public void SetAutoMode() + { + isInAutoMode = true; + if (PartitionPresentFeedback != null) + { + PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue); + } + else + { + PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionPresentFeedback.BoolValue); + } + + if (_partitionSensor != null) + { + _partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; + } + } + + public void SetManualMode() + { + isInAutoMode = false; + if (PartitionPresentFeedback != null) + { + PartitionPresentFeedback.SetValueFunc(() => partitionPresent); + } + else + { + PartitionPresentFeedback = new BoolFeedback(() => partitionPresent); + } + + if (_partitionSensor != null) + { + _partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange; + } + } + + + public void SetPartitionStatePresent() + { + if (!isInAutoMode) + { + partitionPresent = true; + PartitionPresentFeedback.FireUpdate(); + } + } + + public void SetPartitionStateNotPresent() + { + if (!isInAutoMode) + { + partitionPresent = false; + PartitionPresentFeedback.FireUpdate(); + } + } + + public void ToggglePartitionState() + { + if (!isInAutoMode) + { + partitionPresent = !partitionPresent; + PartitionPresentFeedback.FireUpdate(); + } + } + + #endregion + + #region IPartitionStateProvider Members + + public BoolFeedback PartitionPresentFeedback { get; private set; } + + #endregion + + #region IKeyName Members + + public string Name { get; private set; } + + #endregion + + #region IKeyed Members + + public string Key { get; private set; } + + #endregion + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index 768e476b..752a7107 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Core public StringFeedback NameFeedback { get; private set; } public BoolFeedback EnableFeedback { get; private set; } - public BoolFeedback PartitionSensedFeedback { get; private set; } + public BoolFeedback PartitionPresentFeedback { get; private set; } public BoolFeedback PartitionNotSensedFeedback { get; private set; } public IntFeedback SensitivityFeedback { get; private set; } @@ -40,7 +40,7 @@ namespace PepperDash.Essentials.Core NameFeedback = new StringFeedback(() => Name); EnableFeedback = new BoolFeedback(() => _partitionSensor.EnableFeedback.BoolValue); - PartitionSensedFeedback = new BoolFeedback(() => _partitionSensor.PartitionSensedFeedback.BoolValue); + PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionSensedFeedback.BoolValue); PartitionNotSensedFeedback = new BoolFeedback(() => _partitionSensor.PartitionNotSensedFeedback.BoolValue); SensitivityFeedback = new IntFeedback(() => _partitionSensor.SensitivityFeedback.UShortValue); @@ -61,7 +61,7 @@ namespace PepperDash.Essentials.Core } case (GlsPartCn.PartitionSensedFeedbackEventId): { - PartitionSensedFeedback.FireUpdate(); + PartitionPresentFeedback.FireUpdate(); break; } case (GlsPartCn.PartitionNotSensedFeedbackEventId): @@ -186,7 +186,7 @@ namespace PepperDash.Essentials.Core // link output to simpl IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); EnableFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Enable.JoinNumber]); - PartitionSensedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionSensed.JoinNumber]); + PartitionPresentFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionSensed.JoinNumber]); PartitionNotSensedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionNotSensed.JoinNumber]); SensitivityFeedback.LinkInputSig(trilist.UShortInput[joinMap.Sensitivity.JoinNumber]); @@ -216,7 +216,7 @@ namespace PepperDash.Essentials.Core IsOnline.FireUpdate(); NameFeedback.FireUpdate(); EnableFeedback.FireUpdate(); - PartitionSensedFeedback.FireUpdate(); + PartitionPresentFeedback.FireUpdate(); PartitionNotSensedFeedback.FireUpdate(); SensitivityFeedback.FireUpdate(); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs index 08b8012b..faf84015 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs @@ -13,15 +13,24 @@ namespace PepperDash.Essentials.Core /// public interface IPartitionStateProvider : IKeyName { - BoolFeedback PartitionSensedFeedback { get; } + BoolFeedback PartitionPresentFeedback { get; } } - public interface IManualPartitionSensor : IPartitionStateProvider + /// + /// Describes the functionality of a device that can provide partition state either manually via user input or optionally via a sensor state + /// + public interface IPartitionController : IPartitionStateProvider { + List AdjacentRoomKeys { get; set; } + void SetPartitionStatePresent(); void SetPartitionStateNotPresent(); void ToggglePartitionState(); + + void SetManualMode(); + + void SetAutoMode(); } } \ 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 38a532ba..53779a0d 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -233,6 +233,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs index 6e9a0afb..bb3040ff 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -42,14 +42,19 @@ namespace PepperDash.Essentials.Core void CreateScenarios() { + RoomCombinationScenarios = new List(); + foreach (var scenarioConfig in _propertiesConfig.Scenarios) { var scenario = new RoomCombinationScenario(scenarioConfig); + RoomCombinationScenarios.Add(scenario); } } void SetRooms() { + _rooms = new List(); + foreach (var roomKey in _propertiesConfig.RoomKeys) { var room = DeviceManager.GetDeviceForKey(roomKey) as IEssentialsRoom; @@ -62,7 +67,36 @@ namespace PepperDash.Essentials.Core void SetupPartitionStateProviders() { + foreach (var pConfig in _propertiesConfig.Partitions) + { + var sensor = DeviceManager.GetDeviceForKey(pConfig.DeviceKey) as IPartitionStateProvider; + var partition = new EssentialsPartitionController(pConfig.Key, pConfig.Name, sensor, _propertiesConfig.defaultToManualMode, pConfig.AdjacentRoomKeys); + + partition.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange; + + Partitions.Add(partition); + } + } + + void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) + { + DetermineRoomCombinationScenario(); + } + + + /// + /// Determines the current room combination scenario based on the state of the partition sensors + /// + void DetermineRoomCombinationScenario() + { + //RoomCombinationScenarios.FirstOrDefault((s) => + //{ + // foreach (var partitionState in s.PartitionStates) + // { + // var partition = Partitions.FirstOrDefault( + // } + //}); } #region IEssentialsRoomCombiner Members @@ -111,11 +145,11 @@ namespace PepperDash.Essentials.Core public List RoomCombinationScenarios { get; private set; } - public List PartitionStateProviders { get; private set; } + public List Partitions { get; private set; } public void TogglePartitionState(string partitionKey) { - var partition = PartitionStateProviders.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IManualPartitionSensor; + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IPartitionController; if (partition != null) { diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 95b97c35..7fa215d5 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -84,8 +84,8 @@ namespace PepperDash.Essentials.Core [JsonProperty("partitionStates")] public List PartitionStates { get; set; } - [JsonProperty("roomMap")] - public Dictionary RoomMap { get; set; } + [JsonProperty("uiMap")] + public Dictionary UiMap { get; set; } [JsonProperty("activationActions")] public List ActivationActions { get; set; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs index 142e066c..c5fa0c50 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs @@ -11,7 +11,7 @@ namespace PepperDash.Essentials.Core /// /// Describes the functionality for an EssentailsRoomCombiner device /// - public interface IEssentialsRoomCombiner + public interface IEssentialsRoomCombiner : IKeyed { /// /// Indicates that the room combination scenario has changed @@ -51,7 +51,7 @@ namespace PepperDash.Essentials.Core /// /// The partition /// - List PartitionStateProviders { get; } + List Partitions { get; } /// /// Toggles the state of a manual partition sensor @@ -77,6 +77,16 @@ namespace PepperDash.Essentials.Core /// Activates this room combination scenario /// void Activate(); + + /// + /// The state of the partitions that would activate this scenario + /// + List PartitionStates { get; } + + /// + /// The mapping of UIs by key to rooms by key + /// + Dictionary UiMap { get; set; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs index c1d75c3e..a5534edc 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/RoomCombinationScenario.cs @@ -21,7 +21,7 @@ namespace PepperDash.Essentials.Core public List PartitionStates { get; private set; } - public Dictionary EnabledRoomMap { get; set; } + public Dictionary UiMap { get; set; } private bool _isActive; @@ -39,7 +39,7 @@ namespace PepperDash.Essentials.Core PartitionStates = config.PartitionStates; - EnabledRoomMap = config.RoomMap; + UiMap = config.UiMap; activationActions = config.ActivationActions; From 6f6ca50c373e2e3327f7ad48f30f7b188575f454 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 15:36:59 -0600 Subject: [PATCH 08/27] Removes set from interface --- .../PartitionSensor/IPartitionStateProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs index faf84015..adb420b7 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/IPartitionStateProvider.cs @@ -21,7 +21,7 @@ namespace PepperDash.Essentials.Core /// public interface IPartitionController : IPartitionStateProvider { - List AdjacentRoomKeys { get; set; } + List AdjacentRoomKeys { get; } void SetPartitionStatePresent(); From 9795637d755a80a16ee6b0ce55029d84e88b6b9a Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 16:09:38 -0600 Subject: [PATCH 09/27] #742 EssentialsRoomCombiner substantially complete. Adds debounce timer when changing scenarios --- .../Room/Combining/EssentialsRoomCombiner.cs | 97 +++++++++++++++++-- .../EssentialsRoomCombinerPropertiesConfig.cs | 3 + 2 files changed, 91 insertions(+), 9 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs index bb3040ff..cbbb58d1 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using PepperDash.Core; + namespace PepperDash.Essentials.Core { public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner @@ -16,11 +18,20 @@ namespace PepperDash.Essentials.Core private bool isInAutoMode; + private CTimer _scenarioChangeDebounceTimer; + + private int _scenarioChangeDebounceTimeSeconds = 10; // default to 10s + public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props) : base(key) { _propertiesConfig = props; + if (_propertiesConfig.ScenarioChangeDebounceTimeSeconds > 0) + { + _scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds; + } + IsInAutoModeFeedback = new BoolFeedback(() => isInAutoMode); // default to auto mode @@ -81,22 +92,61 @@ namespace PepperDash.Essentials.Core void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e) { - DetermineRoomCombinationScenario(); + StartDebounceTimer(); } + void StartDebounceTimer() + { + var time = _scenarioChangeDebounceTimeSeconds * 1000; + + if (_scenarioChangeDebounceTimer == null) + { + _scenarioChangeDebounceTimer = new CTimer((o) => DetermineRoomCombinationScenario(), time); + } + else + { + _scenarioChangeDebounceTimer.Reset(time); + } + } /// /// Determines the current room combination scenario based on the state of the partition sensors /// void DetermineRoomCombinationScenario() { - //RoomCombinationScenarios.FirstOrDefault((s) => - //{ - // foreach (var partitionState in s.PartitionStates) - // { - // var partition = Partitions.FirstOrDefault( - // } - //}); + if (_scenarioChangeDebounceTimer != null) + { + _scenarioChangeDebounceTimer.Dispose(); + _scenarioChangeDebounceTimer = null; + } + + var currentScenario = RoomCombinationScenarios.FirstOrDefault((s) => + { + // iterate the partition states + foreach (var partitionState in s.PartitionStates) + { + // get the partition by key + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); + + if (partition != null && partitionState.PartitionPresent != partition.PartitionPresentFeedback.BoolValue) + { + // the partition can't be found or the state doesn't match + return false; + } + else + { + // check the next partition state + continue; + } + } + // if it hasn't returned false by now we have the matching scenario + return true; + }); + + if (currentScenario != null) + { + CurrentScenario = currentScenario; + } } #region IEssentialsRoomCombiner Members @@ -114,6 +164,7 @@ namespace PepperDash.Essentials.Core if (value != _currentScenario) { _currentScenario = value; + Debug.Console(1, this, "Current Scenario: {0}", _currentScenario.Name); var handler = RoomCombinationScenarioChanged; if (handler != null) { @@ -145,7 +196,7 @@ namespace PepperDash.Essentials.Core public List RoomCombinationScenarios { get; private set; } - public List Partitions { get; private set; } + public List Partitions { get; private set; } public void TogglePartitionState(string partitionKey) { @@ -159,7 +210,35 @@ namespace PepperDash.Essentials.Core public void SetRoomCombinationScenario(string scenarioKey) { + if (isInAutoMode) + { + Debug.Console(0, this, "Cannot set room combination scenario when in auto mode. Set to auto mode first."); + return; + } + // Get the scenario + var scenario = RoomCombinationScenarios.FirstOrDefault((s) => s.Key.Equals(scenarioKey)); + + // Set the parition states from the scenario manually + if (scenario != null) + { + foreach (var partitionState in scenario.PartitionStates) + { + var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionState.PartitionKey)); + + if (partition != null) + { + if (partitionState.PartitionPresent) + { + partition.SetPartitionStatePresent(); + } + else + { + partition.SetPartitionStateNotPresent(); + } + } + } + } } #endregion diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs index 7fa215d5..05295f42 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombinerPropertiesConfig.cs @@ -44,6 +44,9 @@ namespace PepperDash.Essentials.Core /// [JsonProperty("defaultScenarioKey")] public string defaultScenarioKey { get; set; } + + [JsonProperty("scenarioChangeDebounceTimeSeconds")] + public int ScenarioChangeDebounceTimeSeconds { get; set; } } /// From 377cccf912e9dd963545df32e1a02afcbe0bd8af Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 16 Jul 2021 16:10:06 -0600 Subject: [PATCH 10/27] Updates type for Partitions on IEssentialsRoomController --- .../Room/Combining/IEssentialsRoomCombiner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs index c5fa0c50..c0c8101b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/IEssentialsRoomCombiner.cs @@ -51,7 +51,7 @@ namespace PepperDash.Essentials.Core /// /// The partition /// - List Partitions { get; } + List Partitions { get; } /// /// Toggles the state of a manual partition sensor From dfaaa3f6bc68b89b6e7711b68ca8149b74546123 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 19 Jul 2021 15:41:10 -0600 Subject: [PATCH 11/27] #742 Adds factory for EssentialsRoomCombiner --- .../PepperDashEssentials.csproj | 3 +- .../Room/Types/IEssentialsHuddleSpaceRoom.cs | 48 -- .../Interfaces/IEssentialsHuddleSpaceRoom.cs | 24 + .../Interfaces/IEssentialsHuddleVtc1Room.cs | 25 + .../EssentialsHuddleTechPageDriver.cs | 648 +++++++++--------- .../GlsPartitionSensorController.cs | 2 +- .../Room/Combining/EssentialsRoomCombiner.cs | 24 +- 7 files changed, 398 insertions(+), 376 deletions(-) delete mode 100644 PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs create mode 100644 PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleSpaceRoom.cs create mode 100644 PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 14bd450a..d172076a 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -149,7 +149,8 @@ - + + diff --git a/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs deleted file mode 100644 index efc126f6..00000000 --- a/PepperDashEssentials/Room/Types/IEssentialsHuddleSpaceRoom.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.DeviceTypeInterfaces; -using PepperDash.Essentials.Room.Config; -using PepperDash.Essentials.Core.Devices; -using PepperDash.Essentials.Devices.Common.Codec; -using PepperDash.Essentials.Devices.Common.VideoCodec; -using PepperDash.Essentials.Devices.Common.AudioCodec; - - -using PepperDash.Core; - -namespace PepperDash.Essentials -{ - public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay - { - bool ExcludeFromGlobalFunctions { get; } - - void RunRouteAction(string routeKey); - - EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } - - IBasicVolumeControls CurrentVolumeControls { get; } - - event EventHandler CurrentVolumeDeviceChange; - } - - public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, - IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback - { - EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } - - void RunRouteAction(string routeKey); - - IHasScheduleAwareness ScheduleSource { get; } - - BoolFeedback InCallFeedback { get; } - - BoolFeedback PrivacyModeIsOnFeedback { get; } - - string DefaultCodecRouteString { get; } - } -} \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleSpaceRoom.cs new file mode 100644 index 00000000..c7f68e8b --- /dev/null +++ b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleSpaceRoom.cs @@ -0,0 +1,24 @@ +using System; + +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Room.Config; + + + +namespace PepperDash.Essentials +{ + public interface IEssentialsHuddleSpaceRoom : IEssentialsRoom, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasDefaultDisplay + { + bool ExcludeFromGlobalFunctions { get; } + + void RunRouteAction(string routeKey); + + EssentialsHuddleRoomPropertiesConfig PropertiesConfig { get; } + + IBasicVolumeControls CurrentVolumeControls { get; } + + event EventHandler CurrentVolumeDeviceChange; + } + + +} \ No newline at end of file diff --git a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs new file mode 100644 index 00000000..662988a1 --- /dev/null +++ b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs @@ -0,0 +1,25 @@ + +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Room.Config; +using PepperDash.Essentials.Devices.Common.Codec; +using PepperDash.Essentials.Devices.Common.VideoCodec; +using PepperDash.Essentials.Devices.Common.AudioCodec; + +namespace PepperDash.Essentials +{ + public interface IEssentialsHuddleVtc1Room : IEssentialsRoom, IHasCurrentSourceInfoChange, + IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec, IHasDefaultDisplay, IHasInCallFeedback + { + EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; } + + void RunRouteAction(string routeKey); + + IHasScheduleAwareness ScheduleSource { get; } + + BoolFeedback InCallFeedback { get; } + + BoolFeedback PrivacyModeIsOnFeedback { get; } + + string DefaultCodecRouteString { get; } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddleTechPageDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddleTechPageDriver.cs index b8e1dfd6..776e1034 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddleTechPageDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddleTechPageDriver.cs @@ -1,326 +1,326 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro.DeviceSupport; - -using PepperDash.Core; -using PepperDash.Essentials; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.DeviceSupport; + +using PepperDash.Core; +using PepperDash.Essentials; using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Config; -using PepperDash.Essentials.Core.SmartObjects; -using PepperDash.Essentials.Core.Touchpanels.Keyboards; -using PepperDash.Essentials.Devices.Displays; -using PepperDash.Essentials.Room.Config; - -namespace PepperDash.Essentials.UIDrivers -{ - public class EssentialsHuddleTechPageDriver : PanelDriverBase - { - /// - /// - /// - SmartObjectDynamicList MenuList; - /// - /// - /// - SubpageReferenceList StatusList; - /// - /// The list of display controls - /// - SubpageReferenceList DisplayList; - /// - /// References lines in the list against device instances - /// - Dictionary StatusListDeviceIndexes; - /// - /// - /// - JoinedSigInterlock PagesInterlock; - - /// - /// 1 - /// - public const uint JoinText = 1; - - CTimer PinAuthorizedTimer; - - EssentialsRoomTechConfig Config; - - StringBuilder PinEntryBuilder = new StringBuilder(4); - - bool IsAuthorized; - - SmartObjectNumeric PinKeypad; - - /// - /// - /// - /// - /// - public EssentialsHuddleTechPageDriver(BasicTriListWithSmartObject trilist, EssentialsRoomTechConfig config) - : base(trilist) - { - Config = config; - - PagesInterlock = new JoinedSigInterlock(trilist); - PagesInterlock.SetButDontShow(UIBoolJoin.TechSystemStatusVisible); - - trilist.SetSigFalseAction(UIBoolJoin.TechExitButton, Hide); - - MenuList = new SmartObjectDynamicList(trilist.SmartObjects[UISmartObjectJoin.TechMenuList], - true, 3100); - - MenuList.SetFeedback(1, true); // initial fb - ushort count = 0; - - MenuList.SetItemMainText(1, "System Status"); - MenuList.SetItemButtonAction(1, b => { - if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechSystemStatusVisible); - MenuList.SetFeedback(1, true); - }); - - MenuList.SetItemMainText(2, "Display Controls"); - MenuList.SetItemButtonAction(2, b => { - if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechDisplayControlsVisible); - MenuList.SetFeedback(2, true); - }); - - count = 2; - - // Don't show panel setup on iPad or xpanel - if (TriList is Crestron.SimplSharpPro.DeviceSupport.TswFt5Button) - { - count++; - MenuList.SetItemMainText(count, "Panel Setup"); - MenuList.SetItemButtonAction(count, b => - { - if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechPanelSetupVisible); - MenuList.SetFeedback(count, true); - }); - } - - MenuList.Count = count; - BuildStatusList(); - BuildDisplayList(); - SetupPinModal(); - } - - /// - /// - /// - public override void Show() - { - // divert to PIN if we need auth - if (IsAuthorized) - { - // Cancel the auth timer so we don't deauth after coming back in - if (PinAuthorizedTimer != null) - PinAuthorizedTimer.Stop(); - - TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, true); - PagesInterlock.Show(); - base.Show(); - } - else - { - TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, true); - } - } - - /// - /// - /// - public override void Hide() - { - // Leave it authorized for 60 seconds. - if (IsAuthorized) - PinAuthorizedTimer = new CTimer(o => { - IsAuthorized = false; - PinAuthorizedTimer = null; - }, 60000); - TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, false); - PagesInterlock.Hide(); - base.Hide(); - } - - /// - /// Wire up the keypad and buttons - /// - void SetupPinModal() - { - TriList.SetSigFalseAction(UIBoolJoin.PinDialogCancelPress, CancelPinDialog); - PinKeypad = new SmartObjectNumeric(TriList.SmartObjects[UISmartObjectJoin.TechPinDialogKeypad], true); - PinKeypad.Digit0.UserObject = new Action(b => { if (b)DialPinDigit('0'); }); - PinKeypad.Digit1.UserObject = new Action(b => { if (b)DialPinDigit('1'); }); - PinKeypad.Digit2.UserObject = new Action(b => { if (b)DialPinDigit('2'); }); - PinKeypad.Digit3.UserObject = new Action(b => { if (b)DialPinDigit('3'); }); - PinKeypad.Digit4.UserObject = new Action(b => { if (b)DialPinDigit('4'); }); - PinKeypad.Digit5.UserObject = new Action(b => { if (b)DialPinDigit('5'); }); - PinKeypad.Digit6.UserObject = new Action(b => { if (b)DialPinDigit('6'); }); - PinKeypad.Digit7.UserObject = new Action(b => { if (b)DialPinDigit('7'); }); - PinKeypad.Digit8.UserObject = new Action(b => { if (b)DialPinDigit('8'); }); - PinKeypad.Digit9.UserObject = new Action(b => { if (b)DialPinDigit('9'); }); - } - - /// - /// - /// - /// - void DialPinDigit(char d) - { - PinEntryBuilder.Append(d); - var len = PinEntryBuilder.Length; - SetPinDotsFeedback(len); - - // check it! - if (len == 4) - { - if (Config.Password == PinEntryBuilder.ToString()) - { - IsAuthorized = true; - SetPinDotsFeedback(0); - TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false); - Show(); - } - else - { - SetPinDotsFeedback(0); - TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, true); - new CTimer(o => - { - TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, false); - }, 1500); - } - - PinEntryBuilder.Remove(0, len); // clear it either way - } - } - - /// - /// Draws the dots as pin is entered - /// - /// - void SetPinDotsFeedback(int len) - { - TriList.SetBool(UIBoolJoin.PinDialogDot1, len >= 1); - TriList.SetBool(UIBoolJoin.PinDialogDot2, len >= 2); - TriList.SetBool(UIBoolJoin.PinDialogDot3, len >= 3); - TriList.SetBool(UIBoolJoin.PinDialogDot4, len == 4); - - } - - /// - /// Does what it says - /// - void CancelPinDialog() - { - PinEntryBuilder.Remove(0, PinEntryBuilder.Length); - TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false); - } - - - /// - /// - /// - void BuildStatusList() - { - StatusList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechStatusList, 3, 3, 3); - StatusListDeviceIndexes = new Dictionary(); - uint i = 0; - foreach (var d in DeviceManager.AllDevices) - { - // make sure it is both ICommunicationMonitor and a Device - var sd = d as ICommunicationMonitor; - if (sd == null) - continue; - var dd = sd as Device; - if(dd == null) - continue; - i++; - StatusList.StringInputSig(i, 1).StringValue = dd.Name; - StatusList.UShortInputSig(i, 1).UShortValue = (ushort)sd.CommunicationMonitor.Status; - StatusListDeviceIndexes.Add(sd, i); - sd.CommunicationMonitor.StatusChange += CommunicationMonitor_StatusChange ; - } - StatusList.Count = (ushort)i; - } - - /// - /// Builds the list of display controls - /// - void BuildDisplayList() - { - DisplayList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechDisplayControlsList, 10, 3, 3); - - var devKeys = ConfigReader.ConfigObject.Devices.Where(d => - d.Group.Equals("display", StringComparison.OrdinalIgnoreCase) - || d.Group.Equals("projector", StringComparison.OrdinalIgnoreCase)) - .Select(dd => dd.Key); - var disps = DeviceManager.AllDevices.Where(d => - devKeys.Contains(d.Key)); - ushort i = 0; - foreach (var disp in disps) - { - var display = disp as DisplayBase; - if (display != null) - { - i++; - DisplayList.StringInputSig(i, 1).StringValue = display.Name; - DisplayList.GetBoolFeedbackSig(i, 1).SetSigFalseAction(display.PowerOn); - DisplayList.GetBoolFeedbackSig(i, 2).SetSigFalseAction(display.PowerOff); - if (display is TwoWayDisplayBase) - { - var powerOnSig = DisplayList.BoolInputSig(i, 1); - (display as TwoWayDisplayBase).PowerIsOnFeedback.LinkInputSig(powerOnSig); - - var powerOffSig = DisplayList.BoolInputSig(1, 2); - (display as TwoWayDisplayBase).PowerIsOnFeedback.LinkComplementInputSig(powerOffSig); - } - DisplayList.GetBoolFeedbackSig(i, 3).SetSigFalseAction(() => - { if (display is IInputHdmi1) (display as IInputHdmi1).InputHdmi1(); }); - DisplayList.GetBoolFeedbackSig(i, 4).SetSigFalseAction(() => - { if (display is IInputHdmi2) (display as IInputHdmi2).InputHdmi2(); }); - DisplayList.GetBoolFeedbackSig(i, 5).SetSigFalseAction(() => - { if (display is IInputHdmi3) (display as IInputHdmi3).InputHdmi3(); }); - //DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() => - //{ if (display is IInputHdmi4) (display as IInputHdmi4).InputHdmi4(); }); - DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() => - { if (display is IInputDisplayPort1) (display as IInputDisplayPort1).InputDisplayPort1(); }); - - - // Figure out some way to provide current input feedback - if (display is TwoWayDisplayBase) - { - (display as TwoWayDisplayBase).CurrentInputFeedback.OutputChange += CurrentInputFeedback_OutputChange; - } - } - - - } - - DisplayList.Count = i; - } - - - void CurrentInputFeedback_OutputChange(object sender, EventArgs e) - { - - } - - /// - /// - /// - void CommunicationMonitor_StatusChange(object sender, MonitorStatusChangeEventArgs e) - { - var c = sender as ICommunicationMonitor; - if (StatusListDeviceIndexes.ContainsKey(c)) - { - var i = StatusListDeviceIndexes[c]; - StatusList.UShortInputSig(i, 1).UShortValue = (ushort)e.Status; - } - } - } +using PepperDash.Essentials.Core.Config; +using PepperDash.Essentials.Core.SmartObjects; +using PepperDash.Essentials.Core.Touchpanels.Keyboards; +using PepperDash.Essentials.Devices.Displays; +using PepperDash.Essentials.Room.Config; + +namespace PepperDash.Essentials.UIDrivers +{ + public class EssentialsHuddleTechPageDriver : PanelDriverBase + { + /// + /// + /// + SmartObjectDynamicList MenuList; + /// + /// + /// + SubpageReferenceList StatusList; + /// + /// The list of display controls + /// + SubpageReferenceList DisplayList; + /// + /// References lines in the list against device instances + /// + Dictionary StatusListDeviceIndexes; + /// + /// + /// + JoinedSigInterlock PagesInterlock; + + /// + /// 1 + /// + public const uint JoinText = 1; + + CTimer PinAuthorizedTimer; + + EssentialsRoomTechConfig Config; + + StringBuilder PinEntryBuilder = new StringBuilder(4); + + bool IsAuthorized; + + SmartObjectNumeric PinKeypad; + + /// + /// + /// + /// + /// + public EssentialsHuddleTechPageDriver(BasicTriListWithSmartObject trilist, EssentialsRoomTechConfig config) + : base(trilist) + { + Config = config; + + PagesInterlock = new JoinedSigInterlock(trilist); + PagesInterlock.SetButDontShow(UIBoolJoin.TechSystemStatusVisible); + + trilist.SetSigFalseAction(UIBoolJoin.TechExitButton, Hide); + + MenuList = new SmartObjectDynamicList(trilist.SmartObjects[UISmartObjectJoin.TechMenuList], + true, 3100); + + MenuList.SetFeedback(1, true); // initial fb + ushort count = 0; + + MenuList.SetItemMainText(1, "System Status"); + MenuList.SetItemButtonAction(1, b => { + if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechSystemStatusVisible); + MenuList.SetFeedback(1, true); + }); + + MenuList.SetItemMainText(2, "Display Controls"); + MenuList.SetItemButtonAction(2, b => { + if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechDisplayControlsVisible); + MenuList.SetFeedback(2, true); + }); + + count = 2; + + // Don't show panel setup on iPad or xpanel + if (TriList is Crestron.SimplSharpPro.DeviceSupport.TswFt5Button) + { + count++; + MenuList.SetItemMainText(count, "Panel Setup"); + MenuList.SetItemButtonAction(count, b => + { + if (b) PagesInterlock.ShowInterlocked(UIBoolJoin.TechPanelSetupVisible); + MenuList.SetFeedback(count, true); + }); + } + + MenuList.Count = count; + BuildStatusList(); + BuildDisplayList(); + SetupPinModal(); + } + + /// + /// + /// + public override void Show() + { + // divert to PIN if we need auth + if (IsAuthorized) + { + // Cancel the auth timer so we don't deauth after coming back in + if (PinAuthorizedTimer != null) + PinAuthorizedTimer.Stop(); + + TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, true); + PagesInterlock.Show(); + base.Show(); + } + else + { + TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, true); + } + } + + /// + /// + /// + public override void Hide() + { + // Leave it authorized for 60 seconds. + if (IsAuthorized) + PinAuthorizedTimer = new CTimer(o => { + IsAuthorized = false; + PinAuthorizedTimer = null; + }, 60000); + TriList.SetBool(UIBoolJoin.TechCommonItemsVisbible, false); + PagesInterlock.Hide(); + base.Hide(); + } + + /// + /// Wire up the keypad and buttons + /// + void SetupPinModal() + { + TriList.SetSigFalseAction(UIBoolJoin.PinDialogCancelPress, CancelPinDialog); + PinKeypad = new SmartObjectNumeric(TriList.SmartObjects[UISmartObjectJoin.TechPinDialogKeypad], true); + PinKeypad.Digit0.UserObject = new Action(b => { if (b)DialPinDigit('0'); }); + PinKeypad.Digit1.UserObject = new Action(b => { if (b)DialPinDigit('1'); }); + PinKeypad.Digit2.UserObject = new Action(b => { if (b)DialPinDigit('2'); }); + PinKeypad.Digit3.UserObject = new Action(b => { if (b)DialPinDigit('3'); }); + PinKeypad.Digit4.UserObject = new Action(b => { if (b)DialPinDigit('4'); }); + PinKeypad.Digit5.UserObject = new Action(b => { if (b)DialPinDigit('5'); }); + PinKeypad.Digit6.UserObject = new Action(b => { if (b)DialPinDigit('6'); }); + PinKeypad.Digit7.UserObject = new Action(b => { if (b)DialPinDigit('7'); }); + PinKeypad.Digit8.UserObject = new Action(b => { if (b)DialPinDigit('8'); }); + PinKeypad.Digit9.UserObject = new Action(b => { if (b)DialPinDigit('9'); }); + } + + /// + /// + /// + /// + void DialPinDigit(char d) + { + PinEntryBuilder.Append(d); + var len = PinEntryBuilder.Length; + SetPinDotsFeedback(len); + + // check it! + if (len == 4) + { + if (Config.Password == PinEntryBuilder.ToString()) + { + IsAuthorized = true; + SetPinDotsFeedback(0); + TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false); + Show(); + } + else + { + SetPinDotsFeedback(0); + TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, true); + new CTimer(o => + { + TriList.SetBool(UIBoolJoin.PinDialogErrorVisible, false); + }, 1500); + } + + PinEntryBuilder.Remove(0, len); // clear it either way + } + } + + /// + /// Draws the dots as pin is entered + /// + /// + void SetPinDotsFeedback(int len) + { + TriList.SetBool(UIBoolJoin.PinDialogDot1, len >= 1); + TriList.SetBool(UIBoolJoin.PinDialogDot2, len >= 2); + TriList.SetBool(UIBoolJoin.PinDialogDot3, len >= 3); + TriList.SetBool(UIBoolJoin.PinDialogDot4, len == 4); + + } + + /// + /// Does what it says + /// + void CancelPinDialog() + { + PinEntryBuilder.Remove(0, PinEntryBuilder.Length); + TriList.SetBool(UIBoolJoin.PinDialog4DigitVisible, false); + } + + + /// + /// + /// + void BuildStatusList() + { + StatusList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechStatusList, 3, 3, 3); + StatusListDeviceIndexes = new Dictionary(); + uint i = 0; + foreach (var d in DeviceManager.AllDevices) + { + // make sure it is both ICommunicationMonitor and a Device + var sd = d as ICommunicationMonitor; + if (sd == null) + continue; + var dd = sd as Device; + if(dd == null) + continue; + i++; + StatusList.StringInputSig(i, 1).StringValue = dd.Name; + StatusList.UShortInputSig(i, 1).UShortValue = (ushort)sd.CommunicationMonitor.Status; + StatusListDeviceIndexes.Add(sd, i); + sd.CommunicationMonitor.StatusChange += CommunicationMonitor_StatusChange ; + } + StatusList.Count = (ushort)i; + } + + /// + /// Builds the list of display controls + /// + void BuildDisplayList() + { + DisplayList = new SubpageReferenceList(TriList, UISmartObjectJoin.TechDisplayControlsList, 10, 3, 3); + + var devKeys = ConfigReader.ConfigObject.Devices.Where(d => + d.Group.Equals("display", StringComparison.OrdinalIgnoreCase) + || d.Group.Equals("projector", StringComparison.OrdinalIgnoreCase)) + .Select(dd => dd.Key); + var disps = DeviceManager.AllDevices.Where(d => + devKeys.Contains(d.Key)); + ushort i = 0; + foreach (var disp in disps) + { + var display = disp as DisplayBase; + if (display != null) + { + i++; + DisplayList.StringInputSig(i, 1).StringValue = display.Name; + DisplayList.GetBoolFeedbackSig(i, 1).SetSigFalseAction(display.PowerOn); + DisplayList.GetBoolFeedbackSig(i, 2).SetSigFalseAction(display.PowerOff); + if (display is TwoWayDisplayBase) + { + var powerOnSig = DisplayList.BoolInputSig(i, 1); + (display as TwoWayDisplayBase).PowerIsOnFeedback.LinkInputSig(powerOnSig); + + var powerOffSig = DisplayList.BoolInputSig(1, 2); + (display as TwoWayDisplayBase).PowerIsOnFeedback.LinkComplementInputSig(powerOffSig); + } + DisplayList.GetBoolFeedbackSig(i, 3).SetSigFalseAction(() => + { if (display is IInputHdmi1) (display as IInputHdmi1).InputHdmi1(); }); + DisplayList.GetBoolFeedbackSig(i, 4).SetSigFalseAction(() => + { if (display is IInputHdmi2) (display as IInputHdmi2).InputHdmi2(); }); + DisplayList.GetBoolFeedbackSig(i, 5).SetSigFalseAction(() => + { if (display is IInputHdmi3) (display as IInputHdmi3).InputHdmi3(); }); + //DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() => + //{ if (display is IInputHdmi4) (display as IInputHdmi4).InputHdmi4(); }); + DisplayList.GetBoolFeedbackSig(i, 6).SetSigFalseAction(() => + { if (display is IInputDisplayPort1) (display as IInputDisplayPort1).InputDisplayPort1(); }); + + + // Figure out some way to provide current input feedback + if (display is TwoWayDisplayBase) + { + (display as TwoWayDisplayBase).CurrentInputFeedback.OutputChange += CurrentInputFeedback_OutputChange; + } + } + + + } + + DisplayList.Count = i; + } + + + void CurrentInputFeedback_OutputChange(object sender, EventArgs e) + { + + } + + /// + /// + /// + void CommunicationMonitor_StatusChange(object sender, MonitorStatusChangeEventArgs e) + { + var c = sender as ICommunicationMonitor; + if (StatusListDeviceIndexes.ContainsKey(c)) + { + var i = StatusListDeviceIndexes[c]; + StatusList.UShortInputSig(i, 1).UShortValue = (ushort)e.Status; + } + } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index 752a7107..114909c4 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -257,7 +257,7 @@ namespace PepperDash.Essentials.Core public override EssentialsDevice BuildDevice(DeviceConfig dc) { - Debug.Console(1, "Factory Attempting to create new C2N-RTHS Device"); + Debug.Console(1, "Factory Attempting to create new GlsPartitionSensorController Device"); return new GlsPartitionSensorController(dc.Key, GetGlsPartCnDevice, dc); } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs index cbbb58d1..b68a4c04 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -46,9 +46,12 @@ namespace PepperDash.Essentials.Core CreateScenarios(); - SetupPartitionStateProviders(); + AddPostActivationAction(() => + { + SetupPartitionStateProviders(); - SetRooms(); + SetRooms(); + }); } void CreateScenarios() @@ -243,4 +246,21 @@ namespace PepperDash.Essentials.Core #endregion } + + public class EssentialsRoomCombinerFactory : EssentialsDeviceFactory + { + public EssentialsRoomCombinerFactory() + { + TypeNames = new List { "essentialsroomcombiner" }; + } + + public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new EssentialsRoomCombiner Device"); + + var props = dc.Properties.ToObject(); + + return new EssentialsRoomCombiner(dc.Key, props); + } + } } \ No newline at end of file From 5a4f7b6a2864e650ba343a7f7d71dc0d9bf935a4 Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Mon, 19 Jul 2021 15:44:28 -0600 Subject: [PATCH 12/27] Adds new keyword to intentionally hide properties --- .../Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs index 662988a1..5a6e9f59 100644 --- a/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/Interfaces/IEssentialsHuddleVtc1Room.cs @@ -16,9 +16,9 @@ namespace PepperDash.Essentials IHasScheduleAwareness ScheduleSource { get; } - BoolFeedback InCallFeedback { get; } + new BoolFeedback InCallFeedback { get; } - BoolFeedback PrivacyModeIsOnFeedback { get; } + new BoolFeedback PrivacyModeIsOnFeedback { get; } string DefaultCodecRouteString { get; } } From 94c0e92f6bc912c172e79b5430d4f0347cb36b78 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 08:28:25 -0600 Subject: [PATCH 13/27] fix: Initialize lists for partitions and scenarios also removed unnecessary else --- .../Room/Combining/EssentialsRoomCombiner.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs index b68a4c04..6d80913f 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Combining/EssentialsRoomCombiner.cs @@ -27,6 +27,9 @@ namespace PepperDash.Essentials.Core { _propertiesConfig = props; + Partitions = new List(); + RoomCombinationScenarios = new List(); + if (_propertiesConfig.ScenarioChangeDebounceTimeSeconds > 0) { _scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds; @@ -136,11 +139,6 @@ namespace PepperDash.Essentials.Core // the partition can't be found or the state doesn't match return false; } - else - { - // check the next partition state - continue; - } } // if it hasn't returned false by now we have the matching scenario return true; From 5f6b650dba081b5eb0bfd860bb0402d1e09a99c7 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 11:15:37 -0600 Subject: [PATCH 14/27] fix: Update fusion IP-ID for multiple rooms --- PepperDashEssentials/ControlSystem.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 033d82fe..8c3399ae 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -450,14 +450,13 @@ namespace PepperDash.Essentials return; } + uint fusionIpId = 0xf1; + foreach (var roomConfig in ConfigReader.ConfigObject.Rooms) { var room = EssentialsRoomConfigHelper.GetRoomObject(roomConfig) as IEssentialsRoom; if (room != null) { - // default IPID - uint fusionIpId = 0xf1; - // default to no join map key string fusionJoinMapKey = string.Empty; @@ -515,9 +514,13 @@ namespace PepperDash.Essentials DeviceManager.AddDevice(room); } + fusionIpId += 1; } else + { Debug.Console(0, Debug.ErrorLogLevel.Notice, "Notice: Cannot create room from config, key '{0}' - Is this intentional? This may be a valid configuration.", roomConfig.Key); + + } } Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Rooms Loaded."); From 1415999d8653fbb1760908b3fc1ef0ad1cb5e30b Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 17:28:40 -0600 Subject: [PATCH 15/27] refactor: Update a debug message with IP-ID info --- .../Fusion/EssentialsHuddleVtc1FusionController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs index 54d936f0..c3877706 100644 --- a/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs +++ b/PepperDashEssentials/Fusion/EssentialsHuddleVtc1FusionController.cs @@ -150,7 +150,7 @@ namespace PepperDash.Essentials.Fusion protected override void CreateSymbolAndBasicSigs(uint ipId) { - Debug.Console(1, this, "Creating Fusion Room symbol with GUID: {0}", RoomGuid); + Debug.Console(0, this, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId); FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use(); From 88e5c49663f7b0b9db35faec8480cec00ab0f627 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 17:29:02 -0600 Subject: [PATCH 16/27] refactor: Add Fusion IP-ID info to debug messages --- PepperDashEssentials/ControlSystem.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index 8c3399ae..ba5529d9 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -477,7 +477,7 @@ namespace PepperDash.Essentials { DeviceManager.AddDevice(room); - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion"); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId); DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase(room, fusionIpId, fusionJoinMapKey)); @@ -489,7 +489,7 @@ namespace PepperDash.Essentials { DeviceManager.AddDevice(room); - Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion"); + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId); DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey)); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge..."); @@ -501,7 +501,7 @@ namespace PepperDash.Essentials DeviceManager.AddDevice(room); Debug.Console(0, Debug.ErrorLogLevel.Notice, - "Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion"); + "Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId); DeviceManager.AddDevice(new EssentialsTechRoomFusionSystemController((EssentialsTechRoom)room, fusionIpId, fusionJoinMapKey)); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge"); From de7a74eaffa5946f0330985d4de6ec979faefe37 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 17:30:45 -0600 Subject: [PATCH 17/27] feat: Update Fusion to create a GUID file per room This allows for multiple rooms to be designated and created without any issues. Also moved post Activation action to it's own method rather than a lambda. In the interest of backwards compatibility, the Fusion class will look for a GUID file with the old file name and migrate it to the new file name. --- ...lsHuddleSpaceFusionSystemControllerBase.cs | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs index a172ab49..1bf925d6 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Fusion/EssentialsHuddleSpaceFusionSystemControllerBase.cs @@ -119,9 +119,21 @@ namespace PepperDash.Essentials.Core.Fusion var slot = Global.ControlSystem.ProgramNumber; var guidFilePath = Global.FilePathPrefix + - string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); + string.Format(@"{0}-FusionGuids-{1:X2}.json", InitialParametersClass.ProgramIDTag, _ipId); - _guidFileExists = File.Exists(guidFilePath); + var oldGuidFilePath = Global.FilePathPrefix + + string.Format(@"{0}-FusionGuids.json", InitialParametersClass.ProgramIDTag); + + if (File.Exists(oldGuidFilePath)) + { + Debug.Console(0, 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) @@ -149,19 +161,7 @@ namespace PepperDash.Essentials.Core.Fusion } - AddPostActivationAction(() => - { - CreateSymbolAndBasicSigs(_ipId); - SetUpSources(); - SetUpCommunitcationMonitors(); - SetUpDisplay(); - SetUpError(); - ExecuteCustomSteps(); - - FusionRVI.GenerateFileForAllFusionDevices(); - - GenerateGuidFile(guidFilePath); - }); + AddPostActivationAction(() => PostActivate(guidFilePath)); } catch (Exception e) { @@ -169,6 +169,20 @@ namespace PepperDash.Essentials.Core.Fusion } } + private void PostActivate(string guidFilePath) + { + CreateSymbolAndBasicSigs(_ipId); + SetUpSources(); + SetUpCommunitcationMonitors(); + SetUpDisplay(); + SetUpError(); + ExecuteCustomSteps(); + + FusionRVI.GenerateFileForAllFusionDevices(); + + GenerateGuidFile(guidFilePath); + } + protected string RoomGuid { get { return _guiDs.RoomGuid; } @@ -314,7 +328,7 @@ namespace PepperDash.Essentials.Core.Fusion protected virtual void CreateSymbolAndBasicSigs(uint ipId) { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating Fusion Room symbol with GUID: {0}", RoomGuid); + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating Fusion Room symbol with GUID: {0} and IP-ID {1:X2}", RoomGuid, ipId); FusionRoom = new FusionRoom(ipId, Global.ControlSystem, Room.Name, RoomGuid); FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.Use(); From 290e887903d2d0f3ac84eede97aeda695680c5fd Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 20 Jul 2021 17:32:00 -0600 Subject: [PATCH 18/27] refactor: Modify debug messages Exceptions now print the device key and the error message. To see stack traces, use `appdebug:XX 1`. There are also now debug messages indicating when the different activation cycles are complete. --- .../Devices/DeviceManager.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs index aac38dfa..df864550 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/DeviceManager.cs @@ -60,6 +60,7 @@ namespace PepperDash.Essentials.Core DeviceCriticalSection.Enter(); AddDeviceEnabled = false; // PreActivate all devices + Debug.Console(0,"****PreActivation starting...****"); foreach (var d in Devices.Values) { try @@ -69,9 +70,12 @@ namespace PepperDash.Essentials.Core } catch (Exception e) { - Debug.Console(0, d, "ERROR: Device PreActivation failure:\r{0}", e); + Debug.Console(0, d, "ERROR: Device {1} PreActivation failure: {0}", e.Message, d.Key); + Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace); } } + Debug.Console(0, "****PreActivation complete****"); + Debug.Console(0, "****Activation starting...****"); // Activate all devices foreach (var d in Devices.Values) @@ -83,10 +87,14 @@ namespace PepperDash.Essentials.Core } catch (Exception e) { - Debug.Console(0, d, "ERROR: Device Activation failure:\r{0}", e); + Debug.Console(0, d, "ERROR: Device {1} Activation failure: {0}", e.Message, d.Key); + Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace); } } + Debug.Console(0, "****Activation complete****"); + Debug.Console(0, "****PostActivation starting...****"); + // PostActivate all devices foreach (var d in Devices.Values) { @@ -97,10 +105,13 @@ namespace PepperDash.Essentials.Core } catch (Exception e) { - Debug.Console(0, d, "ERROR: Device PostActivation failure:\r{0}", e); + Debug.Console(0, d, "ERROR: Device {1} PostActivation failure: {0}", e.Message, d.Key); + Debug.Console(1, d, "Stack Trace: {0}", e.StackTrace); } } + Debug.Console(0, "****PostActivation complete****"); + OnAllDevicesActivated(); } finally From 085a64c87b14ce76ad0e955fc255c94cb1da9601 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 13:41:21 -0600 Subject: [PATCH 19/27] fix: Correct functioning while in test mode --- .../GlsPartitionSensorController.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index 114909c4..26cade95 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -39,10 +39,10 @@ namespace PepperDash.Essentials.Core RegisterCrestronGenericBase(_partitionSensor); NameFeedback = new StringFeedback(() => Name); - EnableFeedback = new BoolFeedback(() => _partitionSensor.EnableFeedback.BoolValue); - PartitionPresentFeedback = new BoolFeedback(() => _partitionSensor.PartitionSensedFeedback.BoolValue); - PartitionNotSensedFeedback = new BoolFeedback(() => _partitionSensor.PartitionNotSensedFeedback.BoolValue); - SensitivityFeedback = new IntFeedback(() => _partitionSensor.SensitivityFeedback.UShortValue); + EnableFeedback = new BoolFeedback(() => InTestMode ? TestEnableFeedback : _partitionSensor.EnableFeedback.BoolValue); + PartitionPresentFeedback = new BoolFeedback(() => InTestMode ? TestPartitionSensedFeedback : _partitionSensor.PartitionSensedFeedback.BoolValue); + PartitionNotSensedFeedback = new BoolFeedback(() => InTestMode ? !TestPartitionSensedFeedback : _partitionSensor.PartitionNotSensedFeedback.BoolValue); + SensitivityFeedback = new IntFeedback(() => InTestMode ? TestSensitivityFeedback : _partitionSensor.SensitivityFeedback.UShortValue); if (_partitionSensor != null) _partitionSensor.BaseEvent += PartitionSensor_BaseEvent; }); @@ -93,6 +93,9 @@ namespace PepperDash.Essentials.Core if (InTestMode) { TestEnableFeedback = state; + + EnableFeedback.FireUpdate(); + Debug.Console(1, this, "TestEnableFeedback: {0}", TestEnableFeedback.ToString()); return; } @@ -105,6 +108,10 @@ namespace PepperDash.Essentials.Core if (InTestMode) { TestPartitionSensedFeedback = state; + + PartitionPresentFeedback.FireUpdate(); + PartitionNotSensedFeedback.FireUpdate(); + Debug.Console(1, this, "TestPartitionSensedFeedback: {0}", TestPartitionSensedFeedback.ToString()); return; } @@ -117,6 +124,8 @@ namespace PepperDash.Essentials.Core if (InTestMode) { TestSensitivityFeedback = value; + + SensitivityFeedback.FireUpdate(); Debug.Console(1, this, "TestSensitivityFeedback: {0}", TestSensitivityFeedback); return; } From f607394ee724d9192d83d88db5f9c6ccb97748b3 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 16:53:11 -0600 Subject: [PATCH 20/27] chore: Update PD Core to 1.0.48 --- packages.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages.config b/packages.config index 3876040a..3494f2eb 100644 --- a/packages.config +++ b/packages.config @@ -1,3 +1,3 @@ - + \ No newline at end of file From 4bd777f6b942b2da27ada6a163788ecff8bd1e33 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 16:53:36 -0600 Subject: [PATCH 21/27] feat: Update `Essentials Device` to call `Initialize` method --- .../Devices/EssentialsDevice.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs index 781101d4..00624007 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs @@ -27,6 +27,27 @@ namespace PepperDash.Essentials.Core { } + + private void SubscribeToActivateComplete() + { + DeviceManager.AllDevicesActivated += DeviceManagerOnAllDevicesActivated; + } + + private void DeviceManagerOnAllDevicesActivated(object sender, EventArgs eventArgs) + { + CrestronInvoke.BeginInvoke((o) => + { + try + { + Initialize(); + } + catch (Exception ex) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Exception initializing device: {0}", ex.Message); + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stack Trace: {0}", ex.StackTrace); + } + }); + } } [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)] From 76e4d4a82d9994ec2e0c1b3c7dd76810cd29f724 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 19:44:41 -0600 Subject: [PATCH 22/27] feat: Add method call to constructor for EssentialsDevice --- .../PepperDashEssentialsBase/Devices/EssentialsDevice.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs index 00624007..46fa819b 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Devices/EssentialsDevice.cs @@ -19,13 +19,13 @@ namespace PepperDash.Essentials.Core protected EssentialsDevice(string key) : base(key) { - + SubscribeToActivateComplete(); } protected EssentialsDevice(string key, string name) : base(key, name) { - + SubscribeToActivateComplete(); } private void SubscribeToActivateComplete() From ea254ef98333f754e12f411891613a2691f05d8a Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 23 Jul 2021 19:56:29 -0600 Subject: [PATCH 23/27] feat: Update some internal Essentials devices to use Initialize method --- .../MicrophonePrivacyController.cs | 14 +++++++++----- .../VideoCodec/CiscoCodec/CiscoSparkCodec.cs | 19 +++++++++++++------ .../VideoCodec/ZoomRoom/ZoomRoom.cs | 17 +++++++++++++---- 3 files changed, 35 insertions(+), 15 deletions(-) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs index 0f15a02d..55b458a7 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Microphone Privacy/MicrophonePrivacyController.cs @@ -88,11 +88,6 @@ namespace PepperDash.Essentials.Core.Privacy else Debug.Console(0, this, "Unable to add Red LED device"); - DeviceManager.AllDevicesActivated += (o, a) => - { - CheckPrivacyMode(); - }; - AddPostActivationAction(() => { PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange -= PrivacyModeIsOnFeedback_OutputChange; PrivacyDevice.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; @@ -103,6 +98,15 @@ namespace PepperDash.Essentials.Core.Privacy return base.CustomActivate(); } + #region Overrides of Device + + public override void Initialize() + { + CheckPrivacyMode(); + } + + #endregion + public void SetPrivacyDevice(IPrivacy privacyDevice) { PrivacyDevice = privacyDevice; diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index a7be2443..7cfe82c0 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -550,6 +550,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CrestronConsole.AddNewConsoleCommand(GetPhonebook, "GetCodecPhonebook", "Triggers a refresh of the codec phonebook", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(GetBookings, "GetCodecBookings", "Triggers a refresh of the booking data for today", ConsoleAccessLevelEnum.AccessOperator); + return base.CustomActivate(); + } + + #region Overrides of Device + + public override void Initialize() + { var socket = Communication as ISocketStatus; if (socket != null) { @@ -558,9 +565,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco Communication.Connect(); - CommunicationMonitor.Start(); + CommunicationMonitor.Start(); - string prefix = "xFeedback register "; + const string prefix = "xFeedback register "; CliFeedbackRegistrationExpression = prefix + "/Configuration" + Delimiter + @@ -575,14 +582,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco prefix + "/Status/Video/Layout" + Delimiter + prefix + "/Status/Video/Input/MainVideoMute" + Delimiter + prefix + "/Bookings" + Delimiter + - prefix + "/Event/CallDisconnect" + Delimiter + + prefix + "/Event/CallDisconnect" + Delimiter + prefix + "/Event/Bookings" + Delimiter + prefix + "/Event/CameraPresetListUpdated" + Delimiter + - prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter; - - return base.CustomActivate(); + prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter; } + #endregion + /// /// Fires when initial codec sync is completed. Used to then send commands to get call history, phonebook, bookings, etc. /// diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index fc3f14a9..e838ceed 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -717,7 +717,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom CrestronConsole.AddNewConsoleCommand(s => GetBookings(), "GetZoomRoomBookings", "Triggers a refresh of the booking data for today", ConsoleAccessLevelEnum.AccessOperator); - var socket = Communication as ISocketStatus; + + + return base.CustomActivate(); + } + + #region Overrides of Device + + public override void Initialize() + { + var socket = Communication as ISocketStatus; if (socket != null) { socket.ConnectionChange += socket_ConnectionChange; @@ -728,11 +737,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Communication.Connect(); CommunicationMonitor.Start(); + } - return base.CustomActivate(); - } + #endregion - public void SetCommDebug(string s) + public void SetCommDebug(string s) { if (s == "1") { From 864e0675ea589b0d70db4aade804ebfdf674a430 Mon Sep 17 00:00:00 2001 From: Trevor Payne <44117050+TrevorPayne@users.noreply.github.com> Date: Mon, 2 Aug 2021 10:34:41 -0500 Subject: [PATCH 24/27] Resolves #769 Fix issues with large dm frame instantiation --- .../Chassis/DmBladeChassisController.cs | 380 +++++++++++------- 1 file changed, 238 insertions(+), 142 deletions(-) diff --git a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmBladeChassisController.cs b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmBladeChassisController.cs index 3a4f55c0..96cc8097 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmBladeChassisController.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmBladeChassisController.cs @@ -16,7 +16,8 @@ using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.DM.Config; -namespace PepperDash.Essentials.DM { +namespace PepperDash.Essentials.DM +{ /// /// Builds a controller for basic DM-RMCs with Com and IR ports and no control functions /// @@ -75,8 +76,10 @@ namespace PepperDash.Essentials.DM { /// Factory method to create a new chassis controller from config data. Limited to 8x8 right now /// public static DmBladeChassisController GetDmChassisController(string key, string name, - string type, DMChassisPropertiesConfig properties) { - try { + string type, DMChassisPropertiesConfig properties) + { + try + { type = type.ToLower(); uint ipid = properties.Control.IpIdInt; @@ -85,7 +88,8 @@ namespace PepperDash.Essentials.DM { else if (type == "dmmd128x128") { chassis = new DmMd128x128(ipid, Global.ControlSystem); } - if (chassis == null) { + if (chassis == null) + { return null; } @@ -93,11 +97,13 @@ namespace PepperDash.Essentials.DM { // add the cards and port names foreach (var kvp in properties.InputSlots) controller.AddInputBlade(kvp.Value, kvp.Key); - foreach (var kvp in properties.OutputSlots) { + foreach (var kvp in properties.OutputSlots) + { controller.AddOutputBlade(kvp.Value, kvp.Key); } - foreach (var kvp in properties.VolumeControls) { + foreach (var kvp in properties.VolumeControls) + { // get the card // check it for an audio-compatible type // make a something-something that will make it work @@ -123,7 +129,8 @@ namespace PepperDash.Essentials.DM { controller.PropertiesConfig = properties; return controller; } - catch (System.Exception e) { + catch (System.Exception e) + { Debug.Console(0, "Error creating DM chassis:\r{0}", e); } return null; @@ -137,7 +144,8 @@ namespace PepperDash.Essentials.DM { /// /// public DmBladeChassisController(string key, string name, BladeSwitch chassis) - : base(key, name, chassis) { + : base(key, name, chassis) + { Chassis = chassis; InputPorts = new RoutingPortCollection(); OutputPorts = new RoutingPortCollection(); @@ -161,68 +169,87 @@ namespace PepperDash.Essentials.DM { InputCardHdcpCapabilityFeedbacks = new Dictionary(); InputCardHdcpCapabilityTypes = new Dictionary(); - for (uint x = 1; x <= Chassis.NumberOfOutputs; x++) { + for (uint x = 1; x <= Chassis.NumberOfOutputs; x++) + { var tempX = x; - if (Chassis.Outputs[tempX] != null) { - VideoOutputFeedbacks[tempX] = new IntFeedback(() => { + if (Chassis.Outputs[tempX] != null) + { + VideoOutputFeedbacks[tempX] = new IntFeedback(() => + { if (Chassis.Outputs[tempX].VideoOutFeedback != null) { return (ushort)Chassis.Outputs[tempX].VideoOutFeedback.Number; } else { return 0; }; }); - OutputNameFeedbacks[tempX] = new StringFeedback(() => { - if (Chassis.Outputs[tempX].NameFeedback != null) { + OutputNameFeedbacks[tempX] = new StringFeedback(() => + { + if (Chassis.Outputs[tempX].NameFeedback != null) + { return Chassis.Outputs[tempX].NameFeedback.StringValue; } - else { + else + { return ""; } }); - OutputVideoRouteNameFeedbacks[tempX] = new StringFeedback(() => { - if (Chassis.Outputs[tempX].VideoOutFeedback != null) { + OutputVideoRouteNameFeedbacks[tempX] = new StringFeedback(() => + { + if (Chassis.Outputs[tempX].VideoOutFeedback != null) + { return Chassis.Outputs[tempX].VideoOutFeedback.NameFeedback.StringValue; } - else { + else + { return ""; } }); - OutputEndpointOnlineFeedbacks[tempX] = new BoolFeedback(() => { + OutputEndpointOnlineFeedbacks[tempX] = new BoolFeedback(() => + { //if (Chassis.Outputs[tempX].Endpoint != null) // return Chassis.Outputs[tempX].Endpoint.IsOnline; //else - return Chassis.Outputs[tempX].EndpointOnlineFeedback; + return Chassis.Outputs[tempX].EndpointOnlineFeedback; }); } - if (Chassis.Inputs[tempX] != null) { - UsbInputRoutedToFeebacks[tempX] = new IntFeedback(() => { + if (Chassis.Inputs[tempX] != null) + { + UsbInputRoutedToFeebacks[tempX] = new IntFeedback(() => + { if (Chassis.Inputs[tempX].USBRoutedToFeedback != null) { return (ushort)Chassis.Inputs[tempX].USBRoutedToFeedback.Number; } else { return 0; }; }); - VideoInputSyncFeedbacks[tempX] = new BoolFeedback(() => { + VideoInputSyncFeedbacks[tempX] = new BoolFeedback(() => + { if (Chassis.Inputs[tempX].VideoDetectedFeedback != null) return Chassis.Inputs[tempX].VideoDetectedFeedback.BoolValue; else return false; }); - InputNameFeedbacks[tempX] = new StringFeedback(() => { - if (Chassis.Inputs[tempX].NameFeedback != null) { + InputNameFeedbacks[tempX] = new StringFeedback(() => + { + if (Chassis.Inputs[tempX].NameFeedback != null) + { return Chassis.Inputs[tempX].NameFeedback.StringValue; } - else { + else + { return ""; } }); - InputEndpointOnlineFeedbacks[tempX] = new BoolFeedback(() => { + InputEndpointOnlineFeedbacks[tempX] = new BoolFeedback(() => + { return Chassis.Inputs[tempX].EndpointOnlineFeedback; }); - InputCardHdcpCapabilityFeedbacks[tempX] = new IntFeedback(() => { + InputCardHdcpCapabilityFeedbacks[tempX] = new IntFeedback(() => + { var inputCard = Chassis.Inputs[tempX]; - if (inputCard.Card is DmHdmi4kInputBladeCard) { + if (inputCard.Card is DmHdmi4kInputBladeCard) + { InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.Hdcp2_2Support; if ((inputCard.Card as DmHdmi4kInputBladeCard).Hdmi4kInput.HdcpSupportOnFeedback.BoolValue) @@ -231,7 +258,8 @@ namespace PepperDash.Essentials.DM { return 0; } - if (inputCard.Card is DmC4kInputBladeCard) { + if (inputCard.Card is DmC4kInputBladeCard) + { InputCardHdcpCapabilityTypes[tempX] = eHdcpCapabilityType.Hdcp2_2Support; if ((inputCard.Card as DmC4kInputBladeCard).DmInput.HdcpCapabilityFeedback.Equals(eHdcpCapabilityType.HdcpSupportOff)) @@ -252,45 +280,56 @@ namespace PepperDash.Essentials.DM { /// /// /// - public void AddInputBlade(string type, uint number) { + public void AddInputBlade(string type, uint number) + { Debug.Console(2, this, "Adding input blade '{0}', slot {1}", type, number); type = type.ToLower(); - if (type == "dmb4kihd") { + if (type == "dmb4kihd") + { var inputBlade = new Dmb4kIHd(number, this.Chassis); - foreach (var item in inputBlade.Inputs) { + foreach (var item in inputBlade.Inputs) + { var card = (item.Card as DmHdmi4kInputBladeCard).Hdmi4kInput; var cecPort = card as ICec; AddHdmiInBladePorts(item.Number, cecPort); } } - else if (type == "dmb4kihddnt") { + else if (type == "dmb4kihddnt") + { var inputBlade = new Dmb4kIHd(number, this.Chassis); - foreach (var item in inputBlade.Inputs) { + foreach (var item in inputBlade.Inputs) + { var card = (item.Card as DmHdmi4kInputBladeCard).Hdmi4kInput; var cecPort = card as ICec; AddHdmiInBladePorts(item.Number, cecPort); } } - else if (type == "dmb4kic") { + else if (type == "dmb4kic") + { var inputBlade = new Dmb4kIC(number, this.Chassis); - foreach (var item in inputBlade.Inputs) { + foreach (var item in inputBlade.Inputs) + { AddDmInBladePorts(item.Number); } } - else if (type == "dmbis") { + else if (type == "dmbis") + { var inputBlade = new DmbIS(number, this.Chassis); - foreach (var item in inputBlade.Inputs) { + foreach (var item in inputBlade.Inputs) + { AddDmInMmFiberPorts(item.Number); } } - else if (type == "dmbis2") { + else if (type == "dmbis2") + { var inputBlade = new DmbIS2(number, this.Chassis); - foreach (var item in inputBlade.Inputs) { + foreach (var item in inputBlade.Inputs) + { AddDmInSmFiberPorts(item.Number); } } @@ -304,22 +343,26 @@ namespace PepperDash.Essentials.DM { { var newEvent = NumericSwitchChange; if (newEvent != null) newEvent(this, e); - } + } - void AddHdmiInBladePorts(uint number, ICec cecPort) { + void AddHdmiInBladePorts(uint number, ICec cecPort) + { AddInputPortWithDebug(number, "hdmiIn", eRoutingSignalType.Audio | eRoutingSignalType.Video, eRoutingPortConnectionType.DmCat, cecPort); } - void AddDmInBladePorts(uint number) { + void AddDmInBladePorts(uint number) + { AddInputPortWithDebug(number, "dmCIn", eRoutingSignalType.Video, eRoutingPortConnectionType.DmCat); } - void AddDmInMmFiberPorts(uint number) { + void AddDmInMmFiberPorts(uint number) + { AddInputPortWithDebug(number, "dmMmIn", eRoutingSignalType.Video, eRoutingPortConnectionType.DmMmFiber); } - void AddDmInSmFiberPorts(uint number) { + void AddDmInSmFiberPorts(uint number) + { AddInputPortWithDebug(number, "dmSmIn", eRoutingSignalType.Video, eRoutingPortConnectionType.DmSmFiber); } @@ -328,64 +371,81 @@ namespace PepperDash.Essentials.DM { /// /// /// - public void AddOutputBlade(string type, uint number) { + public void AddOutputBlade(string type, uint number) + { type = type.ToLower(); Debug.Console(2, this, "Adding output blade '{0}', slot {1}", type, number); - if (type == "dmb4kohd") { + if (type == "dmb4kohd") + { var outputBlade = new Dmb4KOHD(number, Chassis); - foreach (var item in outputBlade.Outputs) { + foreach (var item in outputBlade.Outputs) + { AddHdmiOutBladePorts(item.Number); } } - else if (type == "dmb4kohddnt") { + else if (type == "dmb4kohddnt") + { var outputBlade = new Dmb4KOHD(number, Chassis); - foreach (var item in outputBlade.Outputs) { + foreach (var item in outputBlade.Outputs) + { AddHdmiOutBladePorts(item.Number); } } - else if (type == "dmb4koc") { + else if (type == "dmb4koc") + { var outputBlade = new Dmb4KOC(number, Chassis); - foreach (var item in outputBlade.Outputs) { + foreach (var item in outputBlade.Outputs) + { AddDmOutBladePorts(item.Number); } } - else if (type == "dmb4koc") { + else if (type == "dmb4koc") + { var outputBlade = new Dmb4KOC(number, Chassis); - foreach (var item in outputBlade.Outputs) { + foreach (var item in outputBlade.Outputs) + { AddDmOutBladePorts(item.Number); } } - else if (type == "dmbos") { + else if (type == "dmbos") + { var outputBlade = new DmbOS(number, Chassis); - foreach (var item in outputBlade.Outputs) { + foreach (var item in outputBlade.Outputs) + { AddDmOutMmFiberBladePorts(item.Number); } } - else if (type == "dmbos2") { + else if (type == "dmbos2") + { var outputBlade = new DmbOS2(number, Chassis); - foreach (var item in outputBlade.Outputs) { + foreach (var item in outputBlade.Outputs) + { AddDmOutSmFiberBladePorts(item.Number); } } } - void AddHdmiOutBladePorts(uint number) { - AddOutputPortWithDebug(String.Format("outputBlade{0}", (number / 8 > 0 ? 1 : number / 8)), String.Format("hdmiOut{0}", number) , eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, Chassis.Outputs[number]); + void AddHdmiOutBladePorts(uint number) + { + AddOutputPortWithDebug(number, "hdmiOut", eRoutingSignalType.Video, eRoutingPortConnectionType.Hdmi, Chassis.Outputs[number]); } - void AddDmOutBladePorts(uint number) { - AddOutputPortWithDebug(String.Format("outputBlade{0}", (number / 8 > 0 ? 1 : number / 8)), String.Format("dmOut{0}", number), eRoutingSignalType.Video, eRoutingPortConnectionType.DmCat, Chassis.Outputs[number]); + void AddDmOutBladePorts(uint number) + { + AddOutputPortWithDebug(number, "dmOut", eRoutingSignalType.Video, eRoutingPortConnectionType.DmCat, Chassis.Outputs[number]); } - void AddDmOutMmFiberBladePorts(uint number) { - AddOutputPortWithDebug(String.Format("outputBlade{0}", (number / 8 > 0 ? 1 : number / 8)), String.Format("dmOut{0}", number), eRoutingSignalType.Video, eRoutingPortConnectionType.DmMmFiber, Chassis.Outputs[number]); + void AddDmOutMmFiberBladePorts(uint number) + { + AddOutputPortWithDebug(number, "dmMmOut", eRoutingSignalType.Video, eRoutingPortConnectionType.DmMmFiber, Chassis.Outputs[number]); } - void AddDmOutSmFiberBladePorts(uint number) { - AddOutputPortWithDebug(String.Format("outputBlade{0}", (number / 8 > 0 ? 1 : number / 8)), String.Format("dmOut{0}", number), eRoutingSignalType.Video, eRoutingPortConnectionType.DmSmFiber, Chassis.Outputs[number]); + void AddDmOutSmFiberBladePorts(uint number) + { + AddOutputPortWithDebug(number, "dmSmOut", eRoutingSignalType.Video, eRoutingPortConnectionType.DmSmFiber, Chassis.Outputs[number]); } @@ -417,23 +477,44 @@ namespace PepperDash.Essentials.DM { } - /// - /// Adds OutputPort - /// - void AddOutputPortWithDebug(string cardName, string portName, eRoutingSignalType sigType, eRoutingPortConnectionType portType, object selector) { + + /*void AddOutputPortWithDebug(string cardName, string portName, eRoutingSignalType sigType, eRoutingPortConnectionType portType, object selector) { var portKey = string.Format("{0}--{1}", cardName, portName); Debug.Console(2, this, "Adding output port '{0}'", portKey); OutputPorts.Add(new RoutingOutputPort(portKey, sigType, portType, selector, this) { FeedbackMatchObject = Chassis.Outputs[(uint)selector] }); + }*/ + + /// + /// Adds OutputPort + /// + void AddOutputPortWithDebug(uint cardNum, string portName, eRoutingSignalType sigType, eRoutingPortConnectionType portType, object selector) + { + try + { + var portKey = string.Format("outputCard{0}--{1}", cardNum, portName); + Debug.Console(2, this, "Adding output port '{0}'", portKey); + var outputPort = new RoutingOutputPort(portKey, sigType, portType, selector, this) + { + FeedbackMatchObject = Chassis.Outputs[cardNum] + }; + OutputPorts.Add(outputPort); + } + catch (Exception ex) + { + Debug.Console(0, this, "Exception : {0}", ex); + } + } /// /// /// - void AddVolumeControl(uint number, Audio.Output audio) { + void AddVolumeControl(uint number, Audio.Output audio) + { VolumeControls.Add(number, new DmCardAudioOutputController(audio)); } @@ -443,35 +524,43 @@ namespace PepperDash.Essentials.DM { //} - void Chassis_DMInputChange(Switch device, DMInputEventArgs args) { + void Chassis_DMInputChange(Switch device, DMInputEventArgs args) + { - switch (args.EventId) { - case DMInputEventIds.EndpointOnlineEventId: { + switch (args.EventId) + { + case DMInputEventIds.EndpointOnlineEventId: + { Debug.Console(2, this, "DM Input EndpointOnlineEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback); InputEndpointOnlineFeedbacks[args.Number].FireUpdate(); break; } - case DMInputEventIds.OnlineFeedbackEventId: { + case DMInputEventIds.OnlineFeedbackEventId: + { Debug.Console(2, this, "DM Input OnlineFeedbackEventId for input: {0}. State: {1}", args.Number, device.Inputs[args.Number].EndpointOnlineFeedback); InputEndpointOnlineFeedbacks[args.Number].FireUpdate(); break; } - case DMInputEventIds.VideoDetectedEventId: { + case DMInputEventIds.VideoDetectedEventId: + { Debug.Console(2, this, "DM Input {0} VideoDetectedEventId", args.Number); VideoInputSyncFeedbacks[args.Number].FireUpdate(); break; } - case DMInputEventIds.InputNameEventId: { + case DMInputEventIds.InputNameEventId: + { Debug.Console(2, this, "DM Input {0} NameFeedbackEventId", args.Number); InputNameFeedbacks[args.Number].FireUpdate(); break; } - case DMInputEventIds.HdcpCapabilityFeedbackEventId: { + case DMInputEventIds.HdcpCapabilityFeedbackEventId: + { Debug.Console(2, this, "DM Input {0} HdcpCapabilityFeedbackEventId", args.Number); InputCardHdcpCapabilityFeedbacks[args.Number].FireUpdate(); break; } - default: { + default: + { Debug.Console(2, this, "DMInputChange fired for Input {0} with Unhandled EventId: {1}", args.Number, args.EventId); break; } @@ -487,74 +576,74 @@ namespace PepperDash.Essentials.DM { switch (args.EventId) { case DMOutputEventIds.VolumeEventId: - { - if (VolumeControls.ContainsKey(output)) { - VolumeControls[args.Number].VolumeEventFromChassis(); + if (VolumeControls.ContainsKey(output)) + { + VolumeControls[args.Number].VolumeEventFromChassis(); + } + break; } - break; - } case DMOutputEventIds.EndpointOnlineEventId: - { - Debug.Console(2, this, - "Output {0} DMOutputEventIds.EndpointOnlineEventId fired. EndpointOnlineFeedback State: {1}", - args.Number, Chassis.Outputs[output].EndpointOnlineFeedback); - if (Chassis.Outputs[output].Endpoint != null) + { Debug.Console(2, this, - "Output {0} DMOutputEventIds.EndpointOnlineEventId fired. Endpoint.IsOnline State: {1}", - args.Number, Chassis.Outputs[output].Endpoint.IsOnline); + "Output {0} DMOutputEventIds.EndpointOnlineEventId fired. EndpointOnlineFeedback State: {1}", + args.Number, Chassis.Outputs[output].EndpointOnlineFeedback); + if (Chassis.Outputs[output].Endpoint != null) + Debug.Console(2, this, + "Output {0} DMOutputEventIds.EndpointOnlineEventId fired. Endpoint.IsOnline State: {1}", + args.Number, Chassis.Outputs[output].Endpoint.IsOnline); - OutputEndpointOnlineFeedbacks[output].FireUpdate(); - break; - } + OutputEndpointOnlineFeedbacks[output].FireUpdate(); + break; + } case DMOutputEventIds.OnlineFeedbackEventId: - { - Debug.Console(2, this, "Output {0} DMInputEventIds.OnlineFeedbackEventId fired. State: {1}", - args.Number, Chassis.Outputs[output].EndpointOnlineFeedback); - OutputEndpointOnlineFeedbacks[output].FireUpdate(); - break; - } + { + Debug.Console(2, this, "Output {0} DMInputEventIds.OnlineFeedbackEventId fired. State: {1}", + args.Number, Chassis.Outputs[output].EndpointOnlineFeedback); + OutputEndpointOnlineFeedbacks[output].FireUpdate(); + break; + } case DMOutputEventIds.VideoOutEventId: - { - - var inputNumber = Chassis.Outputs[output].VideoOutFeedback == null ? 0 : Chassis.Outputs[output].VideoOutFeedback.Number; - - Debug.Console(2, this, "DMSwitchAudioVideo:{0} Routed Input:{1} Output:{2}'", this.Name, - inputNumber, output); - - if (VideoOutputFeedbacks.ContainsKey(output)) { - var localInputPort = InputPorts.FirstOrDefault(p => (DMInput)p.FeedbackMatchObject == Chassis.Outputs[output].VideoOutFeedback); - var localOutputPort = - OutputPorts.FirstOrDefault(p => (DMOutput) p.FeedbackMatchObject == Chassis.Outputs[output]); + + var inputNumber = Chassis.Outputs[output].VideoOutFeedback == null ? 0 : Chassis.Outputs[output].VideoOutFeedback.Number; + + Debug.Console(2, this, "DMSwitchAudioVideo:{0} Routed Input:{1} Output:{2}'", this.Name, + inputNumber, output); + + if (VideoOutputFeedbacks.ContainsKey(output)) + { + var localInputPort = InputPorts.FirstOrDefault(p => (DMInput)p.FeedbackMatchObject == Chassis.Outputs[output].VideoOutFeedback); + var localOutputPort = + OutputPorts.FirstOrDefault(p => (DMOutput)p.FeedbackMatchObject == Chassis.Outputs[output]); - VideoOutputFeedbacks[output].FireUpdate(); - OnSwitchChange(new RoutingNumericEventArgs(output, - inputNumber, - localOutputPort, - localInputPort, - eRoutingSignalType.AudioVideo)); + VideoOutputFeedbacks[output].FireUpdate(); + OnSwitchChange(new RoutingNumericEventArgs(output, + inputNumber, + localOutputPort, + localInputPort, + eRoutingSignalType.AudioVideo)); + } + if (OutputVideoRouteNameFeedbacks.ContainsKey(output)) + { + OutputVideoRouteNameFeedbacks[output].FireUpdate(); + } + break; } - if (OutputVideoRouteNameFeedbacks.ContainsKey(output)) - { - OutputVideoRouteNameFeedbacks[output].FireUpdate(); - } - break; - } case DMOutputEventIds.OutputNameEventId: - { - Debug.Console(2, this, "DM Output {0} NameFeedbackEventId", output); - OutputNameFeedbacks[output].FireUpdate(); - break; - } + { + Debug.Console(2, this, "DM Output {0} NameFeedbackEventId", output); + OutputNameFeedbacks[output].FireUpdate(); + break; + } default: - { - Debug.Console(2, this, "DMOutputChange fired for Output {0} with Unhandled EventId: {1}", - args.Number, args.EventId); - break; - } + { + Debug.Console(2, this, "DMOutputChange fired for Output {0} with Unhandled EventId: {1}", + args.Number, args.EventId); + break; + } } } @@ -564,7 +653,8 @@ namespace PepperDash.Essentials.DM { /// /// /// - void StartOffTimer(PortNumberType pnt) { + void StartOffTimer(PortNumberType pnt) + { if (RouteOffTimers.ContainsKey(pnt)) return; RouteOffTimers[pnt] = new CTimer(o => ExecuteSwitch(null, pnt.Selector, pnt.Type), RouteOffTime); @@ -572,8 +662,10 @@ namespace PepperDash.Essentials.DM { // Send out sigs when coming online - void IsOnline_OutputChange(object sender, EventArgs e) { - if (IsOnline.BoolValue) { + void IsOnline_OutputChange(object sender, EventArgs e) + { + if (IsOnline.BoolValue) + { Chassis.EnableUSBBreakaway.BoolValue = true; if (InputNames != null) @@ -587,12 +679,13 @@ namespace PepperDash.Essentials.DM { #region IRouting Members - public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType sigType) { + public void ExecuteSwitch(object inputSelector, object outputSelector, eRoutingSignalType sigType) + { Debug.Console(2, this, "Making an awesome DM route from {0} to {1} {2}", inputSelector, outputSelector, sigType); var input = inputSelector as DMInput; // Cast can sometimes fail var output = outputSelector as DMOutput; - + if (output == null) { @@ -605,11 +698,14 @@ namespace PepperDash.Essentials.DM { // Check to see if there's an off timer waiting on this and if so, cancel var key = new PortNumberType(output, sigType); - if (input == null) { + if (input == null) + { StartOffTimer(key); } - else { - if (RouteOffTimers.ContainsKey(key)) { + else + { + if (RouteOffTimers.ContainsKey(key)) + { Debug.Console(2, this, "{0} cancelling route off due to new source", output); RouteOffTimers[key].Stop(); RouteOffTimers.Remove(key); @@ -671,7 +767,7 @@ namespace PepperDash.Essentials.DM { var ioSlotJoin = ioSlot - 1; // Control - trilist.SetUShortSigAction(joinMap.OutputVideo.JoinNumber + ioSlotJoin, o => ExecuteNumericSwitch(o, (ushort) ioSlot, eRoutingSignalType.Video)); + trilist.SetUShortSigAction(joinMap.OutputVideo.JoinNumber + ioSlotJoin, o => ExecuteNumericSwitch(o, (ushort)ioSlot, eRoutingSignalType.Video)); if (TxDictionary.ContainsKey(ioSlot)) { From 71881addabf9cced4f0009cc4faaebaa45af73ee Mon Sep 17 00:00:00 2001 From: Jason Alborough Date: Wed, 11 Aug 2021 13:00:51 -0400 Subject: [PATCH 25/27] fix(Devices.Common.Cameras.CameraVisca): add and fire the event OnPresetsListHasChanged() after LinkToApi so that the camera presets populate to the bridge correctly --- .../Essentials Devices Common/Cameras/CameraVisca.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs index fb8ae79c..37a0487e 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs @@ -170,6 +170,8 @@ namespace PepperDash.Essentials.Devices.Common.Cameras public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); + + OnPresetsListHasChanged(); } void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) @@ -525,6 +527,15 @@ namespace PepperDash.Essentials.Devices.Common.Cameras public event EventHandler PresetsListHasChanged; + protected void OnPresetsListHasChanged() + { + var handler = PresetsListHasChanged; + if (handler == null) + return; + + handler.Invoke(this, EventArgs.Empty); + } + public List Presets { get; private set; } public void PresetSelect(int preset) @@ -537,6 +548,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras SavePreset(preset); } + #endregion #region IHasCameraFocusControl Members From 072411e4f60a142a749465d8a7fc214a43064a41 Mon Sep 17 00:00:00 2001 From: Louis Iacovelli Date: Thu, 12 Aug 2021 11:49:59 -0400 Subject: [PATCH 26/27] Added method to set preset for multiple situations --- .../Cameras/CameraBase.cs | 41 +++++++++++++------ .../Cameras/CameraVisca.cs | 3 +- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs index def22069..18a1ad36 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraBase.cs @@ -216,21 +216,11 @@ namespace PepperDash.Essentials.Devices.Common.Cameras var presetsCamera = cameraDevice as IHasCameraPresets; presetsCamera.PresetsListHasChanged += new EventHandler((o, a) => { - for (int i = 1; i <= joinMap.NumberOfPresets.JoinNumber; i++) - { - int tempNum = i - 1; - - string label = ""; - - var preset = presetsCamera.Presets.FirstOrDefault(p => p.ID.Equals(i)); - - if (preset != null) - label = preset.Description; - - trilist.SetString((ushort) (joinMap.PresetLabelStart.JoinNumber + tempNum), label); - } + SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); }); + SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); + for (int i = 0; i < joinMap.NumberOfPresets.JoinNumber; i++) { int tempNum = i; @@ -246,10 +236,35 @@ namespace PepperDash.Essentials.Devices.Common.Cameras presetsCamera.PresetStore(tempNum, label); }); } + trilist.OnlineStatusChange += (sender, args) => + { + if (!args.DeviceOnLine) + { return; } + + SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist); + }; + + } + } + private void SendCameraPresetNamesToApi(IHasCameraPresets presetsCamera, CameraControllerJoinMap joinMap, BasicTriList trilist) + { + for (int i = 1; i <= joinMap.NumberOfPresets.JoinNumber; i++) + { + int tempNum = i - 1; + + string label = ""; + + var preset = presetsCamera.Presets.FirstOrDefault(p => p.ID.Equals(i)); + + if (preset != null) + label = preset.Description; + + trilist.SetString((ushort)(joinMap.PresetLabelStart.JoinNumber + tempNum), label); } } } + public class CameraPreset : PresetBase { public CameraPreset(int id, string description, bool isDefined, bool isDefinable) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs index 37a0487e..71adf030 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs @@ -171,7 +171,8 @@ namespace PepperDash.Essentials.Devices.Common.Cameras { LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); - OnPresetsListHasChanged(); + //OnPresetsListHasChanged(); + } void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e) From c26d7d73f8ae613c4f28705a9703847464827c60 Mon Sep 17 00:00:00 2001 From: Louis Iacovelli Date: Thu, 12 Aug 2021 15:14:23 -0400 Subject: [PATCH 27/27] Removed commented line. --- .../Essentials Devices Common/Cameras/CameraVisca.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs index 71adf030..6acf5850 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Cameras/CameraVisca.cs @@ -170,9 +170,6 @@ namespace PepperDash.Essentials.Devices.Common.Cameras public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) { LinkCameraToApi(this, trilist, joinStart, joinMapKey, bridge); - - //OnPresetsListHasChanged(); - } void socket_ConnectionChange(object sender, GenericSocketStatusChageEventArgs e)