diff --git a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs index 5ed1bfa8..c9133a60 100644 --- a/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs +++ b/src/PepperDash.Essentials.Core/CrestronIO/GenericVersiportInputDevice.cs @@ -21,7 +21,7 @@ namespace PepperDash.Essentials.Core.CrestronIO /// /// Represents a generic digital input deviced tied to a versiport /// - public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput + public class GenericVersiportDigitalInputDevice : EssentialsBridgeableDevice, IDigitalInput, IPartitionStateProvider { public Versiport InputPort { get; private set; } @@ -35,10 +35,15 @@ namespace PepperDash.Essentials.Core.CrestronIO } } + public BoolFeedback PartitionPresentFeedback { get; } + + public bool PartitionPresent => !InputStateFeedbackFunc(); + public GenericVersiportDigitalInputDevice(string key, string name, Func postActivationFunc, IOPortConfig config) : base(key, name) { InputStateFeedback = new BoolFeedback(InputStateFeedbackFunc); + PartitionPresentFeedback = new BoolFeedback(() => !InputStateFeedbackFunc()); AddPostActivationAction(() => { @@ -52,7 +57,8 @@ namespace PepperDash.Essentials.Core.CrestronIO InputPort.VersiportChange += InputPort_VersiportChange; - + InputStateFeedback.FireUpdate(); + PartitionPresentFeedback.FireUpdate(); Debug.LogMessage(LogEventLevel.Debug, this, "Created GenericVersiportDigitalInputDevice on port '{0}'. DisablePullUpResistor: '{1}'", config.PortNumber, InputPort.DisablePullUpResistor); @@ -65,7 +71,10 @@ namespace PepperDash.Essentials.Core.CrestronIO Debug.LogMessage(LogEventLevel.Debug, this, "Versiport change: {0}", args.Event); if(args.Event == eVersiportEvent.DigitalInChange) + { InputStateFeedback.FireUpdate(); + PartitionPresentFeedback.FireUpdate(); + } } diff --git a/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs new file mode 100644 index 00000000..7d158027 --- /dev/null +++ b/src/PepperDash.Essentials.Core/DeviceTypeInterfaces/IEmergencyOSD.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PepperDash.Essentials.Core.DeviceTypeInterfaces +{ + public interface IEmergencyOSD + { + void ShowEmergencyMessage(string url); + void HideEmergencyMessage(); + } +} diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs index 3f457176..e9a2c29b 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomConfig.cs @@ -24,6 +24,7 @@ namespace PepperDash.Essentials.Room.Config //switch on emergency type here. Right now only contact and shutdown var e = new EssentialsRoomEmergencyContactClosure(room.Key + "-emergency", props.Emergency, room); DeviceManager.AddDevice(e); + return e; } return null; } diff --git a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs index 76199a91..dbc068eb 100644 --- a/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs +++ b/src/PepperDash.Essentials.Core/Room/Config/EssentialsRoomEmergencyConfig.cs @@ -16,7 +16,7 @@ public class EssentialsRoomEmergencyTriggerConfig { /// - /// contact, + /// contact,versiport /// public string Type { get; set; } /// diff --git a/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs b/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs index 7ad7f700..48d24ab0 100644 --- a/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs +++ b/src/PepperDash.Essentials.Core/Room/EsentialsRoomEmergencyContactClosure.cs @@ -4,12 +4,16 @@ using PepperDash.Essentials.Room.Config; namespace PepperDash.Essentials.Core { - public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase + public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase, IEssentialsRoomEmergency { + public event EventHandler EmergencyStateChange; + IEssentialsRoom Room; string Behavior; bool TriggerOnClose; + public bool InEmergency { get; private set; } + public EssentialsRoomEmergencyContactClosure(string key, EssentialsRoomEmergencyConfig config, IEssentialsRoom room) : base(key) { @@ -25,14 +29,49 @@ namespace PepperDash.Essentials.Core cs.DigitalInputPorts[portNum].StateChange += EsentialsRoomEmergencyContactClosure_StateChange; } } + else if (config.Trigger.Type.Equals("versiport", StringComparison.OrdinalIgnoreCase)) + { + var portNum = (uint)config.Trigger.Number; + if (portNum <= cs.NumberOfVersiPorts) + { + cs.VersiPorts[portNum].Register(); + cs.VersiPorts[portNum].SetVersiportConfiguration(eVersiportConfiguration.DigitalInput); + cs.VersiPorts[portNum].DisablePullUpResistor = true; + cs.VersiPorts[portNum].VersiportChange += EssentialsRoomEmergencyContactClosure_VersiportChange; + } + } Behavior = config.Behavior; TriggerOnClose = config.Trigger.TriggerOnClose; } + private void EssentialsRoomEmergencyContactClosure_VersiportChange(Versiport port, VersiportEventArgs args) + { + if (args.Event == eVersiportEvent.DigitalInChange) + { + ContactClosure_StateChange(port.DigitalIn); + } + } + void EsentialsRoomEmergencyContactClosure_StateChange(DigitalInput digitalInput, DigitalInputEventArgs args) { - if (args.State && TriggerOnClose || !args.State && !TriggerOnClose) + ContactClosure_StateChange(args.State); + } + + void ContactClosure_StateChange(bool portState) + { + if (portState && TriggerOnClose || !portState && !TriggerOnClose) + { + InEmergency = true; + if (EmergencyStateChange != null) + EmergencyStateChange(this, new EventArgs()); RunEmergencyBehavior(); + } + else + { + InEmergency = false; + if (EmergencyStateChange != null) + EmergencyStateChange(this, new EventArgs()); + } } /// @@ -44,4 +83,14 @@ namespace PepperDash.Essentials.Core Room.Shutdown(); } } + + /// + /// Describes the functionality of a room emergency contact closure + /// + public interface IEssentialsRoomEmergency + { + event EventHandler EmergencyStateChange; + + bool InEmergency { get; } + } } \ No newline at end of file diff --git a/src/PepperDash.Essentials.Core/Routing/Extensions.cs b/src/PepperDash.Essentials.Core/Routing/Extensions.cs index fccaa80c..ee885abf 100644 --- a/src/PepperDash.Essentials.Core/Routing/Extensions.cs +++ b/src/PepperDash.Essentials.Core/Routing/Extensions.cs @@ -108,25 +108,31 @@ namespace PepperDash.Essentials.Core private static void RunRouteRequest(RouteRequest request) { - if (request.Source == null) - return; - - var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort); - - if (audioOrSingleRoute == null && videoRoute == null) - return; - - RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute); - - if (videoRoute != null) + try { - RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute); + if (request.Source == null) + return; + + var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort); + + if (audioOrSingleRoute == null && videoRoute == null) + return; + + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute); + + if (videoRoute != null) + { + RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute); + } + + Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); + + audioOrSingleRoute.ExecuteRoutes(); + videoRoute?.ExecuteRoutes(); + } catch(Exception ex) + { + Debug.LogMessage(ex, "Exception Running Route Request {request}", null, request); } - - Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination); - - audioOrSingleRoute.ExecuteRoutes(); - videoRoute?.ExecuteRoutes(); } public static void ReleaseRoute(this IRoutingInputs destination) @@ -141,23 +147,28 @@ namespace PepperDash.Essentials.Core /// public static void ReleaseRoute(this IRoutingInputs destination, string inputPortKey) { - - Debug.LogMessage(LogEventLevel.Information, "Release route for {inputPortKey}", destination, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); - - if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling) + try { - var coolingDevice = destination as IWarmingCooling; + Debug.LogMessage(LogEventLevel.Information, "Release route for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); - coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; - } + if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling) + { + var coolingDevice = destination as IWarmingCooling; - RouteRequests.Remove(destination.Key); + coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRequest.HandleCooldown; + } - var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey); - if (current != null) + RouteRequests.Remove(destination.Key); + + var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination, inputPortKey); + if (current != null) + { + Debug.LogMessage(LogEventLevel.Information, "Releasing current route: {0}", destination, current.Source.Key); + current.ReleaseRoutes(); + } + } catch (Exception ex) { - Debug.LogMessage(LogEventLevel.Debug, "Releasing current route: {0}", destination, current.Source.Key); - current.ReleaseRoutes(); + Debug.LogMessage(ex, "Exception releasing route for '{destination}':'{inputPortKey}'",null, destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); } } @@ -179,7 +190,8 @@ namespace PepperDash.Essentials.Core if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort)) singleTypeRouteDescriptor = null; - foreach (var route in singleTypeRouteDescriptor.Routes) + var routes = singleTypeRouteDescriptor?.Routes ?? new List(); + foreach (var route in routes) { Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString()); } diff --git a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs index 6c4a5df5..9bafc128 100644 --- a/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs +++ b/src/PepperDash.Essentials.Core/Routing/RouteDescriptorCollection.cs @@ -41,7 +41,7 @@ namespace PepperDash.Essentials.Core && RouteDescriptors.Any(t => t.Destination == descriptor.Destination && t.InputPort != null && descriptor.InputPort != null && t.InputPort.Key == descriptor.InputPort.Key)) { Debug.LogMessage(LogEventLevel.Debug, descriptor.Destination, - "Route to [{0}] already exists in global routes table", descriptor.Source.Key); + "Route to [{0}] already exists in global routes table", descriptor?.Source?.Key); return; } RouteDescriptors.Add(descriptor); @@ -53,14 +53,14 @@ namespace PepperDash.Essentials.Core /// null if no RouteDescriptor for a destination exists public RouteDescriptor GetRouteDescriptorForDestination(IRoutingInputs destination) { - Debug.LogMessage(LogEventLevel.Debug, "Getting route descriptor", destination); + Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}'", destination?.Key ?? null); return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination); } public RouteDescriptor GetRouteDescriptorForDestinationAndInputPort(IRoutingInputs destination, string inputPortKey) { - Debug.LogMessage(LogEventLevel.Debug, "Getting route descriptor for {inputPortKey}", destination, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); + Debug.LogMessage(LogEventLevel.Information, "Getting route descriptor for '{destination}':'{inputPortKey}'", destination?.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); return RouteDescriptors.FirstOrDefault(rd => rd.Destination == destination && rd.InputPort != null && rd.InputPort.Key == inputPortKey); } @@ -70,7 +70,7 @@ namespace PepperDash.Essentials.Core /// public RouteDescriptor RemoveRouteDescriptor(IRoutingInputs destination, string inputPortKey = "") { - Debug.LogMessage(LogEventLevel.Debug, "Removing route descriptor for {inputPortKey}", destination, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); + Debug.LogMessage(LogEventLevel.Information, "Removing route descriptor for '{destination}':'{inputPortKey}'", destination.Key ?? null, string.IsNullOrEmpty(inputPortKey) ? "auto" : inputPortKey); var descr = string.IsNullOrEmpty(inputPortKey) ? GetRouteDescriptorForDestination(destination) @@ -78,7 +78,7 @@ namespace PepperDash.Essentials.Core if (descr != null) RouteDescriptors.Remove(descr); - Debug.LogMessage(LogEventLevel.Debug, "Found route descriptor {routeDescriptor}", destination, descr); + Debug.LogMessage(LogEventLevel.Information, "Found route descriptor {routeDescriptor}", destination, descr); return descr; }