diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolOutputLogicals.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolOutputLogicals.cs index 3074254e..a8dae7b8 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolOutputLogicals.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Feedbacks/BoolOutputLogicals.cs @@ -23,7 +23,7 @@ namespace PepperDash.Essentials.Core protected bool ComputedValue; - public BoolFeedbackLogic() + protected BoolFeedbackLogic() { Output = new BoolFeedback(() => ComputedValue); } @@ -40,21 +40,18 @@ namespace PepperDash.Essentials.Core public void AddOutputsIn(List outputs) { - foreach (var o in outputs) - { - // skip existing - if (OutputsIn.Contains(o)) continue; - - OutputsIn.Add(o); - o.OutputChange += AnyInput_OutputChange; - } - Evaluate(); + foreach (var o in outputs.Where(o => !OutputsIn.Contains(o))) + { + OutputsIn.Add(o); + o.OutputChange += AnyInput_OutputChange; + } + Evaluate(); } - public void RemoveOutputIn(BoolFeedback output) + public void RemoveOutputIn(BoolFeedback output) { // Don't double up outputs - if (OutputsIn.Contains(output)) return; + if (!OutputsIn.Contains(output)) return; OutputsIn.Remove(output); output.OutputChange -= AnyInput_OutputChange; @@ -71,6 +68,12 @@ namespace PepperDash.Essentials.Core Evaluate(); } + public void ClearOutputs() + { + OutputsIn.Clear(); + Evaluate(); + } + void AnyInput_OutputChange(object sender, EventArgs e) { Evaluate(); @@ -85,11 +88,12 @@ namespace PepperDash.Essentials.Core { var prevValue = ComputedValue; var newValue = OutputsIn.All(o => o.BoolValue); - if (newValue != prevValue) - { - ComputedValue = newValue; - Output.FireUpdate(); - } + if (newValue == prevValue) + { + return; + } + ComputedValue = newValue; + Output.FireUpdate(); } } @@ -99,33 +103,35 @@ namespace PepperDash.Essentials.Core { var prevValue = ComputedValue; var newValue = OutputsIn.Any(o => o.BoolValue); - if (newValue != prevValue) - { - ComputedValue = newValue; - Output.FireUpdate(); - } + if (newValue == prevValue) + { + return; + } + ComputedValue = newValue; + Output.FireUpdate(); } } public class BoolFeedbackLinq : BoolFeedbackLogic { - Func, bool> Predicate; + readonly Func, bool> _predicate; public BoolFeedbackLinq(Func, bool> predicate) : base() { - Predicate = predicate; + _predicate = predicate; } protected override void Evaluate() { var prevValue = ComputedValue; - var newValue = Predicate(OutputsIn); - if (newValue != prevValue) - { - ComputedValue = newValue; - Output.FireUpdate(); - } + var newValue = _predicate(OutputsIn); + if (newValue == prevValue) + { + return; + } + ComputedValue = newValue; + Output.FireUpdate(); } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs index c321dcad..3da9c0dc 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/IOccupancyStatusProviderAggregator.cs @@ -2,17 +2,18 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Crestron.SimplSharp; - +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.GeneralIO; using PepperDash.Core; using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; namespace PepperDash.Essentials.Core { /// /// Aggregates the RoomIsOccupied feedbacks of one or more IOccupancyStatusProvider objects /// - public class IOccupancyStatusProviderAggregator : Device, IOccupancyStatusProvider + public class IOccupancyStatusProviderAggregator : EssentialsDevice, IOccupancyStatusProvider { /// /// Aggregated feedback of all linked IOccupancyStatusProvider devices @@ -21,16 +22,51 @@ namespace PepperDash.Essentials.Core { get { - return AggregatedOccupancyStatus.Output; + return _aggregatedOccupancyStatus.Output; } } - private BoolFeedbackOr AggregatedOccupancyStatus; + private readonly BoolFeedbackOr _aggregatedOccupancyStatus; public IOccupancyStatusProviderAggregator(string key, string name) : base(key, name) { - AggregatedOccupancyStatus = new BoolFeedbackOr(); + _aggregatedOccupancyStatus = new BoolFeedbackOr(); + } + + public IOccupancyStatusProviderAggregator(string key, string name, OccupancyAggregatorConfig config) + : this(key, name) + { + AddPostActivationAction(() => + { + if (config.DeviceKeys.Count == 0) + { + return; + } + + foreach (var deviceKey in config.DeviceKeys) + { + var device = DeviceManager.GetDeviceForKey(deviceKey); + + if (device == null) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, + "Unable to retrieve Occupancy provider with key {0}", deviceKey); + continue; + } + + var provider = device as IOccupancyStatusProvider; + + if (provider == null) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, + "Device with key {0} does NOT implement IOccupancyStatusProvider. Please check configuration."); + continue; + } + + AddOccupancyStatusProvider(provider); + } + }); } /// @@ -39,7 +75,35 @@ namespace PepperDash.Essentials.Core /// public void AddOccupancyStatusProvider(IOccupancyStatusProvider statusProvider) { - AggregatedOccupancyStatus.AddOutputIn(statusProvider.RoomIsOccupiedFeedback); + _aggregatedOccupancyStatus.AddOutputIn(statusProvider.RoomIsOccupiedFeedback); + } + + public void RemoveOccupancyStatusProvider(IOccupancyStatusProvider statusProvider) + { + _aggregatedOccupancyStatus.RemoveOutputIn(statusProvider.RoomIsOccupiedFeedback); + } + + public void ClearOccupancyStatusProviders() + { + _aggregatedOccupancyStatus.ClearOutputs(); } + } + + public class OccupancyAggregatorFactory : EssentialsDeviceFactory + { + public OccupancyAggregatorFactory() + { + TypeNames = new List { "occupancyAggregator", "occAggregate" }; + } + + + public override EssentialsDevice BuildDevice(DeviceConfig dc) + { + Debug.Console(1, "Factory Attempting to create new GlsOccupancySensorBaseController Device"); + + var config = dc.Properties.ToObject(); + + return new IOccupancyStatusProviderAggregator(dc.Key, dc.Name, config); + } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs new file mode 100644 index 00000000..ef237e72 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/OccupancyAggregatorConfig.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace PepperDash.Essentials.Core +{ + public class OccupancyAggregatorConfig + { + [JsonProperty("deviceKeys")] public List DeviceKeys { get; set; } + + public OccupancyAggregatorConfig() + { + DeviceKeys = new List(); + } + } +} \ 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 3919d331..36992629 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -234,6 +234,7 @@ +