Compare commits

..

1 Commits

Author SHA1 Message Date
Andrew Welker
185410b802 fix: ignore case for appdebug {LogLevel} 2025-05-07 08:08:56 -05:00
80 changed files with 1869 additions and 3928 deletions

3
.gitignore vendored
View File

@@ -393,5 +393,4 @@ essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/Pepp
/._PepperDash.Essentials.sln
.vscode/settings.json
_site/
api/
*.DS_Store
api/

View File

@@ -11,35 +11,35 @@ namespace PepperDash.Core
public class Device : IKeyName
{
/// <summary>
/// Unique Key
/// </summary>
/// <summary>
/// Unique Key
/// </summary>
public string Key { get; protected set; }
/// <summary>
/// Name of the devie
/// </summary>
public string Name { get; protected set; }
/// <summary>
///
/// </summary>
public string Name { get; protected set; }
/// <summary>
///
/// </summary>
public bool Enabled { get; protected set; }
///// <summary>
///// A place to store reference to the original config object, if any. These values should
///// NOT be used as properties on the device as they are all publicly-settable values.
///// </summary>
//public DeviceConfig Config { get; private set; }
///// <summary>
///// Helper method to check if Config exists
///// </summary>
//public bool HasConfig { get { return Config != null; } }
///// <summary>
///// A place to store reference to the original config object, if any. These values should
///// NOT be used as properties on the device as they are all publicly-settable values.
///// </summary>
//public DeviceConfig Config { get; private set; }
///// <summary>
///// Helper method to check if Config exists
///// </summary>
//public bool HasConfig { get { return Config != null; } }
List<Action> _PreActivationActions;
List<Action> _PostActivationActions;
/// <summary>
///
/// </summary>
/// <summary>
///
/// </summary>
public static Device DefaultDevice { get { return _DefaultDevice; } }
static Device _DefaultDevice = new Device("Default", "Default");
@@ -54,27 +54,27 @@ namespace PepperDash.Core
Name = "";
}
/// <summary>
/// Constructor with key and name
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
/// <summary>
/// Constructor with key and name
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public Device(string key, string name) : this(key)
{
Name = name;
}
//public Device(DeviceConfig config)
// : this(config.Key, config.Name)
//{
// Config = config;
//}
//public Device(DeviceConfig config)
// : this(config.Key, config.Name)
//{
// Config = config;
//}
/// <summary>
/// Adds a pre activation action
/// </summary>
/// <param name="act"></param>
/// <summary>
/// Adds a pre activation action
/// </summary>
/// <param name="act"></param>
public void AddPreActivationAction(Action act)
{
if (_PreActivationActions == null)
@@ -82,10 +82,10 @@ namespace PepperDash.Core
_PreActivationActions.Add(act);
}
/// <summary>
/// Adds a post activation action
/// </summary>
/// <param name="act"></param>
/// <summary>
/// Adds a post activation action
/// </summary>
/// <param name="act"></param>
public void AddPostActivationAction(Action act)
{
if (_PostActivationActions == null)
@@ -93,58 +93,55 @@ namespace PepperDash.Core
_PostActivationActions.Add(act);
}
/// <summary>
/// Executes the preactivation actions
/// </summary>
public void PreActivate()
{
if (_PreActivationActions != null)
_PreActivationActions.ForEach(a =>
{
/// <summary>
/// Executes the preactivation actions
/// </summary>
public void PreActivate()
{
if (_PreActivationActions != null)
_PreActivationActions.ForEach(a => {
try
{
a.Invoke();
}
catch (Exception e)
{
} catch (Exception e)
{
Debug.LogMessage(e, "Error in PreActivationAction: " + e.Message, this);
}
});
}
});
}
/// <summary>
/// Gets this device ready to be used in the system. Runs any added pre-activation items, and
/// all post-activation at end. Classes needing additional logic to
/// run should override CustomActivate()
/// </summary>
public bool Activate()
public bool Activate()
{
//if (_PreActivationActions != null)
// _PreActivationActions.ForEach(a => a.Invoke());
//if (_PreActivationActions != null)
// _PreActivationActions.ForEach(a => a.Invoke());
var result = CustomActivate();
//if(result && _PostActivationActions != null)
// _PostActivationActions.ForEach(a => a.Invoke());
return result;
//if(result && _PostActivationActions != null)
// _PostActivationActions.ForEach(a => a.Invoke());
return result;
}
/// <summary>
/// Executes the postactivation actions
/// </summary>
public void PostActivate()
{
if (_PostActivationActions != null)
_PostActivationActions.ForEach(a =>
{
try
{
a.Invoke();
}
catch (Exception e)
{
Debug.LogMessage(e, "Error in PostActivationAction: " + e.Message, this);
}
});
}
/// <summary>
/// Executes the postactivation actions
/// </summary>
public void PostActivate()
{
if (_PostActivationActions != null)
_PostActivationActions.ForEach(a => {
try
{
a.Invoke();
}
catch (Exception e)
{
Debug.LogMessage(e, "Error in PostActivationAction: " + e.Message, this);
}
});
}
/// <summary>
/// Called in between Pre and PostActivationActions when Activate() is called.
@@ -161,14 +158,14 @@ namespace PepperDash.Core
/// <returns></returns>
public virtual bool Deactivate() { return true; }
/// <summary>
/// Call this method to start communications with a device. Overriding classes do not need to call base.Initialize()
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// Call this method to start communications with a device. Overriding classes do not need to call base.Initialize()
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// <summary>
/// Helper method to check object for bool value false and fire an Action method
/// </summary>
/// <param name="o">Should be of type bool, others will be ignored</param>
@@ -178,15 +175,5 @@ namespace PepperDash.Core
if (o is bool && !(bool)o) a();
}
/// <summary>
/// Returns a string representation of the object, including its key and name.
/// </summary>
/// <remarks>The returned string is formatted as "{Key} - {Name}". If the <c>Name</c> property is
/// null or empty, "---" is used in place of the name.</remarks>
/// <returns>A string that represents the object, containing the key and name in the format "{Key} - {Name}".</returns>
public override string ToString()
{
return string.Format("{0} - {1}", Key, string.IsNullOrEmpty(Name) ? "---" : Name);
}
}
}

View File

@@ -353,7 +353,7 @@ namespace PepperDash.Core
return;
}
if(Enum.TryParse<LogEventLevel>(levelString, out var levelEnum))
if(Enum.TryParse<LogEventLevel>(levelString, true, out var levelEnum))
{
SetDebugLevel(levelEnum);
return;

View File

@@ -1,107 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{
/// <summary>
/// This defines a device that has screens with layouts
/// Simply decorative
/// </summary>
public interface IHasScreensWithLayouts
{
/// <summary>
/// A dictionary of screens, keyed by screen ID, that contains information about each screen and its layouts.
/// </summary>
Dictionary<uint, ScreenInfo> Screens { get; }
/// <summary>
/// Applies a specific layout to a screen based on the provided screen ID and layout index.
/// </summary>
/// <param name="screenId"></param>
/// <param name="layoutIndex"></param>
void ApplyLayout(uint screenId, uint layoutIndex);
}
/// <summary>
/// Represents information about a screen and its layouts.
/// </summary>
public class ScreenInfo
{
/// <summary>
/// Indicates whether the screen is enabled or not.
/// </summary>
[JsonProperty("enabled")]
public bool Enabled { get; set; }
/// <summary>
/// The name of the screen.
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// The index of the screen.
/// </summary>
[JsonProperty("screenIndex")]
public int ScreenIndex { get; set; }
/// <summary>
/// A dictionary of layout information for the screen, keyed by layout ID.
/// </summary>
[JsonProperty("layouts")]
public Dictionary<uint, LayoutInfo> Layouts { get; set; }
}
/// <summary>
/// Represents information about a layout on a screen.
/// </summary>
public class LayoutInfo
{
/// <summary>
/// The name of the layout.
/// </summary>
[JsonProperty("layoutName")]
public string LayoutName { get; set; }
/// <summary>
/// The index of the layout.
/// </summary>
[JsonProperty("layoutIndex")]
public int LayoutIndex { get; set; }
/// <summary>
/// The type of the layout, which can be "single", "double", "triple", or "quad".
/// </summary>
[JsonProperty("layoutType")]
public string LayoutType { get; set; }
/// <summary>
/// A dictionary of window configurations for the layout, keyed by window ID.
/// </summary>
[JsonProperty("windows")]
public Dictionary<uint, WindowConfig> Windows { get; set; }
}
/// <summary>
/// Represents the configuration of a window within a layout on a screen.
/// </summary>
public class WindowConfig
{
/// <summary>
/// The display label for the window
/// </summary>
[JsonProperty("label")]
public string Label { get; set; }
/// <summary>
/// The input for the window
/// </summary>
[JsonProperty("input")]
public string Input { get; set; }
}
}

View File

@@ -1,90 +0,0 @@
using Crestron.SimplSharpPro.DM.Streaming;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Represents a collection of network port information and provides notifications when the information changes.
/// </summary>
/// <remarks>This interface is designed to provide access to a list of network port details and to notify
/// subscribers when the port information is updated. Implementations of this interface should ensure that the <see
/// cref="PortInformationChanged"/> event is raised whenever the <see cref="NetworkPorts"/> collection
/// changes.</remarks>
public interface INvxNetworkPortInformation
{
/// <summary>
/// Occurs when the port information changes.
/// </summary>
/// <remarks>This event is triggered whenever there is a change in the port information, such as
/// updates to port settings or status. Subscribers can handle this event to respond to such changes.</remarks>
event EventHandler PortInformationChanged;
/// <summary>
/// Gets the collection of network port information associated with the current instance.
/// </summary>
/// <remarks>The collection provides information about the network ports, such as their status,
/// configuration, or other relevant details. The returned list is read-only and cannot be modified
/// directly.</remarks>
List<NvxNetworkPortInformation> NetworkPorts { get; }
}
/// <summary>
/// Represents information about a network port, including its configuration and associated system details.
/// </summary>
/// <remarks>This class provides properties to describe various attributes of a network port, such as its
/// name, description, VLAN configuration, and management IP address. It is typically used to store and retrieve
/// metadata about network ports in a managed environment.</remarks>
public class NvxNetworkPortInformation
{
private readonly DmNvxBaseClass.DmNvx35xNetwork.DmNvxNetworkLldpPort port;
/// <summary>
/// Gets or sets the index of the device port.
/// </summary>
public uint DevicePortIndex { get; }
/// <summary>
/// Gets or sets the name of the port used for communication.
/// </summary>
public string PortName => port.PortNameFeedback.StringValue;
/// <summary>
/// Gets or sets the description of the port.
/// </summary>
public string PortDescription => port.PortNameDescriptionFeedback.StringValue;
/// <summary>
/// Gets or sets the name of the VLAN (Virtual Local Area Network).
/// </summary>
public string VlanName => port.VlanNameFeedback.StringValue;
/// <summary>
/// Gets the IP management address associated with the port.
/// </summary>
public string IpManagementAddress => port.IpManagementAddressFeedback.StringValue;
/// <summary>
/// Gets the name of the system as reported by the associated port.
/// </summary>
public string SystemName => port.SystemNameFeedback.StringValue;
/// <summary>
/// Gets the description of the system name.
/// </summary>
public string SystemNameDescription => port.SystemNameDescriptionFeedback.StringValue;
/// <summary>
/// Initializes a new instance of the <see cref="NvxNetworkPortInformation"/> class with the specified network port
/// and device port index.
/// </summary>
/// <param name="port">The network port associated with the device. Cannot be <see langword="null"/>.</param>
/// <param name="devicePortIndex">The index of the device port.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="port"/> is <see langword="null"/>.</exception>
public NvxNetworkPortInformation(DmNvxBaseClass.DmNvx35xNetwork.DmNvxNetworkLldpPort port, uint devicePortIndex)
{
this.port = port ?? throw new ArgumentNullException(nameof(port), "Port cannot be null");
DevicePortIndex = devicePortIndex;
}
}
}

View File

@@ -248,7 +248,7 @@ namespace PepperDash.Essentials.Core
foreach (var dev in Devices.Values.OfType<ICommunicationMonitor>())
{
CrestronConsole.ConsoleCommandResponse($"{dev}: {dev.CommunicationMonitor.Status}\r\n");
CrestronConsole.ConsoleCommandResponse($"{dev}: {dev.CommunicationMonitor.Status}{Environment.NewLine}");
}
}

View File

@@ -20,20 +20,19 @@ namespace PepperDash.Essentials.Core
public event EventHandler Initialized;
private bool _isInitialized;
public bool IsInitialized
{
public bool IsInitialized {
get { return _isInitialized; }
private set
{
private set
{
if (_isInitialized == value) return;
_isInitialized = value;
if (_isInitialized)
{
Initialized?.Invoke(this, new EventArgs());
}
}
}
}
protected EssentialsDevice(string key)
@@ -81,9 +80,8 @@ namespace PepperDash.Essentials.Core
/// <summary>
/// Override this method to build and create custom Mobile Control Messengers during the Activation phase
/// </summary>
protected virtual void CreateMobileControlMessengers()
{
protected virtual void CreateMobileControlMessengers() {
}
}

View File

@@ -9,15 +9,10 @@ using PepperDash.Essentials.Core.Devices;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Represents a level control item in a list, which can be used to control volume or mute functionality.
/// </summary>
public class LevelControlListItem : AudioControlListItemBase
{
/// <summary>
/// A reference to the IBasicVolumeWithFeedback device for control.
/// </summary>
[JsonIgnore]
public IBasicVolumeWithFeedback LevelControl
{
@@ -60,7 +55,7 @@ namespace PepperDash.Essentials.Core
{
get
{
if (string.IsNullOrEmpty(ItemKey)) return ParentDeviceKey;
if(string.IsNullOrEmpty(ItemKey)) return ParentDeviceKey;
else
{
return DeviceManager.AllDevices.
@@ -75,39 +70,13 @@ namespace PepperDash.Essentials.Core
[JsonProperty("type")]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public eLevelControlType Type { get; set; }
/// <summary>
/// Indicates if the item is a mic or not.
/// </summary>
[JsonProperty("isMic", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsMic { get; set; }
/// <summary>
/// Indicates if the item should show the raw level in the UI.
/// </summary>
[JsonProperty("showRawLevel", NullValueHandling = NullValueHandling.Ignore)]
public bool? ShowRawLevel { get; set; }
}
/// <summary>
/// Indicates the type of level control item.
/// </summary>
[Flags]
public enum eLevelControlType
{
/// <summary>
/// Indicates that the item is a level control only
/// </summary>
Level = 1,
/// <summary>
/// Indicates that the item is a mute control only
/// </summary>
Mute = 2,
/// <summary>
/// Indicates that the item is both a level and mute control
/// </summary>
LevelAndMute = Level | Mute,
}
}

View File

@@ -10,18 +10,7 @@ namespace PepperDash.Essentials.Core
/// </summary>
public enum eSourceListItemType
{
/// <summary>
/// Represents a typical route.
/// </summary>
Route,
/// <summary>
/// Represents an off route.
/// </summary>
Off,
/// <summary>
/// Represents some other type of route
/// </summary>
Other,
Route, Off, Other, SomethingAwesomerThanThese
}
/// <summary>
@@ -29,9 +18,6 @@ namespace PepperDash.Essentials.Core
/// </summary>
public class SourceListItem
{
/// <summary>
/// The key of the source item, which is used to identify it in the DeviceManager
/// </summary>
[JsonProperty("sourceKey")]
public string SourceKey { get; set; }
@@ -131,9 +117,6 @@ namespace PepperDash.Essentials.Core
[JsonProperty("disableRoutedSharing")]
public bool DisableRoutedSharing { get; set; }
/// <summary>
///
/// </summary>
[JsonProperty("destinations")]
public List<eSourceListItemDestinationTypes> Destinations { get; set; }
/// <summary>
@@ -166,56 +149,31 @@ namespace PepperDash.Essentials.Core
[JsonProperty("disableSimpleRouting")]
public bool DisableSimpleRouting { get; set; }
/// <summary>
/// Default constructor for SourceListItem, initializes the Icon to "Blank"
/// </summary>
public SourceListItem()
{
Icon = "Blank";
}
/// <summary>
/// Returns a string representation of the SourceListItem, including the SourceKey and Name
/// </summary>
/// <returns></returns>
public override string ToString()
{
return $"{SourceKey}:{Name}";
}
}
/// <summary>
/// Represents a route in a source list item, which defines the source and destination keys and the type of signal being routed
/// </summary>
public class SourceRouteListItem
{
/// <summary>
/// The key of the source device to route from
/// </summary>
[JsonProperty("sourceKey")]
public string SourceKey { get; set; }
/// <summary>
/// The key of the source port to route from
/// </summary>
[JsonProperty("sourcePortKey")]
public string SourcePortKey { get; set; }
/// <summary>
/// The key of the destination device to route to
/// </summary>
[JsonProperty("destinationKey")]
public string DestinationKey { get; set; }
/// <summary>
/// The key of the destination port to route to
/// </summary>
[JsonProperty("destinationPortKey")]
public string DestinationPortKey { get; set; }
/// <summary>
/// The type of signal being routed, such as audio or video
/// </summary>
[JsonProperty("type")]
public eRoutingSignalType Type { get; set; }
}
@@ -225,85 +183,15 @@ namespace PepperDash.Essentials.Core
/// </summary>
public enum eSourceListItemDestinationTypes
{
/// <summary>
/// Default display, used for the main video output in a room
/// </summary>
defaultDisplay,
/// <summary>
/// Left display
/// </summary>
leftDisplay,
/// <summary>
/// Right display
/// </summary>
rightDisplay,
/// <summary>
/// Center display
/// </summary>
centerDisplay,
/// <summary>
/// Program audio, used for the main audio output in a room
/// </summary>
programAudio,
/// <summary>
/// Codec content, used for sharing content to the far end in a video call
/// </summary>
codecContent,
/// <summary>
/// Front left display, used for rooms with multiple displays
/// </summary>
frontLeftDisplay,
/// <summary>
/// Front right display, used for rooms with multiple displays
/// </summary>
frontRightDisplay,
/// <summary>
/// Rear left display, used for rooms with multiple displays
/// </summary>
rearLeftDisplay,
/// <summary>
/// Rear right display, used for rooms with multiple displays
/// </summary>
rearRightDisplay,
/// <summary>
/// Auxiliary display 1, used for additional displays in a room
/// </summary>
auxDisplay1,
/// <summary>
/// Auxiliary display 2, used for additional displays in a room
/// </summary>
auxDisplay2,
/// <summary>
/// Auxiliary display 3, used for additional displays in a room
/// </summary>
auxDisplay3,
/// <summary>
/// Auxiliary display 4, used for additional displays in a room
/// </summary>
auxDisplay4,
/// <summary>
/// Auxiliary display 5, used for additional displays in a room
/// </summary>
auxDisplay5,
/// <summary>
/// Auxiliary display 6, used for additional displays in a room
/// </summary>
auxDisplay6,
/// <summary>
/// Auxiliary display 7, used for additional displays in a room
/// </summary>
auxDisplay7,
/// <summary>
/// Auxiliary display 8, used for additional displays in a room
/// </summary>
auxDisplay8,
/// <summary>
/// Auxiliary display 9, used for additional displays in a room
/// </summary>
auxDisplay9,
/// <summary>
/// Auxiliary display 10, used for additional displays in a room
/// </summary>
auxDisplay10,
}
}

View File

@@ -1,86 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Extensions for IPAddress to provide additional functionality such as getting broadcast address, network address, and checking if two addresses are in the same subnet.
/// </summary>
public static class IPAddressExtensions
{
/// <summary>
/// Get the broadcast address for a given IP address and subnet mask.
/// </summary>
/// <param name="address">Address to check</param>
/// <param name="subnetMask">Subnet mask in a.b.c.d format</param>
/// <returns>Broadcast address</returns>
/// <remarks>
/// If the input IP address is 192.168.1.100 and the subnet mask is 255.255.255.0, the broadcast address will be 192.168.1.255
/// </remarks>
/// <exception cref="ArgumentException"></exception>
public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
}
return new IPAddress(broadcastAddress);
}
/// <summary>
/// Get the network address for a given IP address and subnet mask.
/// </summary>
/// <param name="address">Address to check</param>
/// <param name="subnetMask">Subnet mask in a.b.c.d</param>
/// <returns>Network Address</returns>
/// /// <remarks>
/// If the input IP address is 192.168.1.100 and the subnet mask is 255.255.255.0, the network address will be 192.168.1.0
/// </remarks>
/// <exception cref="ArgumentException"></exception>
public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
}
return new IPAddress(broadcastAddress);
}
/// <summary>
/// Determine if two IP addresses are in the same subnet.
/// </summary>
/// <param name="address2">Address to check</param>
/// <param name="address">Second address to check</param>
/// <param name="subnetMask">Subnet mask to use to compare the 2 IP Address</param>
/// <returns>True if addresses are in the same subnet</returns>
/// <remarks>
/// If the input IP addresses are 192.168.1.100 and 192.168.1.200, and the subnet mask is 255.255.255.0, this will return true.
/// If the input IP addresses are 10.1.1.100 and 192.168.1.100, and the subnet mask is 255.255.255.0, this will return false.
/// </remarks>
public static bool IsInSameSubnet(this IPAddress address2, IPAddress address, IPAddress subnetMask)
{
IPAddress network1 = address.GetNetworkAddress(subnetMask);
IPAddress network2 = address2.GetNetworkAddress(subnetMask);
return network1.Equals(network2);
}
}
}

View File

@@ -10,13 +10,6 @@ using System.Threading.Tasks;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Represents a device that manages room combinations by controlling partitions and scenarios.
/// </summary>
/// <remarks>The <see cref="EssentialsRoomCombiner"/> allows for dynamic configuration of room
/// combinations based on partition states and predefined scenarios. It supports both automatic and manual modes
/// for managing room combinations. In automatic mode, the device determines the current room combination scenario
/// based on partition sensor states. In manual mode, scenarios can be set explicitly by the user.</remarks>
public class EssentialsRoomCombiner : EssentialsDevice, IEssentialsRoomCombiner
{
private EssentialsRoomCombinerPropertiesConfig _propertiesConfig;
@@ -25,9 +18,6 @@ namespace PepperDash.Essentials.Core
private List<IEssentialsRoom> _rooms;
/// <summary>
/// Gets a list of rooms represented as key-name pairs.
/// </summary>
public List<IKeyName> Rooms
{
get
@@ -38,12 +28,6 @@ namespace PepperDash.Essentials.Core
private bool _isInAutoMode;
/// <summary>
/// Gets or sets a value indicating whether the system is operating in automatic mode.
/// </summary>
/// <remarks>Changing this property triggers an update event via
/// <c>IsInAutoModeFeedback.FireUpdate()</c>. Ensure that any event listeners are properly configured to handle
/// this update.</remarks>
public bool IsInAutoMode
{
get
@@ -62,36 +46,12 @@ namespace PepperDash.Essentials.Core
}
}
/// <summary>
/// Gets a value indicating whether automatic mode is disabled.
/// </summary>
public bool DisableAutoMode
{
get
{
return _propertiesConfig.DisableAutoMode;
}
}
private CTimer _scenarioChangeDebounceTimer;
private int _scenarioChangeDebounceTimeSeconds = 10; // default to 10s
private Mutex _scenarioChange = new Mutex();
/// <summary>
/// Initializes a new instance of the <see cref="EssentialsRoomCombiner"/> class, which manages room combination
/// scenarios and partition states.
/// </summary>
/// <remarks>The <see cref="EssentialsRoomCombiner"/> class is designed to handle dynamic room
/// combination scenarios based on partition states. It supports both automatic and manual modes for managing
/// room combinations. By default, the instance starts in automatic mode unless the <paramref name="props"/>
/// specifies otherwise. After activation, the room combiner initializes partition state providers and sets up
/// the initial room configuration. Additionally, it subscribes to the <see
/// cref="DeviceManager.AllDevicesInitialized"/> event to ensure proper initialization of dependent devices
/// before determining or setting the room combination scenario.</remarks>
/// <param name="key">The unique identifier for the room combiner instance.</param>
/// <param name="props">The configuration properties for the room combiner, including default settings and debounce times.</param>
public EssentialsRoomCombiner(string key, EssentialsRoomCombinerPropertiesConfig props)
: base(key)
{
@@ -286,16 +246,8 @@ namespace PepperDash.Essentials.Core
#region IEssentialsRoomCombiner Members
/// <summary>
/// Occurs when the room combination scenario changes.
/// </summary>
/// <remarks>This event is triggered whenever the configuration or state of the room combination
/// changes. Subscribers can use this event to update their logic or UI based on the new scenario.</remarks>
public event EventHandler<EventArgs> RoomCombinationScenarioChanged;
/// <summary>
/// Gets the current room combination scenario.
/// </summary>
public IRoomCombinationScenario CurrentScenario
{
get
@@ -304,25 +256,10 @@ namespace PepperDash.Essentials.Core
}
}
/// <summary>
/// Gets the feedback indicating whether the system is currently in auto mode.
/// </summary>
public BoolFeedback IsInAutoModeFeedback { get; private set; }
/// <summary>
/// Enables auto mode for the room combiner and its partitions, allowing automatic room combination scenarios to
/// be determined.
/// </summary>
/// <remarks>Auto mode allows the room combiner to automatically adjust its configuration based on
/// the state of its partitions. If auto mode is disabled in the configuration, this method logs a warning and
/// does not enable auto mode.</remarks>
public void SetAutoMode()
{
if(_propertiesConfig.DisableAutoMode)
{
this.LogWarning("Auto mode is disabled for this room combiner. Cannot set to auto mode.");
return;
}
IsInAutoMode = true;
foreach (var partition in Partitions)
@@ -333,12 +270,6 @@ namespace PepperDash.Essentials.Core
DetermineRoomCombinationScenario();
}
/// <summary>
/// Switches the system to manual mode, disabling automatic operations.
/// </summary>
/// <remarks>This method sets the system to manual mode by updating the mode state and propagates
/// the change to all partitions. Once in manual mode, automatic operations are disabled for the system and its
/// partitions.</remarks>
public void SetManualMode()
{
IsInAutoMode = false;
@@ -349,11 +280,6 @@ namespace PepperDash.Essentials.Core
}
}
/// <summary>
/// Toggles the current mode between automatic and manual.
/// </summary>
/// <remarks>If the current mode is automatic, this method switches to manual mode. If the
/// current mode is manual, it switches to automatic mode.</remarks>
public void ToggleMode()
{
if (IsInAutoMode)
@@ -366,22 +292,10 @@ namespace PepperDash.Essentials.Core
}
}
/// <summary>
/// Gets the collection of room combination scenarios.
/// </summary>
public List<IRoomCombinationScenario> RoomCombinationScenarios { get; private set; }
/// <summary>
/// Gets the collection of partition controllers managed by this instance.
/// </summary>
public List<IPartitionController> Partitions { get; private set; }
/// <summary>
/// Toggles the state of the partition identified by the specified partition key.
/// </summary>
/// <remarks>If no partition with the specified key exists, the method performs no
/// action.</remarks>
/// <param name="partitionKey">The key of the partition whose state is to be toggled. This value cannot be null or empty.</param>
public void TogglePartitionState(string partitionKey)
{
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey));
@@ -392,17 +306,6 @@ namespace PepperDash.Essentials.Core
}
}
/// <summary>
/// Sets the room combination scenario based on the specified scenario key.
/// </summary>
/// <remarks>This method manually adjusts the partition states according to the specified
/// scenario. If the application is in auto mode, the operation will not proceed, and a log message will be
/// generated indicating that the mode must be set to manual first. If the specified scenario key does not
/// match any existing scenario, a debug log message will be generated. For each partition state in the
/// scenario, the corresponding partition will be updated to either "Present" or "Not Present" based on the
/// scenario's configuration. If a partition key in the scenario cannot be found, a debug log message will be
/// generated.</remarks>
/// <param name="scenarioKey">The key identifying the room combination scenario to apply. This must match the key of an existing scenario.</param>
public void SetRoomCombinationScenario(string scenarioKey)
{
if (IsInAutoMode)
@@ -451,32 +354,13 @@ namespace PepperDash.Essentials.Core
#endregion
}
/// <summary>
/// Provides a factory for creating instances of <see cref="EssentialsRoomCombiner"/> devices.
/// </summary>
/// <remarks>This factory is responsible for constructing <see cref="EssentialsRoomCombiner"/> devices
/// based on the provided configuration. It supports the type name "essentialsroomcombiner" for device
/// creation.</remarks>
public class EssentialsRoomCombinerFactory : EssentialsDeviceFactory<EssentialsRoomCombiner>
{
/// <summary>
/// Initializes a new instance of the <see cref="EssentialsRoomCombinerFactory"/> class.
/// </summary>
/// <remarks>This factory is used to create instances of room combiners with the specified type
/// names. By default, the factory includes the type name "essentialsroomcombiner".</remarks>
public EssentialsRoomCombinerFactory()
{
TypeNames = new List<string> { "essentialsroomcombiner" };
}
/// <summary>
/// Creates and initializes a new instance of the <see cref="EssentialsRoomCombiner"/> device.
/// </summary>
/// <remarks>This method uses the provided device configuration to extract the properties and
/// create an <see cref="EssentialsRoomCombiner"/> device. Ensure that the configuration contains valid
/// properties for the device to be created successfully.</remarks>
/// <param name="dc">The device configuration containing the key and properties required to build the device.</param>
/// <returns>A new instance of <see cref="EssentialsRoomCombiner"/> initialized with the specified configuration.</returns>
public override EssentialsDevice BuildDevice(PepperDash.Essentials.Core.Config.DeviceConfig dc)
{
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new EssentialsRoomCombiner Device");

View File

@@ -1,4 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
@@ -11,14 +17,6 @@ namespace PepperDash.Essentials.Core
/// </summary>
public class EssentialsRoomCombinerPropertiesConfig
{
/// <summary>
/// Gets or sets a value indicating whether the system operates in automatic mode.
/// <remarks>Some systems don't have partitions sensors, and show shouldn't allow auto mode to be turned on. When this is true in the configuration,
/// auto mode won't be allowed to be turned on.</remarks>
/// </summary>
[JsonProperty("disableAutoMode")]
public bool DisableAutoMode { get; set; }
/// <summary>
/// The list of partitions that device the rooms
/// </summary>
@@ -49,9 +47,6 @@ namespace PepperDash.Essentials.Core
[JsonProperty("defaultScenarioKey")]
public string defaultScenarioKey { get; set; }
/// <summary>
/// Gets or sets the debounce time, in seconds, for scenario changes.
/// </summary>
[JsonProperty("scenarioChangeDebounceTimeSeconds")]
public int ScenarioChangeDebounceTimeSeconds { get; set; }
}
@@ -61,15 +56,9 @@ namespace PepperDash.Essentials.Core
/// </summary>
public class PartitionConfig : IKeyName
{
/// <summary>
/// Gets or sets the unique key associated with the object.
/// </summary>
[JsonProperty("key")]
public string Key { get; set; }
/// <summary>
/// Gets or sets the name associated with the object.
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
@@ -91,21 +80,12 @@ namespace PepperDash.Essentials.Core
/// </summary>
public class RoomCombinationScenarioConfig : IKeyName
{
/// <summary>
/// Gets or sets the key associated with the object.
/// </summary>
[JsonProperty("key")]
public string Key { get; set; }
/// <summary>
/// Gets or sets the name associated with the object.
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// Gets or sets the collection of partition states.
/// </summary>
[JsonProperty("partitionStates")]
public List<PartitionState> PartitionStates { get; set; }
@@ -115,15 +95,9 @@ namespace PepperDash.Essentials.Core
[JsonProperty("uiMap")]
public Dictionary<string, string> UiMap { get; set; }
/// <summary>
/// Gets or sets the list of actions to be performed during device activation.
/// </summary>
[JsonProperty("activationActions")]
public List<DeviceActionWrapper> ActivationActions { get; set; }
/// <summary>
/// Gets or sets the list of actions to be performed when a device is deactivated.
/// </summary>
[JsonProperty("deactivationActions")]
public List<DeviceActionWrapper> DeactivationActions { get; set; }
}
@@ -133,15 +107,9 @@ namespace PepperDash.Essentials.Core
/// </summary>
public class PartitionState
{
/// <summary>
/// Gets or sets the partition key used to group and organize data within a storage system.
/// </summary>
[JsonProperty("partitionKey")]
public string PartitionKey { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a partition is currently present.
/// </summary>
[JsonProperty("partitionSensedState")]
public bool PartitionPresent { get; set; }
}

View File

@@ -28,20 +28,9 @@ namespace PepperDash.Essentials.Core
[JsonIgnore]
BoolFeedback IsInAutoModeFeedback {get;}
/// <summary>
/// Gets a value indicating whether the automatic mode is disabled.
/// </summary>
[JsonProperty("disableAutoMode")]
bool DisableAutoMode { get; }
/// <summary>
/// Gets a value indicating whether the system is operating in automatic mode.
/// </summary>
[JsonProperty("isInAutoMode")]
bool IsInAutoMode { get; }
/// <summary>
/// Gets the collection of rooms associated with the current object.
/// </summary>
[JsonProperty("rooms")]
List<IKeyName> Rooms { get; }
@@ -85,13 +74,6 @@ namespace PepperDash.Essentials.Core
void SetRoomCombinationScenario(string scenarioKey);
}
/// <summary>
/// Represents a scenario for combining rooms, including activation, deactivation, and associated state.
/// </summary>
/// <remarks>This interface defines the behavior for managing room combination scenarios, including
/// activation and deactivation, tracking the active state, and managing related partition states and UI mappings.
/// Implementations of this interface are expected to handle the logic for room combinations based on the provided
/// partition states and UI mappings.</remarks>
public interface IRoomCombinationScenario : IKeyName
{
/// <summary>
@@ -100,9 +82,6 @@ namespace PepperDash.Essentials.Core
[JsonIgnore]
BoolFeedback IsActiveFeedback { get; }
/// <summary>
/// Gets a value indicating whether the entity is active.
/// </summary>
[JsonProperty("isActive")]
bool IsActive { get; }

View File

@@ -7,14 +7,8 @@
{
}
/// <summary>
/// For fixed-source endpoint devices with an input port
/// </summary>
public interface IRoutingSinkWithInputPort :IRoutingSink
{
/// <summary>
/// Gets the current input port for this routing sink.
/// </summary>
RoutingInputPort CurrentInputPort { get; }
}
/*/// <summary>

View File

@@ -227,7 +227,7 @@ namespace PepperDash.Essentials.Devices.Common.Cameras
SendCameraPresetNamesToApi(presetsCamera, joinMap, trilist);
for (int i = 0; i < joinMap.PresetRecallStart.JoinSpan; i++)
for (int i = 0; i < joinMap.NumberOfPresets.JoinSpan; i++)
{
int tempNum = i;

View File

@@ -1,95 +0,0 @@
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Essentials.Devices.Common.Codec.Cisco
{
/// <summary>
/// Describes the available tracking modes for a Cisco codec's Presenter Track feature.
/// </summary>
public enum ePresenterTrackMode
{
/// <summary>
/// Presenter Track is turned off.
/// </summary>
Off,
/// <summary>
/// Presenter Track follows the speaker's movements.
/// </summary>
Follow,
/// <summary>
/// Presenter Track is set to background mode, where it tracks the speaker but does not actively follow.
/// </summary>
Background,
/// <summary>
/// Presenter Track is set to persistent mode, where it maintains a fixed position or focus on the speaker.
/// </summary>
Persistent
}
/// <summary>
/// Describes the Presenter Track controls for a Cisco codec.
/// </summary>
public interface IPresenterTrack : IKeyed
{
/// <summary>
///
/// </summary>
bool PresenterTrackAvailability { get; }
/// <summary>
/// Feedback indicating whether Presenter Track is available.
/// </summary>
BoolFeedback PresenterTrackAvailableFeedback { get; }
/// <summary>
/// Feedback indicating the current status of Presenter Track is off
/// </summary>
BoolFeedback PresenterTrackStatusOffFeedback { get; }
/// <summary>
/// Feedback indicating the current status of Presenter Track is follow
/// </summary>
BoolFeedback PresenterTrackStatusFollowFeedback { get; }
/// <summary>
/// Feedback indicating the current status of Presenter Track is background
/// </summary>
BoolFeedback PresenterTrackStatusBackgroundFeedback { get; }
/// <summary>
/// Feedback indicating the current status of Presenter Track is persistent
/// </summary>
BoolFeedback PresenterTrackStatusPersistentFeedback { get; }
/// <summary>
/// Indicates the current status of Presenter Track.
/// </summary>
bool PresenterTrackStatus { get; }
/// <summary>
/// Turns off Presenter Track.
/// </summary>
void PresenterTrackOff();
/// <summary>
/// Turns on Presenter Track in follow mode.
/// </summary>
void PresenterTrackFollow();
/// <summary>
/// Turns on Presenter Track in background mode.
/// </summary>
void PresenterTrackBackground();
/// <summary>
/// Turns on Presenter Track in persistent mode.
/// </summary>
void PresenterTrackPersistent();
}
}

View File

@@ -1,40 +0,0 @@
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Essentials.Devices.Common.Codec.Cisco
{
/// <summary>
/// Describes the available tracking modes for a Cisco codec
/// </summary>
public interface ISpeakerTrack : IKeyed
{
/// <summary>
/// Indicates whether Speaker Track is available on the codec.
/// </summary>
bool SpeakerTrackAvailability { get; }
/// <summary>
///
/// </summary>
BoolFeedback SpeakerTrackAvailableFeedback { get; }
/// <summary>
/// Feedback indicating the current status of Speaker Track is off
/// </summary>
bool SpeakerTrackStatus { get; }
/// <summary>
/// Turns Speaker Track off
/// </summary>
void SpeakerTrackOff();
/// <summary>
/// Turns Speaker Track on
/// </summary>
void SpeakerTrackOn();
}
}

View File

@@ -18,13 +18,9 @@ namespace PepperDash.Essentials.Devices.Common.DSP
public Dictionary<string, DspControlPoint> SwitcherControlPoints { get; private set; }
public DspBase(string key, string name) :
base(key, name)
{
LevelControlPoints = new Dictionary<string, IBasicVolumeWithFeedback>();
DialerControlPoints = new Dictionary<string, DspControlPoint>();
SwitcherControlPoints = new Dictionary<string, DspControlPoint>();
public DspBase(string key, string name) :
base(key, name)
{
}

View File

@@ -12,45 +12,20 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
/// </summary>
public interface IHasCodecRoomPresets
{
/// <summary>
/// Event that is raised when the list of room presets has changed.
/// </summary>
event EventHandler<EventArgs> CodecRoomPresetsListHasChanged;
/// <summary>
/// List of near end presets that can be recalled.
/// </summary>
List<CodecRoomPreset> NearEndPresets { get; }
/// <summary>
/// List of far end presets that can be recalled.
/// </summary>
List<CodecRoomPreset> FarEndRoomPresets { get; }
/// <summary>
/// Selects a near end preset by its ID.
/// </summary>
/// <param name="preset"></param>
void CodecRoomPresetSelect(int preset);
/// <summary>
/// Stores a near end preset with the given ID and description.
/// </summary>
/// <param name="preset"></param>
/// <param name="description"></param>
void CodecRoomPresetStore(int preset, string description);
void CodecRoomPresetStore(int preset, string description);
/// <summary>
/// Selects a far end preset by its ID. This is typically used to recall a preset that has been defined on the far end codec.
/// </summary>
/// <param name="preset"></param>
void SelectFarEndPreset(int preset);
}
/// <summary>
/// Static class for converting non-generic RoomPresets to generic CameraPresets.
/// </summary>
public static class RoomPresets
public static class RoomPresets
{
/// <summary>
/// Converts non-generic RoomPresets to generic CameraPresets
@@ -72,13 +47,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
/// </summary>
public class CodecRoomPreset : PresetBase
{
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="description"></param>
/// <param name="def"></param>
/// <param name="isDef"></param>
public CodecRoomPreset(int id, string description, bool def, bool isDef)
: base(id, description, def, isDef)
{

View File

@@ -3,51 +3,29 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.AppServer
{
/// <summary>
/// Represents the content of a source selection message
/// </summary>
public class SourceSelectMessageContent
{
/// <summary>
/// Gets or sets the key of the source list item to select
/// </summary>
[JsonProperty("sourceListItemKey")]
public string SourceListItemKey { get; set; }
/// <summary>
/// Gets or sets the key of the source list containing the item
/// </summary>
[JsonProperty("sourceListKey")]
public string SourceListKey { get; set; }
}
/// <summary>
/// Represents a direct routing operation between a source and destination
/// </summary>
public class DirectRoute
{
/// <summary>
/// Gets or sets the key of the source device
/// </summary>
[JsonProperty("sourceKey")]
public string SourceKey { get; set; }
/// <summary>
/// Gets or sets the key of the destination device
/// </summary>
[JsonProperty("destinationKey")]
public string DestinationKey { get; set; }
/// <summary>
/// Gets or sets the type of routing signal (Audio, Video, etc.)
/// </summary>
[JsonProperty("signalType")]
public eRoutingSignalType SignalType { get; set; }
}
/// <summary>
/// Delegate for press and hold actions with boolean state parameter
///
/// </summary>
/// <param name="b">The state of the press and hold action</param>
/// <param name="b"></param>
public delegate void PressAndHoldAction(bool b);
}

View File

@@ -1,35 +1,22 @@
using System.Linq;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.AppServer;
using PepperDash.Essentials.AppServer.Messengers;
using System.Linq;
using DisplayBase = PepperDash.Essentials.Devices.Common.Displays.DisplayBase;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger that provides mobile control interface for display devices
/// </summary>
public class DisplayBaseMessenger : MessengerBase
{
/// <summary>
/// The display device this messenger is associated with
/// </summary>
private readonly DisplayBase display;
/// <summary>
/// Initializes a new instance of the DisplayBaseMessenger class
/// </summary>
/// <param name="key">The unique key for this messenger</param>
/// <param name="messagePath">The message path for routing display control messages</param>
/// <param name="device">The display device to control</param>
public DisplayBaseMessenger(string key, string messagePath, DisplayBase device) : base(key, messagePath, device)
{
display = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();

View File

@@ -4,28 +4,15 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger that provides mobile control interface for devices with channel control functionality
/// </summary>
public class IChannelMessenger : MessengerBase
{
/// <summary>
/// The channel control device this messenger is associated with
/// </summary>
private readonly IChannel channelDevice;
/// <summary>
/// Initializes a new instance of the IChannelMessenger class
/// </summary>
/// <param name="key">The unique key for this messenger</param>
/// <param name="messagePath">The message path for routing channel control messages</param>
/// <param name="device">The device that implements channel control functionality</param>
public IChannelMessenger(string key, string messagePath, IChannel device) : base(key, messagePath, device as IKeyName)
{
channelDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();

View File

@@ -4,25 +4,14 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger for devices that implement IColor interface
/// </summary>
public class IColorMessenger : MessengerBase
{
private readonly IColor colorDevice;
/// <summary>
/// Initializes a new instance of the IColorMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="device">Device that implements IColor</param>
public IColorMessenger(string key, string messagePath, IColor device) : base(key, messagePath, device as IKeyName)
{
colorDevice = device as IColor;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();

View File

@@ -4,28 +4,15 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger that provides mobile control interface for devices with directional pad functionality
/// </summary>
public class IDPadMessenger : MessengerBase
{
/// <summary>
/// The directional pad device this messenger is associated with
/// </summary>
private readonly IDPad dpadDevice;
/// <summary>
/// Initializes a new instance of the IDPadMessenger class
/// </summary>
/// <param name="key">The unique key for this messenger</param>
/// <param name="messagePath">The message path for routing directional pad messages</param>
/// <param name="device">The device that implements directional pad functionality</param>
public IDPadMessenger(string key, string messagePath, IDPad device) : base(key, messagePath, device as IKeyName)
{
dpadDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();

View File

@@ -4,25 +4,14 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger for devices that implement IDvr interface
/// </summary>
public class IDvrMessenger : MessengerBase
{
private readonly IDvr dvrDevice;
/// <summary>
/// Initializes a new instance of the IDvrMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="device">Device that implements IDvr</param>
public IDvrMessenger(string key, string messagePath, IDvr device) : base(key, messagePath, device as IKeyName)
{
dvrDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();

View File

@@ -4,28 +4,14 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger that provides mobile control interface for devices with power control functionality
/// </summary>
public class IHasPowerMessenger : MessengerBase
{
/// <summary>
/// The power control device this messenger is associated with
/// </summary>
private readonly IHasPowerControl powerDevice;
/// <summary>
/// Initializes a new instance of the IHasPowerMessenger class
/// </summary>
/// <param name="key">The unique key for this messenger</param>
/// <param name="messagePath">The message path for routing power control messages</param>
/// <param name="device">The device that implements power control functionality</param>
public IHasPowerMessenger(string key, string messagePath, IHasPowerControl device) : base(key, messagePath, device as IKeyName)
{
powerDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();

View File

@@ -4,28 +4,14 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger that provides mobile control interface for devices with numeric keypad functionality
/// </summary>
public class INumericKeypadMessenger : MessengerBase
{
/// <summary>
/// The numeric keypad device this messenger is associated with
/// </summary>
private readonly INumericKeypad keypadDevice;
/// <summary>
/// Initializes a new instance of the INumericKeypadMessenger class
/// </summary>
/// <param name="key">The unique key for this messenger</param>
/// <param name="messagePath">The message path for routing numeric keypad messages</param>
/// <param name="device">The device that implements numeric keypad functionality</param>
public INumericKeypadMessenger(string key, string messagePath, INumericKeypad device) : base(key, messagePath, device as IKeyName)
{
keypadDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();

View File

@@ -4,25 +4,14 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger for devices that implement ISetTopBoxControls interface
/// </summary>
public class ISetTopBoxControlsMessenger : MessengerBase
{
private readonly ISetTopBoxControls stbDevice;
/// <summary>
/// Initializes a new instance of the ISetTopBoxControlsMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="device">Device that implements ISetTopBoxControls</param>
public ISetTopBoxControlsMessenger(string key, string messagePath, ISetTopBoxControls device) : base(key, messagePath, device as IKeyName)
{
stbDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
@@ -43,9 +32,6 @@ namespace PepperDash.Essentials.Room.MobileControl
}
}
/// <summary>
/// State message for set top box controls
/// </summary>
public class SetTopBoxControlsState : DeviceStateMessageBase
{

View File

@@ -4,28 +4,14 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Room.MobileControl
{
/// <summary>
/// Messenger that provides mobile control interface for devices with transport control functionality
/// </summary>
public class ITransportMessenger : MessengerBase
{
/// <summary>
/// The transport control device this messenger is associated with
/// </summary>
private readonly ITransport transportDevice;
/// <summary>
/// Initializes a new instance of the ITransportMessenger class
/// </summary>
/// <param name="key">The unique key for this messenger</param>
/// <param name="messagePath">The message path for routing transport control messages</param>
/// <param name="device">The device that implements transport control functionality</param>
public ITransportMessenger(string key, string messagePath, ITransport device) : base(key, messagePath, device as IKeyName)
{
transportDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();

View File

@@ -1,8 +1,8 @@
using System;
using System.Linq;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Devices.Common.AudioCodec;
using PepperDash.Essentials.Devices.Common.Codec;
using System;
using System.Linq;
namespace PepperDash.Essentials.AppServer.Messengers
{
@@ -29,16 +29,12 @@ namespace PepperDash.Essentials.AppServer.Messengers
codec.CallStatusChange += Codec_CallStatusChange;
}
/// <summary>
/// Registers actions for handling audio codec operations.
/// Includes call control, status reporting, and audio codec management.
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendAtcFullMessageObject(id));
AddAction("/fullStatus", (id, content) => SendAtcFullMessageObject());
AddAction("/dial", (id, content) =>
{
var msg = content.ToObject<MobileControlSimpleContent<string>>();
@@ -101,7 +97,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// Helper method to build call status for vtc
/// </summary>
/// <returns></returns>
private void SendAtcFullMessageObject(string id = null)
private void SendAtcFullMessageObject()
{
var info = Codec.CodecInfo;
@@ -113,7 +109,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
phoneNumber = info.PhoneNumber
}
}), clientId: id
})
);
}
}

View File

@@ -1,15 +1,11 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.Cameras;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for camera control operations.
/// Handles camera movement, zoom, preset management, and camera status reporting.
/// </summary>
public class CameraBaseMessenger : MessengerBase
{
/// <summary>
@@ -49,15 +45,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
);
}
/// <summary>
/// Registers actions for handling camera control operations.
/// Includes camera movement, zoom, preset management, and full status reporting.
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject(id));
AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject());
if (Camera is IHasCameraPtzControl ptzCamera)
@@ -174,7 +166,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// <summary>
/// Helper method to update the full status of the camera
/// </summary>
private void SendCameraFullMessageObject(string id = null)
private void SendCameraFullMessageObject()
{
var presetList = new List<CameraPreset>();
@@ -189,7 +181,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
cameraMode = GetCameraMode(),
hasPresets = Camera is IHasCameraPresets,
presets = presetList
}), clientId: id
})
);
}

View File

@@ -1,93 +1,41 @@
using System.Timers;
using Independentsoft.Exchange;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core.DeviceInfo;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Facilitates communication of device information by providing mechanisms for status updates and device
/// information reporting.
/// </summary>
/// <remarks>The <see cref="DeviceInfoMessenger"/> class integrates with an <see
/// cref="IDeviceInfoProvider"/> to manage device-specific information. It uses a debounce timer to limit the
/// frequency of updates, ensuring efficient communication. The timer is initialized with a 1-second interval and
/// is disabled by default. This class also subscribes to device information change events and provides actions for
/// reporting full device status and triggering updates.</remarks>
public class DeviceInfoMessenger : MessengerBase
{
private readonly IDeviceInfoProvider _deviceInfoProvider;
private readonly Timer debounceTimer;
/// <summary>
/// Initializes a new instance of the <see cref="DeviceInfoMessenger"/> class, which facilitates communication
/// of device information.
/// </summary>
/// <remarks>The messenger uses a debounce timer to limit the frequency of certain operations. The
/// timer is initialized with a 1-second interval and is disabled by default.</remarks>
/// <param name="key">A unique identifier for the messenger instance.</param>
/// <param name="messagePath">The path used for sending and receiving messages.</param>
/// <param name="device">An implementation of <see cref="IDeviceInfoProvider"/> that provides device-specific information.</param>
public DeviceInfoMessenger(string key, string messagePath, IDeviceInfoProvider device) : base(key, messagePath, device as Device)
{
_deviceInfoProvider = device;
debounceTimer = new Timer(1000)
{
Enabled = false,
AutoReset = false
};
debounceTimer.Elapsed += DebounceTimer_Elapsed;
}
private void DebounceTimer_Elapsed(object sender, ElapsedEventArgs e)
{
PostStatusMessage(JToken.FromObject(new
{
deviceInfo = _deviceInfoProvider.DeviceInfo
}));
}
/// <summary>
/// Registers actions and event handlers for device information updates and status reporting.
/// </summary>
/// <remarks>This method sets up actions for handling device status updates and reporting full
/// device status. It also subscribes to the <see cref="IDeviceInfoProvider.DeviceInfoChanged"/> event to
/// trigger debounced updates when the device information changes.</remarks>
protected override void RegisterActions()
{
base.RegisterActions();
_deviceInfoProvider.DeviceInfoChanged += (o, a) =>
{
debounceTimer.Stop();
debounceTimer.Start();
PostStatusMessage(JToken.FromObject(new
{
deviceInfo = a.DeviceInfo
}));
};
AddAction("/fullStatus", (id, context) => PostStatusMessage(new DeviceInfoStateMessage
{
DeviceInfo = _deviceInfoProvider.DeviceInfo
}, id));
}));
AddAction("/update", (id, context) => _deviceInfoProvider.UpdateDeviceInfo());
}
}
/// <summary>
/// Represents a message containing the state information of a device, including detailed device information.
/// </summary>
/// <remarks>This class is used to encapsulate the state of a device along with its associated
/// information. It extends <see cref="DeviceStateMessageBase"/> to provide additional details about the
/// device.</remarks>
public class DeviceInfoStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the device information.
/// </summary>
[JsonProperty("deviceInfo")]
public DeviceInfo DeviceInfo { get; set; }
}

View File

@@ -1,40 +1,30 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.Presets;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for device preset management operations.
/// Handles preset selection, recall, and preset list management.
/// </summary>
public class DevicePresetsModelMessenger : MessengerBase
{
private readonly ITvPresetsProvider _presetsDevice;
/// <summary>
/// Initializes a new instance of the <see cref="DevicePresetsModelMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="messagePath">The message path for preset control messages.</param>
/// <param name="presetsDevice">The device that provides preset functionality.</param>
public DevicePresetsModelMessenger(string key, string messagePath, ITvPresetsProvider presetsDevice)
: base(key, messagePath, presetsDevice as Device)
{
_presetsDevice = presetsDevice;
}
private void SendPresets(string id = null)
private void SendPresets()
{
PostStatusMessage(new PresetStateMessage
{
Favorites = _presetsDevice.TvPresets.PresetsList
}, id);
});
}
private void RecallPreset(ISetTopBoxNumericKeypad device, string channel)
@@ -50,10 +40,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
#region Overrides of MessengerBase
/// <summary>
/// Registers actions for handling device preset operations.
/// Includes preset selection, recall, and full status reporting.
/// </summary>
protected override void RegisterActions()
{
@@ -62,7 +48,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
this.LogInformation("getting full status for client {id}", id);
try
{
SendPresets(id);
SendPresets();
}
catch (Exception ex)
{
@@ -97,32 +83,17 @@ namespace PepperDash.Essentials.AppServer.Messengers
#endregion
}
/// <summary>
/// Represents a preset channel message for device preset operations.
/// </summary>
public class PresetChannelMessage
{
/// <summary>
/// Gets or sets the preset channel information.
/// </summary>
[JsonProperty("preset")]
public PresetChannel Preset;
/// <summary>
/// Gets or sets the device key associated with the preset.
/// </summary>
[JsonProperty("deviceKey")]
public string DeviceKey;
}
/// <summary>
/// Represents a preset state message containing favorite presets.
/// </summary>
public class PresetStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the list of favorite preset channels.
/// </summary>
[JsonProperty("favorites", NullValueHandling = NullValueHandling.Ignore)]
public List<PresetChannel> Favorites { get; set; } = new List<PresetChannel>();
}

View File

@@ -1,33 +1,23 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for device volume control operations.
/// Handles volume level adjustment, mute control, and volume status reporting.
/// </summary>
public class DeviceVolumeMessenger : MessengerBase
{
private readonly IBasicVolumeWithFeedback _localDevice;
/// <summary>
/// Initializes a new instance of the <see cref="DeviceVolumeMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="messagePath">The message path for volume control messages.</param>
/// <param name="device">The device that provides volume control functionality.</param>
public DeviceVolumeMessenger(string key, string messagePath, IBasicVolumeWithFeedback device)
: base(key, messagePath, device as IKeyName)
{
_localDevice = device;
}
private void SendStatus(string id = null)
private void SendStatus()
{
try
{
@@ -47,7 +37,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
messageObj.Volume.Units = volumeAdvanced.Units;
}
PostStatusMessage(messageObj, id);
PostStatusMessage(messageObj);
}
catch (Exception ex)
{
@@ -58,13 +48,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
#region Overrides of MessengerBase
/// <summary>
/// Registers actions for handling volume control operations.
/// Includes volume level adjustment, mute control, and full status reporting.
/// </summary>
protected override void RegisterActions()
{
AddAction("/fullStatus", (id, content) => SendStatus(id));
AddAction("/fullStatus", (id, content) => SendStatus());
AddAction("/level", (id, content) =>
{
@@ -156,56 +142,29 @@ namespace PepperDash.Essentials.AppServer.Messengers
#endregion
}
/// <summary>
/// Represents a volume state message containing volume information.
/// </summary>
public class VolumeStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the volume information.
/// </summary>
[JsonProperty("volume", NullValueHandling = NullValueHandling.Ignore)]
public Volume Volume { get; set; }
}
/// <summary>
/// Represents volume control information including level, mute status, and units.
/// </summary>
public class Volume
{
/// <summary>
/// Gets or sets the volume level.
/// </summary>
[JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)]
public int? Level { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the device has mute capability.
/// </summary>
[JsonProperty("hasMute", NullValueHandling = NullValueHandling.Ignore)]
public bool? HasMute { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the device is currently muted.
/// </summary>
[JsonProperty("muted", NullValueHandling = NullValueHandling.Ignore)]
public bool? Muted { get; set; }
/// <summary>
/// Gets or sets the volume label for display purposes.
/// </summary>
[JsonProperty("label", NullValueHandling = NullValueHandling.Ignore)]
public string Label { get; set; }
/// <summary>
/// Gets or sets the raw volume value as a string.
/// </summary>
[JsonProperty("rawValue", NullValueHandling = NullValueHandling.Ignore)]
public string RawValue { get; set; }
/// <summary>
/// Gets or sets the volume level units.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
[JsonProperty("units", NullValueHandling = NullValueHandling.Ignore)]
public eVolumeLevelUnits? Units { get; set; }

View File

@@ -2,34 +2,24 @@
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Generic messenger for basic device communication
/// </summary>
public class GenericMessenger : MessengerBase
{
/// <summary>
/// Initializes a new instance of the GenericMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="device">Device to communicate with</param>
/// <param name="messagePath">Path for message routing</param>
public GenericMessenger(string key, EssentialsDevice device, string messagePath) : base(key, messagePath, device)
{
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
var state = new DeviceStateMessageBase();
PostStatusMessage(state, id);
PostStatusMessage(state);
}
}
}

View File

@@ -6,29 +6,15 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for communication monitoring operations.
/// Handles communication status reporting and monitoring feedback.
/// </summary>
public class ICommunicationMonitorMessenger : MessengerBase
{
private readonly ICommunicationMonitor _communicationMonitor;
/// <summary>
/// Initializes a new instance of the <see cref="ICommunicationMonitorMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="messagePath">The message path for communication monitor messages.</param>
/// <param name="device">The device that provides communication monitoring functionality.</param>
public ICommunicationMonitorMessenger(string key, string messagePath, ICommunicationMonitor device) : base(key, messagePath, device as IKeyName)
{
_communicationMonitor = device;
}
/// <summary>
/// Registers actions for handling communication monitoring operations.
/// Includes full status reporting for communication monitoring data.
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
@@ -42,7 +28,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
IsOnline = _communicationMonitor.CommunicationMonitor.IsOnline,
Status = _communicationMonitor.CommunicationMonitor.Status
}
}, id);
});
});
_communicationMonitor.CommunicationMonitor.StatusChange += (sender, args) =>
@@ -64,17 +50,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// </summary>
public class CommunicationMonitorState : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the communication monitor properties.
/// </summary>
[JsonProperty("commMonitor", NullValueHandling = NullValueHandling.Ignore)]
public CommunicationMonitorProps CommunicationMonitor { get; set; }
}
/// <summary>
/// Represents the properties of a communication monitor.
/// </summary>
public class CommunicationMonitorProps
{ /// <summary>
/// For devices that implement ICommunicationMonitor, reports the online status of the device

View File

@@ -1,34 +1,20 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for DSP preset management operations.
/// Handles DSP preset selection, recall, and preset list management.
/// </summary>
public class IDspPresetsMessenger : MessengerBase
{
private readonly IDspPresets device;
/// <summary>
/// Initializes a new instance of the <see cref="IDspPresetsMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="messagePath">The message path for DSP preset control messages.</param>
/// <param name="device">The device that provides DSP preset functionality.</param>
public IDspPresetsMessenger(string key, string messagePath, IDspPresets device)
: base(key, messagePath, device as IKeyName)
{
this.device = device;
}
/// <summary>
/// Registers actions for handling DSP preset operations.
/// Includes preset selection, recall, and full status reporting.
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
@@ -40,7 +26,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
Presets = device.Presets
};
PostStatusMessage(message, id);
PostStatusMessage(message);
});
AddAction("/recallPreset", (id, content) =>
@@ -56,14 +42,8 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// Represents a DSP presets state message containing available presets.
/// </summary>
public class IHasDspPresetsStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the dictionary of available DSP presets.
/// </summary>
[JsonProperty("presets")]
public Dictionary<string, IKeyName> Presets { get; set; }
}

View File

@@ -1,52 +1,26 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging functionality for managing room combination scenarios and partition states in an <see
/// cref="IEssentialsRoomCombiner"/> instance. Enables external systems to interact with the room combiner via
/// predefined actions and status updates.
/// </summary>
/// <remarks>This class facilitates communication with an <see cref="IEssentialsRoomCombiner"/> by
/// exposing actions for toggling modes, managing partitions, and setting room combination scenarios. It also
/// listens for feedback changes and broadcasts status updates to connected systems. Typical usage involves
/// registering actions for external commands and handling feedback events to synchronize state changes.</remarks>
public class IEssentialsRoomCombinerMessenger : MessengerBase
{
private readonly IEssentialsRoomCombiner _roomCombiner;
/// <summary>
/// Initializes a new instance of the <see cref="IEssentialsRoomCombinerMessenger"/> class, which facilitates
/// messaging for an <see cref="IEssentialsRoomCombiner"/> instance.
/// </summary>
/// <remarks>This class is designed to enable communication and interaction with an <see
/// cref="IEssentialsRoomCombiner"/> through the specified messaging path. Ensure that the <paramref
/// name="roomCombiner"/> parameter is not null when creating an instance.</remarks>
/// <param name="key">The unique key identifying this messenger instance.</param>
/// <param name="messagePath">The path used for messaging operations.</param>
/// <param name="roomCombiner">The <see cref="IEssentialsRoomCombiner"/> instance associated with this messenger.</param>
public IEssentialsRoomCombinerMessenger(string key, string messagePath, IEssentialsRoomCombiner roomCombiner)
: base(key, messagePath, roomCombiner as IKeyName)
{
_roomCombiner = roomCombiner;
}
/// <summary>
/// Registers actions and event handlers for managing room combination scenarios and partition states.
/// </summary>
/// <remarks>This method sets up various actions that can be triggered via specific endpoints,
/// such as toggling modes, setting room combination scenarios, and managing partition states. It also
/// subscribes to feedback events to update the status when changes occur in room combination scenarios or
/// partition states.</remarks>
protected override void RegisterActions()
{
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
AddAction("/setAutoMode", (id, content) =>
{
@@ -120,7 +94,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
try
{
@@ -133,7 +107,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
var message = new IEssentialsRoomCombinerStateMessage
{
DisableAutoMode = _roomCombiner.DisableAutoMode,
IsInAutoMode = _roomCombiner.IsInAutoMode,
CurrentScenario = _roomCombiner.CurrentScenario,
Rooms = rooms,
@@ -141,7 +114,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
Partitions = _roomCombiner.Partitions
};
PostStatusMessage(message, id);
PostStatusMessage(message);
}
catch (Exception e)
{
@@ -159,48 +132,20 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// Represents the state message for a room combiner system, providing information about the current configuration,
/// operational mode, and associated rooms, partitions, and scenarios.
/// </summary>
/// <remarks>This class is used to encapsulate the state of a room combiner system, including its current
/// mode of operation, active room combination scenario, and the list of rooms and partitions involved. It is
/// typically serialized and transmitted to communicate the state of the system.</remarks>
public class IEssentialsRoomCombinerStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets a value indicating whether automatic mode is disabled.
/// </summary>
[JsonProperty("disableAutoMode", NullValueHandling = NullValueHandling.Ignore)]
public bool DisableAutoMode { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the system is operating in automatic mode.
/// </summary>
[JsonProperty("isInAutoMode", NullValueHandling = NullValueHandling.Ignore)]
public bool IsInAutoMode { get; set; }
/// <summary>
/// Gets or sets the current room combination scenario.
/// </summary>
[JsonProperty("currentScenario", NullValueHandling = NullValueHandling.Ignore)]
public IRoomCombinationScenario CurrentScenario { get; set; }
/// <summary>
/// Gets or sets the collection of rooms associated with the entity.
/// </summary>
[JsonProperty("rooms", NullValueHandling = NullValueHandling.Ignore)]
public List<IKeyName> Rooms { get; set; }
/// <summary>
/// Gets or sets the collection of room combination scenarios.
/// </summary>
[JsonProperty("roomCombinationScenarios", NullValueHandling = NullValueHandling.Ignore)]
public List<IRoomCombinationScenario> RoomCombinationScenarios { get; set; }
/// <summary>
/// Gets or sets the collection of partition controllers.
/// </summary>
[JsonProperty("partitions", NullValueHandling = NullValueHandling.Ignore)]
public List<IPartitionController> Partitions { get; set; }
}

View File

@@ -5,25 +5,14 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for devices that implement IHasCurrentSourceInfoChange interface
/// </summary>
public class IHasCurrentSourceInfoMessenger : MessengerBase
{
private readonly IHasCurrentSourceInfoChange sourceDevice;
/// <summary>
/// Initializes a new instance of the IHasCurrentSourceInfoMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="device">Device that implements IHasCurrentSourceInfoChange</param>
public IHasCurrentSourceInfoMessenger(string key, string messagePath, IHasCurrentSourceInfoChange device) : base(key, messagePath, device as IKeyName)
{
sourceDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
@@ -36,7 +25,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
CurrentSource = sourceDevice.CurrentSourceInfo
};
PostStatusMessage(message, id);
PostStatusMessage(message);
});
sourceDevice.CurrentSourceChange += (sender, e) =>
@@ -57,20 +46,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// State message for current source information
/// </summary>
public class CurrentSourceStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the current source key
/// </summary>
[JsonProperty("currentSourceKey", NullValueHandling = NullValueHandling.Ignore)]
public string CurrentSourceKey { get; set; }
/// <summary>
/// Gets or sets the current source information
/// </summary>
[JsonProperty("currentSource")]
public SourceListItem CurrentSource { get; set; }
}

View File

@@ -1,40 +1,35 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for devices that implement IHasInputs interface
/// </summary>
/// <typeparam name="TKey">Type of the key used for inputs</typeparam>
public class IHasInputsMessenger<TKey> : MessengerBase
{
private readonly IHasInputs<TKey> itemDevice;
{
private readonly IHasInputs<TKey> itemDevice;
/// <summary>
/// Constructs a messenger for a device that implements IHasInputs<typeparamref name="TKey"/>
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="device">Device that implements IHasInputs</param>
/// <param name="key"></param>
/// <param name="messagePath"></param>
/// <param name="device"></param>
public IHasInputsMessenger(string key, string messagePath, IHasInputs<TKey> device) : base(key, messagePath, device)
{
itemDevice = device;
itemDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, context) =>
{
SendFullStatus(id);
SendFullStatus();
});
itemDevice.Inputs.ItemsUpdated += (sender, args) =>
@@ -64,7 +59,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
try
{
@@ -79,7 +74,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
};
PostStatusMessage(stateObject, id);
PostStatusMessage(stateObject);
}
catch (Exception e)
{
@@ -88,34 +83,17 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// State message for devices with inputs
/// </summary>
/// <typeparam name="TKey">Type of the key used for inputs</typeparam>
public class IHasInputsStateMessage<TKey> : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the inputs
/// </summary>
[JsonProperty("inputs")]
public Inputs<TKey> Inputs { get; set; }
}
/// <summary>
/// Represents a collection of inputs
/// </summary>
/// <typeparam name="TKey">Type of the key used for inputs</typeparam>
public class Inputs<TKey>
{
/// <summary>
/// Gets or sets the items dictionary
/// </summary>
[JsonProperty("items")]
public Dictionary<TKey, ISelectableItem> Items { get; set; }
/// <summary>
/// Gets or sets the current item
/// </summary>
[JsonProperty("currentItem")]
public TKey CurrentItem { get; set; }
}

View File

@@ -5,48 +5,31 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for power control operations with feedback.
/// Handles power on/off commands and power state feedback reporting.
/// </summary>
public class IHasPowerControlWithFeedbackMessenger : MessengerBase
{
private readonly IHasPowerControlWithFeedback _powerControl;
/// <summary>
/// Initializes a new instance of the <see cref="IHasPowerControlWithFeedbackMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="messagePath">The message path for power control messages.</param>
/// <param name="powerControl">The device that provides power control functionality.</param>
public IHasPowerControlWithFeedbackMessenger(string key, string messagePath, IHasPowerControlWithFeedback powerControl)
: base(key, messagePath, powerControl as IKeyName)
{
_powerControl = powerControl;
}
/// <summary>
/// Sends the full power control status to connected clients.
/// </summary>
public void SendFullStatus(string id = null)
public void SendFullStatus()
{
var messageObj = new PowerControlWithFeedbackStateMessage
{
PowerState = _powerControl.PowerIsOnFeedback.BoolValue
};
PostStatusMessage(messageObj, id);
PostStatusMessage(messageObj);
}
/// <summary>
/// Registers actions for handling power control operations.
/// Includes power on, power off, power toggle, and full status reporting.
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
_powerControl.PowerIsOnFeedback.OutputChange += PowerIsOnFeedback_OutputChange; ;
}
@@ -61,14 +44,8 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// Represents a power control state message containing power state information.
/// </summary>
public class PowerControlWithFeedbackStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the power state of the device.
/// </summary>
[JsonProperty("powerState", NullValueHandling = NullValueHandling.Ignore)]
public bool? PowerState { get; set; }
}

View File

@@ -1,28 +1,16 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Devices.Common.Codec;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for devices that implement IHasScheduleAwareness interface
/// </summary>
public class IHasScheduleAwarenessMessenger : MessengerBase
{
/// <summary>
/// Gets the schedule source device
/// </summary>
public IHasScheduleAwareness ScheduleSource { get; private set; }
/// <summary>
/// Initializes a new instance of the IHasScheduleAwarenessMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="scheduleSource">Device that implements IHasScheduleAwareness</param>
/// <param name="messagePath">Path for message routing</param>
public IHasScheduleAwarenessMessenger(string key, IHasScheduleAwareness scheduleSource, string messagePath)
: base(key, messagePath, scheduleSource as IKeyName)
{
@@ -31,10 +19,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
ScheduleSource.CodecSchedule.MeetingEventChange += new EventHandler<MeetingEventArgs>(CodecSchedule_MeetingEventChange);
}
/// <inheritdoc />
protected override void RegisterActions()
{
AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject(id));
AddAction("/schedule/fullStatus", (id, content) => SendFullScheduleObject());
}
private void CodecSchedule_MeetingEventChange(object sender, MeetingEventArgs e)
@@ -58,60 +45,36 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// <summary>
/// Helper method to send the full schedule data
/// </summary>
private void SendFullScheduleObject(string id = null)
private void SendFullScheduleObject()
{
PostStatusMessage(new FullScheduleMessage
{
Meetings = ScheduleSource.CodecSchedule.Meetings,
MeetingWarningMinutes = ScheduleSource.CodecSchedule.MeetingWarningMinutes
}, id);
});
}
}
/// <summary>
/// Full schedule message containing meetings and warning minutes
/// </summary>
public class FullScheduleMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the list of meetings
/// </summary>
[JsonProperty("meetings", NullValueHandling = NullValueHandling.Ignore)]
public List<Meeting> Meetings { get; set; }
/// <summary>
/// Gets or sets the meeting warning minutes
/// </summary>
[JsonProperty("meetingWarningMinutes", NullValueHandling = NullValueHandling.Ignore)]
public int MeetingWarningMinutes { get; set; }
}
/// <summary>
/// Message containing meeting change information
/// </summary>
public class MeetingChangeMessage
{
/// <summary>
/// Gets or sets the meeting change details
/// </summary>
[JsonProperty("meetingChange", NullValueHandling = NullValueHandling.Ignore)]
public MeetingChange MeetingChange { get; set; }
}
/// <summary>
/// Represents a meeting change with type and meeting details
/// </summary>
public class MeetingChange
{
/// <summary>
/// Gets or sets the change type
/// </summary>
[JsonProperty("changeType", NullValueHandling = NullValueHandling.Ignore)]
public string ChangeType { get; set; }
/// <summary>
/// Gets or sets the meeting details
/// </summary>
[JsonProperty("meeting", NullValueHandling = NullValueHandling.Ignore)]
public Meeting Meeting { get; set; }
}

View File

@@ -1,7 +1,7 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using System;
namespace PepperDash.Essentials.AppServer.Messengers
{
@@ -19,19 +19,19 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
device.HumidityFeedback.OutputChange += new EventHandler<Core.FeedbackEventArgs>((o, a) => SendFullStatus());
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
var state = new IHumiditySensorStateMessage
{
Humidity = string.Format("{0}%", device.HumidityFeedback.UShortValue)
};
PostStatusMessage(state, id);
PostStatusMessage(state);
}
}

View File

@@ -1,31 +1,20 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using System.Collections.Generic;
using System.Linq;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for devices that implement ILevelControls interface
/// </summary>
public class ILevelControlsMessenger : MessengerBase
{
private ILevelControls levelControlsDevice;
/// <summary>
/// Initializes a new instance of the ILevelControlsMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="device">Device that implements ILevelControls</param>
public ILevelControlsMessenger(string key, string messagePath, ILevelControls device) : base(key, messagePath, device as IKeyName)
{
levelControlsDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
@@ -37,7 +26,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
Levels = levelControlsDevice.LevelControlPoints.ToDictionary(kv => kv.Key, kv => new Volume { Level = kv.Value.VolumeLevelFeedback.IntValue, Muted = kv.Value.MuteFeedback.BoolValue })
};
PostStatusMessage(message, id);
PostStatusMessage(message);
});
foreach (var levelControl in levelControlsDevice.LevelControlPoints)
@@ -85,32 +74,17 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// State message for level controls
/// </summary>
public class LevelControlStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the level controls
/// </summary>
[JsonProperty("levelControls")]
public Dictionary<string, Volume> Levels { get; set; }
}
/// <summary>
/// Request message for level control operations
/// </summary>
public class LevelControlRequestMessage
{
/// <summary>
/// Gets or sets the control key
/// </summary>
[JsonProperty("key")]
public string Key { get; set; }
/// <summary>
/// Gets or sets the level
/// </summary>
[JsonProperty("level", NullValueHandling = NullValueHandling.Ignore)]
public ushort? Level { get; set; }
}

View File

@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PepperDash.Essentials.AppServer.Messengers
{
@@ -16,19 +16,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
public class IMatrixRoutingMessenger : MessengerBase
{
private readonly IMatrixRouting matrixDevice;
/// <summary>
/// Initializes a new instance of the IMatrixRoutingMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="device">Device that implements IMatrixRouting</param>
public IMatrixRoutingMessenger(string key, string messagePath, IMatrixRouting device) : base(key, messagePath, device as IKeyName)
{
matrixDevice = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
@@ -45,7 +37,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
};
PostStatusMessage(message, id);
PostStatusMessage(message);
}
catch (Exception e)
{
@@ -90,159 +82,86 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// State message for matrix routing information
/// </summary>
public class MatrixStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the outputs dictionary
/// </summary>
[JsonProperty("outputs")]
public Dictionary<string, RoutingOutput> Outputs;
/// <summary>
/// Gets or sets the inputs dictionary
/// </summary>
[JsonProperty("inputs")]
public Dictionary<string, RoutingInput> Inputs;
}
/// <summary>
/// Represents a routing input slot
/// </summary>
public class RoutingInput
{
private IRoutingInputSlot _input;
/// <summary>
/// Gets the transmit device key
/// </summary>
[JsonProperty("txDeviceKey", NullValueHandling = NullValueHandling.Ignore)]
public string TxDeviceKey => _input?.TxDeviceKey;
/// <summary>
/// Gets the slot number
/// </summary>
[JsonProperty("slotNumber", NullValueHandling = NullValueHandling.Ignore)]
public int? SlotNumber => _input?.SlotNumber;
/// <summary>
/// Gets the supported signal types
/// </summary>
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
[JsonProperty("supportedSignalTypes", NullValueHandling = NullValueHandling.Ignore)]
public eRoutingSignalType? SupportedSignalTypes => _input?.SupportedSignalTypes;
/// <summary>
/// Gets the name
/// </summary>
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name => _input?.Name;
/// <summary>
/// Gets the online status
/// </summary>
[JsonProperty("isOnline", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsOnline => _input?.IsOnline.BoolValue;
/// <summary>
/// Gets the video sync detected status
/// </summary>
[JsonProperty("videoSyncDetected", NullValueHandling = NullValueHandling.Ignore)]
public bool? VideoSyncDetected => _input?.VideoSyncDetected;
/// <summary>
/// Gets the key
/// </summary>
[JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)]
public string Key => _input?.Key;
/// <summary>
/// Initializes a new instance of the RoutingInput class
/// </summary>
/// <param name="input">The input slot</param>
public RoutingInput(IRoutingInputSlot input)
{
_input = input;
}
}
/// <summary>
/// Represents a routing output slot
/// </summary>
public class RoutingOutput
{
private IRoutingOutputSlot _output;
/// <summary>
/// Initializes a new instance of the RoutingOutput class
/// </summary>
/// <param name="output">The output slot</param>
public RoutingOutput(IRoutingOutputSlot output)
{
_output = output;
}
/// <summary>
/// Gets the receive device key
/// </summary>
[JsonProperty("rxDeviceKey")]
public string RxDeviceKey => _output.RxDeviceKey;
/// <summary>
/// Gets the current routes
/// </summary>
[JsonProperty("currentRoutes")]
public Dictionary<string, RoutingInput> CurrentRoutes => _output.CurrentRoutes.ToDictionary(kvp => kvp.Key.ToString(), kvp => new RoutingInput(kvp.Value));
/// <summary>
/// Gets the slot number
/// </summary>
[JsonProperty("slotNumber")]
public int SlotNumber => _output.SlotNumber;
/// <summary>
/// Gets the supported signal types
/// </summary>
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
[JsonProperty("supportedSignalTypes")]
public eRoutingSignalType SupportedSignalTypes => _output.SupportedSignalTypes;
/// <summary>
/// Gets the name
/// </summary>
[JsonProperty("name")]
public string Name => _output.Name;
/// <summary>
/// Gets the key
/// </summary>
[JsonProperty("key")]
public string Key => _output.Key;
}
/// <summary>
/// Request for matrix routing
/// </summary>
public class MatrixRouteRequest
{
/// <summary>
/// Gets or sets the output key
/// </summary>
[JsonProperty("outputKey")]
public string OutputKey { get; set; }
/// <summary>
/// Gets or sets the input key
/// </summary>
[JsonProperty("inputKey")]
public string InputKey { get; set; }
/// <summary>
/// Gets or sets the route type
/// </summary>
[JsonProperty("routeType")]
public eRoutingSignalType RouteType { get; set; }
}

View File

@@ -1,9 +1,9 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using System;
namespace PepperDash.Essentials.AppServer.Messengers
{
@@ -21,7 +21,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
AddAction("/raise", (id, content) =>
{
@@ -50,7 +50,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
PostStatusMessage(JToken.FromObject(state));
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
var state = new ScreenLiftStateMessage
{
@@ -59,7 +59,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
DisplayDeviceKey = device.DisplayDeviceKey
};
PostStatusMessage(state, id);
PostStatusMessage(state);
}
}

View File

@@ -1,15 +1,12 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
using System;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for routing actions
/// </summary>
public class RunRouteActionMessenger : MessengerBase
{
/// <summary>
@@ -17,13 +14,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// </summary>
public IRunRouteAction RoutingDevice { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="RunRouteActionMessenger"/> class.
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="routingDevice">Device that implements IRunRouteAction</param>
/// <param name="messagePath">Path for message routing</param>
/// <exception cref="ArgumentNullException">Thrown when routingDevice is null</exception>
public RunRouteActionMessenger(string key, IRunRouteAction routingDevice, string messagePath)
: base(key, messagePath, routingDevice as IKeyName)
{
@@ -41,10 +31,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
SendRoutingFullMessageObject();
}
/// <inheritdoc />
protected override void RegisterActions()
{
AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject(id));
AddAction("/fullStatus", (id, content) => SendRoutingFullMessageObject());
AddAction("/source", (id, content) =>
{
@@ -70,7 +59,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// <summary>
/// Helper method to update full status of the routing device
/// </summary>
private void SendRoutingFullMessageObject(string id = null)
private void SendRoutingFullMessageObject()
{
if (RoutingDevice is IRoutingSink sinkDevice)
{
@@ -82,19 +71,13 @@ namespace PepperDash.Essentials.AppServer.Messengers
PostStatusMessage(new RoutingStateMessage
{
SelectedSourceKey = sourceKey
}, id);
});
}
}
}
/// <summary>
/// Message class for routing state
/// </summary>
public class RoutingStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the selected source key
/// </summary>
[JsonProperty("selectedSourceKey")]
public string SelectedSourceKey { get; set; }
}

View File

@@ -1,18 +1,14 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for devices that implement ISelectableItems interface
/// </summary>
/// <typeparam name="TKey">Type of the key used for selectable items</typeparam>
public class ISelectableItemsMessenger<TKey> : MessengerBase
{
{
private readonly ISelectableItems<TKey> itemDevice;
private readonly string _propName;
@@ -20,24 +16,23 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// <summary>
/// Constructs a messenger for a device that implements ISelectableItems<typeparamref name="TKey"/>
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="device">Device that implements ISelectableItems</param>
/// <param name="propName">Property name for JSON serialization</param>
/// <param name="key"></param>
/// <param name="messagePath"></param>
/// <param name="device"></param>
/// <param name="propName"></param>
public ISelectableItemsMessenger(string key, string messagePath, ISelectableItems<TKey> device, string propName) : base(key, messagePath, device as IKeyName)
{
itemDevice = device;
_propName = propName;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, context) =>
{
SendFullStatus(id);
SendFullStatus();
});
itemDevice.ItemsUpdated += (sender, args) =>
@@ -67,7 +62,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
try
{
@@ -79,7 +74,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
CurrentItem = itemDevice.CurrentItem
};
PostStatusMessage(stateObject, id);
PostStatusMessage(stateObject);
}
catch (Exception e)
{
@@ -88,21 +83,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// State message for selectable items
/// </summary>
/// <typeparam name="TKey">Type of the key used for selectable items</typeparam>
public class ISelectableItemsStateMessage<TKey> : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the items dictionary
/// </summary>
[JsonProperty("items")]
public Dictionary<TKey, ISelectableItem> Items { get; set; }
/// <summary>
/// Gets or sets the current item
/// </summary>
[JsonProperty("currentItem")]
public TKey CurrentItem { get; set; }
}

View File

@@ -5,26 +5,16 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for the shutdown prompt timer
/// </summary>
public class IShutdownPromptTimerMessenger : MessengerBase
{
private readonly IShutdownPromptTimer _room;
/// <summary>
/// Initializes a new instance of the <see cref="IShutdownPromptTimerMessenger"/> class.
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="room">Room that implements IShutdownPromptTimer</param>
public IShutdownPromptTimerMessenger(string key, string messagePath, IShutdownPromptTimer room)
: base(key, messagePath, room as IKeyName)
{
_room = room;
}
/// <inheritdoc />
protected override void RegisterActions()
{
AddAction("/status", (id, content) =>
@@ -75,7 +65,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
};
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
var status = new IShutdownPromptTimerStateMessage
{
@@ -84,7 +74,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
PercentageRemaining = _room.ShutdownPromptTimer.PercentFeedback.UShortValue
};
PostStatusMessage(status, id);
PostStatusMessage(status);
}
}

View File

@@ -1,39 +1,26 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.CrestronIO;
using System;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for ISwitchedOutput devices
/// </summary>
public class ISwitchedOutputMessenger : MessengerBase
{
private readonly ISwitchedOutput device;
/// <summary>
/// Initializes a new instance of the <see cref="ISwitchedOutputMessenger"/> class.
/// This messenger provides mobile control interface for switched output devices.
/// It allows sending commands to turn the output on or off, and provides feedback on the
/// current state of the output.
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="device">Device that implements ISwitchedOutput</param>
/// <param name="messagePath">Path for message routing</param>
public ISwitchedOutputMessenger(string key, ISwitchedOutput device, string messagePath)
: base(key, messagePath, device as IKeyName)
{
this.device = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
AddAction("/on", (id, content) =>
{
@@ -52,29 +39,19 @@ namespace PepperDash.Essentials.AppServer.Messengers
device.OutputIsOnFeedback.OutputChange += new EventHandler<Core.FeedbackEventArgs>((o, a) => SendFullStatus());
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
var state = new ISwitchedOutputStateMessage
{
IsOn = device.OutputIsOnFeedback.BoolValue
};
PostStatusMessage(state, id);
PostStatusMessage(state);
}
}
/// <summary>
/// State message for ISwitchedOutput devices
/// This message contains the current state of the switched output, specifically whether it is on or off.
/// It is used to communicate the state of the output to clients that subscribe to this messenger.
/// </summary>
public class ISwitchedOutputStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets a value indicating whether the switched output is currently on.
/// This property is used to convey the current state of the output to clients.
/// A value of true indicates that the output is on, while false indicates it is off.
/// </summary>
[JsonProperty("isOn")]
public bool IsOn { get; set; }
}

View File

@@ -4,32 +4,22 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for devices that implement ITechPassword interface
/// </summary>
public class ITechPasswordMessenger : MessengerBase
{
private readonly ITechPassword _room;
/// <summary>
/// Initializes a new instance of the ITechPasswordMessenger class
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="room">Room that implements ITechPassword</param>
public ITechPasswordMessenger(string key, string messagePath, ITechPassword room)
: base(key, messagePath, room as IKeyName)
{
_room = room;
}
/// <inheritdoc />
protected override void RegisterActions()
{
AddAction("/status", (id, content) =>
{
SendFullStatus(id);
SendFullStatus();
});
AddAction("/validateTechPassword", (id, content) =>
@@ -62,56 +52,35 @@ namespace PepperDash.Essentials.AppServer.Messengers
};
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
var status = new ITechPasswordStateMessage
{
TechPasswordLength = _room.TechPasswordLength
};
PostStatusMessage(status, id);
PostStatusMessage(status);
}
}
/// <summary>
/// State message for tech password information
/// </summary>
public class ITechPasswordStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the tech password length
/// </summary>
[JsonProperty("techPasswordLength", NullValueHandling = NullValueHandling.Ignore)]
public int? TechPasswordLength { get; set; }
}
/// <summary>
/// Event message for tech password validation result
/// </summary>
public class ITechPasswordEventMessage : DeviceEventMessageBase
{
/// <summary>
/// Gets or sets whether the password is valid
/// </summary>
[JsonProperty("isValid", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsValid { get; set; }
}
/// <summary>
/// Content for setting tech password
/// </summary>
internal class SetTechPasswordContent
{
/// <summary>
/// Gets or sets the old password
/// </summary>
[JsonProperty("oldPassword")]
public string OldPassword { get; set; }
/// <summary>
/// Gets or sets the new password
/// </summary>
[JsonProperty("newPassword")]
public string NewPassword { get; set; }
}

View File

@@ -1,37 +1,25 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using System;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for temperature sensor devices
/// </summary>
public class ITemperatureSensorMessenger : MessengerBase
{
private readonly ITemperatureSensor device;
/// <summary>
/// Initializes a new instance of the ITemperatureSensorMessenger class
/// This messenger provides a mobile control interface for temperature sensor devices.
/// It allows clients to retrieve the current temperature and change the temperature format between Celsius and Fahrenheit.
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="device">Device that implements ITemperatureSensor</param>
/// <param name="messagePath">Path for message routing</param>
public ITemperatureSensorMessenger(string key, ITemperatureSensor device, string messagePath)
: base(key, messagePath, device as IKeyName)
{
this.device = device;
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
AddAction("/setTemperatureUnitsToCelcius", (id, content) =>
{
@@ -47,7 +35,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
device.TemperatureInCFeedback.OutputChange += new EventHandler<Core.FeedbackEventArgs>((o, a) => SendFullStatus());
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
// format the temperature to a string with one decimal place
var tempString = string.Format("{0}.{1}", device.TemperatureFeedback.UShortValue / 10, device.TemperatureFeedback.UShortValue % 10);
@@ -58,27 +46,15 @@ namespace PepperDash.Essentials.AppServer.Messengers
TemperatureInCelsius = device.TemperatureInCFeedback.BoolValue
};
PostStatusMessage(state, id);
PostStatusMessage(state);
}
}
/// <summary>
/// State message for temperature sensor devices
/// </summary>
public class ITemperatureSensorStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the current temperature reading from the sensor.
/// The temperature is represented as a string formatted to one decimal place.
/// For example, "22.5" for 22.5 degrees.
/// </summary>
[JsonProperty("temperature")]
public string Temperature { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the temperature is in Celsius.
/// This property is true if the temperature is in Celsius, and false if it is in Fahrenheit.
/// </summary>
[JsonProperty("temperatureInCelsius")]
public bool TemperatureInCelsius { get; set; }
}

View File

@@ -1,25 +1,15 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.Lighting;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for lighting scenes devices
/// </summary>
public class ILightingScenesMessenger : MessengerBase
{
private ILightingScenes lightingScenesDevice;
/// <summary>
/// Initializes a new instance of the <see cref="ILightingScenesMessenger"/> class.
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="device">Device that implements ILightingScenes</param>
/// <param name="messagePath">Path for message routing</param>
/// <exception cref="ArgumentNullException">Thrown when device is null</exception>
public ILightingScenesMessenger(string key, ILightingScenes device, string messagePath)
: base(key, messagePath, device as IKeyName)
{
@@ -38,12 +28,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
PostStatusMessage(state);
}
/// <inheritdoc />
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
AddAction("/selectScene", (id, content) =>
{
@@ -51,14 +40,14 @@ namespace PepperDash.Essentials.AppServer.Messengers
lightingScenesDevice.SelectScene(s);
});
if (!(lightingScenesDevice is ILightingScenesDynamic lightingScenesDynamic))
if(!(lightingScenesDevice is ILightingScenesDynamic lightingScenesDynamic))
return;
lightingScenesDynamic.LightingScenesUpdated += (s, e) => SendFullStatus();
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
var state = new LightingBaseStateMessage
{
@@ -66,7 +55,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
CurrentLightingScene = lightingScenesDevice.CurrentLightingScene
};
PostStatusMessage(state, id);
PostStatusMessage(state);
}
}

View File

@@ -1,57 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides a messaging bridge between mobile control clients and Essentials devices.
/// This abstract base class handles message routing, action registration, and status updates.
/// Provides a messaging bridge
/// </summary>
public abstract class MessengerBase : EssentialsDevice, IMobileControlMessenger
{
/// <summary>
/// The device that this messenger is associated with
/// </summary>
protected IKeyName _device;
/// <summary>
/// List of interfaces implemented by the associated device
/// </summary>
private readonly List<string> _deviceInterfaces;
/// <summary>
/// Dictionary of registered actions, keyed by path
/// </summary>
private readonly Dictionary<string, Action<string, JToken>> _actions = new Dictionary<string, Action<string, JToken>>();
/// <summary>
/// Gets the key of the associated device
/// </summary>
public string DeviceKey => _device?.Key ?? "";
/// <summary>
/// Gets the mobile control app server controller
///
/// </summary>
public IMobileControl AppServerController { get; private set; }
/// <summary>
/// Gets the message path for this messenger
/// </summary>
public string MessagePath { get; private set; }
/// <summary>
/// Initializes a new instance of the MessengerBase class
///
/// </summary>
/// <param name="key">The unique key for this messenger</param>
/// <param name="messagePath">The message path for routing messages</param>
/// <exception cref="ArgumentException">Thrown when messagePath is null or empty</exception>
/// <param name="key"></param>
/// <param name="messagePath"></param>
protected MessengerBase(string key, string messagePath)
: base(key)
{
@@ -63,12 +47,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
MessagePath = messagePath;
}
/// <summary>
/// Initializes a new instance of the MessengerBase class with an associated device
/// </summary>
/// <param name="key">The unique key for this messenger</param>
/// <param name="messagePath">The message path for routing messages</param>
/// <param name="device">The device to associate with this messenger</param>
protected MessengerBase(string key, string messagePath, IKeyName device)
: this(key, messagePath)
{
@@ -78,7 +56,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Gets the interfaces implented on the device
/// Gets the interfaces implmented on the device
/// </summary>
/// <param name="device"></param>
/// <returns></returns>
@@ -115,11 +93,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
action(id, content);
}
/// <summary>
/// Adds an action to be executed when a message is received at the specified path
/// </summary>
/// <param name="path">The path to register the action for</param>
/// <param name="action">The action to execute when the path is matched</param>
protected void AddAction(string path, Action<string, JToken> action)
{
if (_actions.ContainsKey(path))
@@ -131,19 +104,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
_actions.Add(path, action);
}
/// <summary>
/// Gets a list of all registered action paths
/// </summary>
/// <returns>A list of action paths</returns>
public List<string> GetActionPaths()
{
return _actions.Keys.ToList();
}
/// <summary>
/// Removes an action from the specified path
/// </summary>
/// <param name="path">The path to remove the action from</param>
protected void RemoveAction(string path)
{
if (!_actions.ContainsKey(path))
@@ -157,6 +122,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// <summary>
/// Implemented in extending classes. Wire up API calls and feedback here
/// </summary>
/// <param name="appServerController"></param>
protected virtual void RegisterActions()
{
@@ -165,8 +131,8 @@ namespace PepperDash.Essentials.AppServer.Messengers
/// <summary>
/// Helper for posting status message
/// </summary>
/// <param name="message">The device state message to post</param>
/// <param name="clientId">Optional client ID to send the message to a specific client</param>
/// <param name="type"></param>
/// <param name="message"></param>
protected void PostStatusMessage(DeviceStateMessageBase message, string clientId = null)
{
try
@@ -187,22 +153,16 @@ namespace PepperDash.Essentials.AppServer.Messengers
message.Name = _device.Name;
var token = JToken.FromObject(message);
var token = JToken.FromObject(message);
PostStatusMessage(token, MessagePath, clientId);
}
catch (Exception ex)
{
this.LogError(ex, "Exception posting status message for {messagePath} to {clientId}", MessagePath, clientId ?? "all clients");
this.LogError(ex, "Exception posting status message for {messagePath} to {clientId}", MessagePath, clientId ?? "all clients");
}
}
/// <summary>
/// Posts a status message with a specific message type
/// </summary>
/// <param name="type">The message type to send</param>
/// <param name="deviceState">The device state message to post</param>
/// <param name="clientId">Optional client ID to send the message to a specific client</param>
protected void PostStatusMessage(string type, DeviceStateMessageBase deviceState, string clientId = null)
{
try
@@ -222,16 +182,10 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
catch (Exception ex)
{
this.LogError(ex, "Exception posting status message for {type} to {clientId}", type, clientId ?? "all clients");
this.LogError(ex, "Exception posting status message for {type} to {clientId}", type, clientId ?? "all clients");
}
}
/// <summary>
/// Posts a status message with JSON content
/// </summary>
/// <param name="content">The JSON content to send</param>
/// <param name="type">The message type (defaults to MessagePath if empty)</param>
/// <param name="clientId">Optional client ID to send the message to a specific client</param>
protected void PostStatusMessage(JToken content, string type = "", string clientId = null)
{
try
@@ -244,10 +198,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// Posts an event message for the device
/// </summary>
/// <param name="message">The device event message to post</param>
protected void PostEventMessage(DeviceEventMessageBase message)
{
message.Key = _device.Key;
@@ -261,11 +211,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
});
}
/// <summary>
/// Posts an event message with a specific event type
/// </summary>
/// <param name="message">The device event message to post</param>
/// <param name="eventType">The event type to use</param>
protected void PostEventMessage(DeviceEventMessageBase message, string eventType)
{
message.Key = _device.Key;
@@ -281,10 +226,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
});
}
/// <summary>
/// Posts an event message with only an event type
/// </summary>
/// <param name="eventType">The event type to post</param>
protected void PostEventMessage(string eventType)
{
AppServerController?.SendMessageObject(new MobileControlMessage
@@ -296,9 +237,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Base class for device messages containing common properties like key, name, and message type
/// </summary>
public abstract class DeviceMessageBase
{
/// <summary>
@@ -319,28 +257,21 @@ namespace PepperDash.Essentials.AppServer.Messengers
[JsonProperty("messageType")]
public string MessageType => GetType().Name;
/// <summary>
/// Gets or sets the base path for the message
/// </summary>
[JsonProperty("messageBasePath")]
public string MessageBasePath { get; set; }
}
/// <summary>
/// Base class for state messages that includes the type of message and the implemented interfaces
/// Base class for state messages that includes the type of message and the implmented interfaces
/// </summary>
public class DeviceStateMessageBase : DeviceMessageBase
{
/// <summary>
/// The interfaces implented by the device sending the messsage
/// The interfaces implmented by the device sending the messsage
/// </summary>
[JsonProperty("interfaces")]
public List<string> Interfaces { get; private set; }
/// <summary>
/// Sets the interfaces implemented by the device
/// </summary>
/// <param name="interfaces">List of interface names to set</param>
public void SetInterfaces(List<string> interfaces)
{
Interfaces = interfaces;

View File

@@ -1,34 +1,19 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharp;
using Crestron.SimplSharp;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Static handler for managing press and hold button actions with automatic timeout functionality
/// </summary>
public static class PressAndHoldHandler
{
/// <summary>
/// The interval in milliseconds for button heartbeat timeout
/// </summary>
private const long ButtonHeartbeatInterval = 1000;
/// <summary>
/// Dictionary of active timers for pressed actions, keyed by device key
/// </summary>
private static readonly Dictionary<string, CTimer> _pushedActions = new Dictionary<string, CTimer>();
/// <summary>
/// Dictionary of action handlers for different button states
/// </summary>
private static readonly Dictionary<string, Action<string, Action<bool>>> _pushedActionHandlers;
/// <summary>
/// Static constructor that initializes the action handlers for different button states
/// </summary>
static PressAndHoldHandler()
{
_pushedActionHandlers = new Dictionary<string, Action<string, Action<bool>>>
@@ -39,11 +24,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
};
}
/// <summary>
/// Adds a timer for a device key and executes the action with true state
/// </summary>
/// <param name="deviceKey">The unique key for the device</param>
/// <param name="action">The action to execute with boolean state</param>
private static void AddTimer(string deviceKey, Action<bool> action)
{
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to add timer for {deviceKey}", deviceKey);
@@ -70,11 +50,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
_pushedActions.Add(deviceKey, cancelTimer);
}
/// <summary>
/// Resets an existing timer for the specified device key
/// </summary>
/// <param name="deviceKey">The unique key for the device</param>
/// <param name="action">The action associated with the timer</param>
private static void ResetTimer(string deviceKey, Action<bool> action)
{
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to reset timer for {deviceKey}", deviceKey);
@@ -90,11 +65,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
cancelTimer.Reset(ButtonHeartbeatInterval);
}
/// <summary>
/// Stops and removes the timer for the specified device key
/// </summary>
/// <param name="deviceKey">The unique key for the device</param>
/// <param name="action">The action to execute with false state before stopping</param>
private static void StopTimer(string deviceKey, Action<bool> action)
{
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Attempting to stop timer for {deviceKey}", deviceKey);
@@ -112,11 +82,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
_pushedActions.Remove(deviceKey);
}
/// <summary>
/// Gets the appropriate press and hold handler for the specified value
/// </summary>
/// <param name="value">The button state value (pressed, held, released)</param>
/// <returns>The handler action for the specified state, or null if not found</returns>
public static Action<string, Action<bool>> GetPressAndHoldHandler(string value)
{
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Getting press and hold handler for {value}", value);
@@ -132,12 +97,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
return handler;
}
/// <summary>
/// Handles press and hold messages by parsing the content and executing the appropriate handler
/// </summary>
/// <param name="deviceKey">The unique key for the device</param>
/// <param name="content">The JSON content containing the button state</param>
/// <param name="action">The action to execute with boolean state</param>
public static void HandlePressAndHold(string deviceKey, JToken content, Action<bool> action)
{
var msg = content.ToObject<MobileControlSimpleContent<string>>();

View File

@@ -1,30 +1,18 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Room.Config;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Messenger for managing scheduled events in a room.
/// This class handles saving scheduled events and sending the current schedule state to clients.
/// It listens for changes in the scheduled events and updates clients accordingly.
/// </summary>
public class RoomEventScheduleMessenger : MessengerBase
{
private readonly IRoomEventSchedule _room;
/// <summary>
/// Initializes a new instance of the <see cref="RoomEventScheduleMessenger"/> class.
/// This constructor sets up the messenger with a unique key, message path, and the room event schedule interface.
/// It registers actions for saving scheduled events and sending the current schedule state.
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="room">Room event schedule interface</param>
public RoomEventScheduleMessenger(string key, string messagePath, IRoomEventSchedule room)
: base(key, messagePath, room as IKeyName)
{
@@ -33,7 +21,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
#region Overrides of MessengerBase
/// <inheritdoc />
protected override void RegisterActions()
{
AddAction("/saveScheduledEvents", (id, content) => SaveScheduledEvents(content.ToObject<List<ScheduledEventConfig>>()));
@@ -41,7 +28,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
var events = _room.GetScheduledEvents();
SendFullStatus(events, id);
SendFullStatus(events);
});
_room.ScheduledEventsChanged += (sender, args) => SendFullStatus(args.ScheduledEvents);
@@ -65,11 +52,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
catch (Exception ex)
{
this.LogException(ex, "Exception saving event");
this.LogException(ex,"Exception saving event");
}
}
private void SendFullStatus(List<ScheduledEventConfig> events, string id = null)
private void SendFullStatus(List<ScheduledEventConfig> events)
{
var message = new RoomEventScheduleStateMessage
@@ -77,22 +64,12 @@ namespace PepperDash.Essentials.AppServer.Messengers
ScheduleEvents = events,
};
PostStatusMessage(message, id);
PostStatusMessage(message);
}
}
/// <summary>
/// Represents the state message for room event schedules.
/// This message contains a list of scheduled events configured for the room.
/// It is used to communicate the current schedule state to clients.
/// </summary>
public class RoomEventScheduleStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the list of scheduled events for the room.
/// This property contains the configuration of scheduled events that are set up in the room.
/// Each event includes details such as the event name, start time, end time, and recurrence pattern.
/// </summary>
[JsonProperty("scheduleEvents")]
public List<ScheduledEventConfig> ScheduleEvents { get; set; }
}

View File

@@ -1,39 +1,32 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.Codec;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// SIMPL messenger for audio-only conference devices that provides audio calling functionality
/// </summary>
// ReSharper disable once InconsistentNaming
public class SIMPLAtcMessenger : MessengerBase
{
/// <summary>
/// The EISC (Ethernet Intersystem Communication) device
/// </summary>
private readonly BasicTriList _eisc;
/// <summary>
/// Gets the join map for SIMPL ATC operations
/// </summary>
public SIMPLAtcJoinMap JoinMap { get; private set; }
/// <summary>
/// The current active call item for audio calls
///
/// </summary>
private readonly CodecActiveCallItem _currentCallItem;
/// <summary>
/// Initializes a new instance of the SIMPLAtcMessenger class
///
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="eisc">The EISC device for communication</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="key"></param>
/// <param name="eisc"></param>
/// <param name="messagePath"></param>
public SIMPLAtcMessenger(string key, BasicTriList eisc, string messagePath)
: base(key, messagePath)
{
@@ -45,7 +38,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Sends the current status of the audio conference device to connected clients
///
/// </summary>
private void SendFullStatus()
{
@@ -60,8 +53,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Registers actions and feedback handlers for the SIMPL ATC messenger
///
/// </summary>
/// <param name="appServerController"></param>
protected override void RegisterActions()
{
//EISC.SetStringSigAction(SCurrentDialString, s => PostStatusMessage(new { currentDialString = s }));
@@ -139,7 +133,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Sends the current calls list to connected clients
///
/// </summary>
private void SendCallsList()
{
@@ -151,9 +145,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Gets the current call list based on the call status
/// Turns the
/// </summary>
/// <returns>A list containing the current call item if connected, or an empty list if disconnected</returns>
/// <returns></returns>
private List<CodecActiveCallItem> GetCurrentCallList()
{
return _currentCallItem.Status == eCodecCallStatus.Disconnected

View File

@@ -1,18 +1,14 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Devices.Common.Cameras;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for camera control operations in SIMPL-based systems.
/// Handles camera movement, zoom, preset management, and mode control.
/// </summary>
// ReSharper disable once InconsistentNaming
public class SIMPLCameraMessenger : MessengerBase
{
@@ -20,13 +16,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
private readonly CameraControllerJoinMap _joinMap;
/// <summary>
/// Initializes a new instance of the <see cref="SIMPLCameraMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="eisc">The basic tri-list for SIMPL communication.</param>
/// <param name="messagePath">The message path for camera control messages.</param>
/// <param name="joinStart">The starting join number for SIMPL signal mapping.</param>
public SIMPLCameraMessenger(string key, BasicTriList eisc, string messagePath, uint joinStart)
: base(key, messagePath)
{
@@ -42,10 +32,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Registers actions for handling camera control operations.
/// Includes camera movement, zoom, preset management, and mode control actions.
/// </summary>
protected override void RegisterActions()
{
AddAction("/fullStatus", (id, content) => SendCameraFullMessageObject());

View File

@@ -1,35 +1,19 @@
using System.Collections.Generic;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for direct routing operations in SIMPL-based systems.
/// Handles source selection, destination routing, and advanced sharing mode functionality.
/// </summary>
public class SimplDirectRouteMessenger : MessengerBase
{
private readonly BasicTriList _eisc;
/// <summary>
/// Gets the join map for SIMPL direct route actions.
/// </summary>
public MobileControlSIMPLRunDirectRouteActionJoinMap JoinMap { get; private set; }
/// <summary>
/// Gets or sets the dictionary of destination items for routing operations.
/// </summary>
public Dictionary<string, DestinationListItem> DestinationList { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="SimplDirectRouteMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="eisc">The basic tri-list for SIMPL communication.</param>
/// <param name="messagePath">The message path for routing messages.</param>
public SimplDirectRouteMessenger(string key, BasicTriList eisc, string messagePath) : base(key, messagePath)
{
_eisc = eisc;
@@ -41,10 +25,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
#region Overrides of MessengerBase
/// <summary>
/// Registers actions for handling direct route messaging operations.
/// Includes audio source selection, full status reporting, and advanced sharing mode controls.
/// </summary>
protected override void RegisterActions()
{
Debug.Console(2, "********** Direct Route Messenger CustomRegisterWithAppServer **********");
@@ -112,10 +92,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
));
}
/// <summary>
/// Registers routing actions for each destination in the destination list.
/// Sets up feedback handlers and source selection actions for individual destinations.
/// </summary>
public void RegisterForDestinationPaths()
{
//handle routing feedback from SIMPL
@@ -138,11 +114,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
#endregion
/// <summary>
/// Updates the source selection for a specific destination and posts a status message.
/// </summary>
/// <param name="sourceKey">The key of the selected source.</param>
/// <param name="destKey">The key of the destination being updated.</param>
private void UpdateSourceForDestination(string sourceKey, string destKey)
{
PostStatusMessage(JToken.FromObject(new

View File

@@ -6,34 +6,21 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for routing operations in SIMPL-based systems.
/// Handles source selection and routing status feedback.
/// </summary>
public class SIMPLRouteMessenger : MessengerBase
{
private readonly BasicTriList _eisc;
private readonly uint _joinStart;
/// <summary>
/// Defines the string join mappings for SIMPL routing operations.
/// </summary>
public class StringJoin
{
/// <summary>
/// Join number for current source information (1).
/// 1
/// </summary>
public const uint CurrentSource = 1;
}
/// <summary>
/// Initializes a new instance of the <see cref="SIMPLRouteMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="eisc">The basic tri-list for SIMPL communication.</param>
/// <param name="messagePath">The message path for routing messages.</param>
/// <param name="joinStart">The starting join number for SIMPL signal mapping.</param>
public SIMPLRouteMessenger(string key, BasicTriList eisc, string messagePath, uint joinStart)
: base(key, messagePath)
{
@@ -43,10 +30,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
_eisc.SetStringSigAction(_joinStart + StringJoin.CurrentSource, SendRoutingFullMessageObject);
}
/// <summary>
/// Registers actions for handling routing operations and status reporting.
/// Includes full status requests and source selection actions.
/// </summary>
protected override void RegisterActions()
{
AddAction("/fullStatus",
@@ -60,11 +43,6 @@ namespace PepperDash.Essentials.AppServer.Messengers
});
}
/// <summary>
/// Unregisters this messenger from the mobile control app server.
/// Removes all registered actions and clears SIMPL signal actions.
/// </summary>
/// <param name="appServerController">The mobile control app server controller.</param>
public void CustomUnregisterWithAppServer(IMobileControl appServerController)
{
appServerController.RemoveAction(MessagePath + "/fullStatus");

View File

@@ -1,51 +1,33 @@
using System;
using System.Collections.Generic;
using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.Codec;
using System;
using System.Collections.Generic;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// SIMPL messenger for video conference devices that provides video calling and camera control functionality
/// </summary>
// ReSharper disable once InconsistentNaming
public class SIMPLVtcMessenger : MessengerBase
{
/// <summary>
/// The EISC (Ethernet Intersystem Communication) device
/// </summary>
private readonly BasicTriList _eisc;
/// <summary>
/// Gets the join map for SIMPL VTC operations
/// </summary>
public SIMPLVtcJoinMap JoinMap { get; private set; }
/// <summary>
/// The current active call item for video calls
/// </summary>
private readonly CodecActiveCallItem _currentCallItem;
/// <summary>
/// The incoming call item for video calls
/// </summary>
private CodecActiveCallItem _incomingCallItem;
/// <summary>
/// The previous directory length for tracking changes
/// </summary>
private ushort _previousDirectoryLength = 701;
/// <summary>
/// Initializes a new instance of the SIMPLVtcMessenger class
///
/// </summary>
/// <param name="key">Unique identifier for the messenger</param>
/// <param name="eisc">The EISC device for communication</param>
/// <param name="messagePath">Path for message routing</param>
/// <param name="key"></param>
/// <param name="eisc"></param>
/// <param name="messagePath"></param>
public SIMPLVtcMessenger(string key, BasicTriList eisc, string messagePath)
: base(key, messagePath)
{
@@ -57,8 +39,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Registers actions and feedback handlers for the SIMPL VTC messenger
///
/// </summary>
/// <param name="appServerController"></param>
protected override void RegisterActions()
{
_eisc.SetStringSigAction(JoinMap.HookState.JoinNumber, s =>

View File

@@ -1,39 +1,25 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core.Shades;
using System;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for shade control operations.
/// Handles shade open, close, and stop commands for shades that support these operations.
/// </summary>
public class IShadesOpenCloseStopMessenger : MessengerBase
{
private readonly IShadesOpenCloseStop device;
/// <summary>
/// Initializes a new instance of the <see cref="IShadesOpenCloseStopMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="shades">The shade device that provides open/close/stop functionality.</param>
/// <param name="messagePath">The message path for shade control messages.</param>
public IShadesOpenCloseStopMessenger(string key, IShadesOpenCloseStop shades, string messagePath)
: base(key, messagePath, shades as IKeyName)
{
device = shades;
}
/// <summary>
/// Registers actions for handling shade control operations.
/// Includes shade open, close, stop, and full status reporting.
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
AddAction("/shadeUp", (id, content) =>
{
@@ -86,7 +72,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
private void SendFullStatus(string id = null)
private void SendFullStatus()
{
var state = new ShadeBaseStateMessage();
@@ -96,30 +82,18 @@ namespace PepperDash.Essentials.AppServer.Messengers
state.IsClosed = feedbackDevice.ShadeIsClosedFeedback.BoolValue;
}
PostStatusMessage(state, id);
PostStatusMessage(state);
}
}
/// <summary>
/// Represents a shade state message containing shade status and control information.
/// </summary>
public class ShadeBaseStateMessage : DeviceStateMessageBase
{
/// <summary>
/// Gets or sets the label for the middle button control.
/// </summary>
[JsonProperty("middleButtonLabel", NullValueHandling = NullValueHandling.Ignore)]
public string MiddleButtonLabel { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the shade is open.
/// </summary>
[JsonProperty("isOpen", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsOpen { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the shade is closed.
/// </summary>
[JsonProperty("isClosed", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsClosed { get; set; }
}

View File

@@ -1,28 +1,17 @@
using System;
using System.Threading.Tasks;
using Crestron.SimplSharp;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core.Monitoring;
using System;
using System.Threading.Tasks;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for system monitoring operations.
/// Handles system performance metrics, program status reporting, and monitoring data communication.
/// </summary>
public class SystemMonitorMessenger : MessengerBase
{
private readonly SystemMonitorController systemMonitor;
/// <summary>
/// Initializes a new instance of the <see cref="SystemMonitorMessenger"/> class.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="sysMon">The system monitor controller for monitoring operations.</param>
/// <param name="messagePath">The message path for system monitor messages.</param>
/// <exception cref="ArgumentNullException">Thrown when sysMon is null.</exception>
public SystemMonitorMessenger(string key, SystemMonitorController sysMon, string messagePath)
: base(key, messagePath, sysMon)
{
@@ -64,20 +53,20 @@ namespace PepperDash.Essentials.AppServer.Messengers
SendSystemMonitorStatusMessage();
}
private void SendFullStatusMessage(string id = null)
private void SendFullStatusMessage()
{
SendSystemMonitorStatusMessage(id);
SendSystemMonitorStatusMessage();
foreach (var p in systemMonitor.ProgramStatusFeedbackCollection)
{
PostStatusMessage(JToken.FromObject(p.Value.ProgramInfo), id);
PostStatusMessage(JToken.FromObject(p.Value.ProgramInfo));
}
}
private void SendSystemMonitorStatusMessage(string id = null)
private void SendSystemMonitorStatusMessage()
{
// This takes a while, launch a new thread
Task.Run(() => PostStatusMessage(JToken.FromObject(new SystemMonitorStateMessage
{
@@ -87,58 +76,33 @@ namespace PepperDash.Essentials.AppServer.Messengers
SnmpVersion = systemMonitor.SnmpVersionFeedback.StringValue,
BacnetVersion = systemMonitor.BaCnetAppVersionFeedback.StringValue,
ControllerVersion = systemMonitor.ControllerVersionFeedback.StringValue
}), id
})
));
}
/// <summary>
/// Registers actions for handling system monitor operations.
/// Includes full status reporting for system monitoring data.
/// </summary>
protected override void RegisterActions()
{
AddAction("/fullStatus", (id, content) => SendFullStatusMessage(id));
AddAction("/fullStatus", (id, content) => SendFullStatusMessage());
}
}
/// <summary>
/// Represents the system monitor state message containing system information and version details.
/// </summary>
public class SystemMonitorStateMessage
{
/// <summary>
/// Gets or sets the system time zone offset.
/// </summary>
[JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)]
public int TimeZone { get; set; }
/// <summary>
/// Gets or sets the system time zone name.
/// </summary>
[JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)]
public string TimeZoneName { get; set; }
/// <summary>
/// Gets or sets the IO controller version information.
/// </summary>
[JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)]
public string IoControllerVersion { get; set; }
/// <summary>
/// Gets or sets the SNMP version information.
/// </summary>
[JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)]
public string SnmpVersion { get; set; }
/// <summary>
/// Gets or sets the BACnet version information.
/// </summary>
[JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)]
public string BacnetVersion { get; set; }
/// <summary>
/// Gets or sets the controller version information.
/// </summary>
[JsonProperty("timeZone", NullValueHandling = NullValueHandling.Ignore)]
public string ControllerVersion { get; set; }
}

View File

@@ -5,27 +5,10 @@ using PepperDash.Essentials.Devices.Common.Displays;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Provides messaging capabilities for two-way display control operations.
/// Handles display input changes, power state, and cooling/warming status.
/// This class extends the MessengerBase to facilitate communication between the display and the mobile control interface.
/// </summary>
public class TwoWayDisplayBaseMessenger : MessengerBase
{
private readonly TwoWayDisplayBase _display;
/// <summary>
/// Initializes a new instance of the <see cref="TwoWayDisplayBaseMessenger"/> class.
/// This constructor sets up the messenger with a key, message path, and the display instance
/// that it will control and monitor.
/// The display instance should implement the TwoWayDisplayBase interface to provide the necessary feedback and
/// control methods for the display device.
/// The messenger will listen for changes in the display's state and send updates to the mobile control interface.
/// It also allows for sending commands to the display, such as changing inputs or toggling power states.
/// </summary>
/// <param name="key">The unique identifier for this messenger instance.</param>
/// <param name="messagePath">The message path for display control messages.</param>
/// <param name="display">The display instance to control and monitor.</param>
public TwoWayDisplayBaseMessenger(string key, string messagePath, TwoWayDisplayBase display)
: base(key, messagePath, display)
{
@@ -34,8 +17,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
#region Overrides of MessengerBase
private void SendFullStatus(string id = null)
public void SendFullStatus()
{
var messageObj = new TwoWayDisplayBaseStateMessage
{
@@ -43,20 +25,16 @@ namespace PepperDash.Essentials.AppServer.Messengers
CurrentInput = _display.CurrentInputFeedback.StringValue
};
PostStatusMessage(messageObj, id);
PostStatusMessage(messageObj);
}
/// <summary>
/// Registers actions for handling two-way display operations.
/// This includes sending full status updates and handling input changes, cooling, and warming feedback.
/// The actions are registered to respond to specific commands sent from the mobile control interface.
/// </summary>
protected override void RegisterActions()
{
base.RegisterActions();
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
//_display.PowerIsOnFeedback.OutputChange += PowerIsOnFeedbackOnOutputChange;
_display.CurrentInputFeedback.OutputChange += CurrentInputFeedbackOnOutputChange;
_display.IsCoolingDownFeedback.OutputChange += IsCoolingFeedbackOnOutputChange;
_display.IsWarmingUpFeedback.OutputChange += IsWarmingFeedbackOnOutputChange;
@@ -71,6 +49,16 @@ namespace PepperDash.Essentials.AppServer.Messengers
);
}
//private void PowerIsOnFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs)
//{
// PostStatusMessage(JToken.FromObject(new
// {
// powerState = feedbackEventArgs.BoolValue
// })
// );
//}
private void IsWarmingFeedbackOnOutputChange(object sender, FeedbackEventArgs feedbackEventArgs)
{
PostStatusMessage(JToken.FromObject(new

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Crestron.SimplSharp;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
@@ -13,6 +9,9 @@ using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PepperDash.Essentials.AppServer.Messengers
{
@@ -22,18 +21,18 @@ namespace PepperDash.Essentials.AppServer.Messengers
public class VideoCodecBaseMessenger : MessengerBase
{
/// <summary>
/// The video codec device being managed by this messenger.
///
/// </summary>
protected VideoCodecBase Codec { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="VideoCodecBaseMessenger"/> class.
///
/// </summary>
/// <param name="key">The unique identifier for the messenger.</param>
/// <param name="codec">The video codec device to be managed.</param>
/// <param name="messagePath">The message path for communication.</param>
/// <exception cref="ArgumentNullException">Thrown when codec is null</exception>
/// <param name="key"></param>
/// <param name="codec"></param>
/// <param name="messagePath"></param>
public VideoCodecBaseMessenger(string key, VideoCodecBase codec, string messagePath)
: base(key, messagePath, codec)
{
@@ -71,6 +70,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
PostEventMessage(eventMsg);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CallHistory_RecentCallsListHasChanged(object sender, EventArgs e)
{
try
@@ -94,10 +98,10 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Handles the event when a directory result is returned from the codec.
///
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The directory event arguments.</param>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void DirCodec_DirectoryResultReturned(object sender, DirectoryEventArgs e)
{
if (Codec is IHasDirectory)
@@ -105,9 +109,8 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Sends the current directory structure to the mobile control interface.
/// Posts the current directory
/// </summary>
/// <param name="directory">The directory structure to send.</param>
protected void SendDirectory(CodecDirectory directory)
{
try
@@ -131,6 +134,11 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Codec_IsReadyChange(object sender, EventArgs e)
{
try
@@ -143,14 +151,16 @@ namespace PepperDash.Essentials.AppServer.Messengers
PostStatusMessage(state);
SendFullStatus();
}
catch (Exception ex)
} catch (Exception ex)
{
this.LogError(ex, "Error sending codec ready status");
}
}
/// <inheritdoc />
/// <summary>
/// Called from base's RegisterWithAppServer method
/// </summary>
/// <param name="appServerController"></param>
protected override void RegisterActions()
{
try
@@ -159,7 +169,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
AddAction("/isReady", (id, content) => SendIsReady());
AddAction("/fullStatus", (id, content) => SendFullStatus(id));
AddAction("/fullStatus", (id, content) => SendFullStatus());
AddAction("/dial", (id, content) =>
{
@@ -359,8 +369,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
};
PostStatusMessage(state);
}
catch (Exception ex)
} catch (Exception ex)
{
this.LogError(ex, "Error posting sharing source");
}
@@ -376,8 +385,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
};
PostStatusMessage(state);
}
catch (Exception ex)
} catch (Exception ex)
{
this.LogError(ex, "Error posting sharing content");
}
@@ -427,13 +435,15 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
MapCameraActions();
PostSelectedCamera();
}
catch (Exception ex)
} catch(Exception ex)
{
this.LogError(ex, "Exception handling camera selected event");
}
}
/// <summary>
/// Maps the camera control actions to the current selected camera on the codec
/// </summary>
private void MapCameraActions()
{
if (Codec is IHasCameras cameraCodec && cameraCodec.SelectedCamera != null)
@@ -589,7 +599,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
{
try
{
var codec = Codec as IHasCallHistory;
var codec = (Codec as IHasCallHistory);
if (codec != null)
{
@@ -611,11 +621,20 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// Helper to grab a call with string ID
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
private CodecActiveCallItem GetCallWithId(string id)
{
return Codec.ActiveCalls.FirstOrDefault(c => c.Id == id);
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
private void GetDirectory(string id)
{
if (!(Codec is IHasDirectory dirCodec))
@@ -625,7 +644,10 @@ namespace PepperDash.Essentials.AppServer.Messengers
dirCodec.GetDirectoryFolderContents(id);
}
private void GetDirectoryRoot(string id = null)
/// <summary>
///
/// </summary>
private void GetDirectoryRoot()
{
try
{
@@ -653,6 +675,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// Requests the parent folder contents
/// </summary>
private void GetPreviousDirectory()
{
if (!(Codec is IHasDirectory dirCodec))
@@ -663,11 +688,17 @@ namespace PepperDash.Essentials.AppServer.Messengers
dirCodec.GetDirectoryParentFolderContents();
}
/// <summary>
/// Handler for codec changes
/// </summary>
private void Codec_CallStatusChange(object sender, CodecCallStatusItemChangeEventArgs e)
{
SendFullStatus();
}
/// <summary>
///
/// </summary>
private void SendIsReady()
{
try
@@ -688,9 +719,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
/// <summary>
/// Gets the current status of the video codec.
/// Helper method to build call status for vtc
/// </summary>
/// <returns> The current status of the video codec.</returns>
/// <returns></returns>
protected VideoCodecBaseStateMessage GetStatus()
{
try
@@ -749,18 +780,14 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
/// Sends the full status of the codec.
/// </summary>
/// <param name="id">The unique identifier for the status message.</param>
protected virtual void SendFullStatus(string id = null)
protected virtual void SendFullStatus()
{
if (!Codec.IsReady)
{
return;
}
Task.Run(() => PostStatusMessage(GetStatus(), id));
CrestronInvoke.BeginInvoke((o) => PostStatusMessage(GetStatus()));
}
private void PostReceivingContent(bool receivingContent)
@@ -773,8 +800,7 @@ namespace PepperDash.Essentials.AppServer.Messengers
};
PostStatusMessage(state);
}
catch (Exception ex)
} catch(Exception ex)
{
this.LogError(ex, "Error posting receiving content");
}
@@ -798,6 +824,9 @@ namespace PepperDash.Essentials.AppServer.Messengers
}
}
/// <summary>
///
/// </summary>
private void PostCameraMode()
{
try
@@ -899,324 +928,164 @@ namespace PepperDash.Essentials.AppServer.Messengers
public class VideoCodecBaseStateMessage : DeviceStateMessageBase
{
/// <summary>
/// The list of active calls on the codec.
/// </summary>
[JsonProperty("calls", NullValueHandling = NullValueHandling.Ignore)]
public List<CodecActiveCallItem> Calls { get; set; }
/// <summary>
/// The current mode of the camera.
/// </summary>
[JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)]
public string CameraMode { get; set; }
/// <summary>
/// Indicates whether the camera self-view is enabled.
/// </summary>
[JsonProperty("cameraSelfView", NullValueHandling = NullValueHandling.Ignore)]
public bool? CameraSelfViewIsOn { get; set; }
/// <summary>
/// Gets the current status of the cameras.
/// </summary>
[JsonProperty("cameras", NullValueHandling = NullValueHandling.Ignore)]
public CameraStatus Cameras { get; set; }
/// <summary>
/// Indicates whether the camera supports auto mode.
/// </summary>
[JsonProperty("cameraSupportsAutoMode", NullValueHandling = NullValueHandling.Ignore)]
public bool? CameraSupportsAutoMode { get; set; }
/// <summary>
/// Indicates whether the camera supports off mode.
/// </summary>
[JsonProperty("cameraSupportsOffMode", NullValueHandling = NullValueHandling.Ignore)]
public bool? CameraSupportsOffMode { get; set; }
/// <summary>
/// The current dial string for the codec.
/// </summary>
[JsonProperty("currentDialString", NullValueHandling = NullValueHandling.Ignore)]
public string CurrentDialString { get; set; }
/// <summary>
/// Gets the current directory for the codec.
/// </summary>
[JsonProperty("currentDirectory", NullValueHandling = NullValueHandling.Ignore)]
public CodecDirectory CurrentDirectory { get; set; }
/// <summary>
/// Gets the selected folder name in the directory.
/// </summary>
[JsonProperty("directorySelectedFolderName", NullValueHandling = NullValueHandling.Ignore)]
public string DirectorySelectedFolderName { get; set; }
/// <summary>
/// Indicates whether the codec has active camera streams.
/// </summary>
[JsonProperty("hasCameras", NullValueHandling = NullValueHandling.Ignore)]
public bool? HasCameras { get; set; }
/// <summary>
/// Indicates whether the codec has a directory.
/// </summary>
[JsonProperty("hasDirectory", NullValueHandling = NullValueHandling.Ignore)]
public bool? HasDirectory { get; set; }
/// <summary>
/// Indicates whether the codec supports directory search functionality.
/// </summary>
[JsonProperty("hasDirectorySearch", NullValueHandling = NullValueHandling.Ignore)]
public bool? HasDirectorySearch { get; set; }
/// <summary>
/// Indicates whether the codec has presets.
/// </summary>
[JsonProperty("hasPresets", NullValueHandling = NullValueHandling.Ignore)]
public bool? HasPresets { get; set; }
/// <summary>
/// Indicates whether the codec has recent calls.
/// </summary>
[JsonProperty("hasRecents", NullValueHandling = NullValueHandling.Ignore)]
public bool? HasRecents { get; set; }
/// <summary>
/// Indicates whether the initial phonebook sync is complete.
/// </summary>
[JsonProperty("initialPhonebookSyncComplete", NullValueHandling = NullValueHandling.Ignore)]
public bool? InitialPhonebookSyncComplete { get; set; }
/// <summary>
/// Gets the information about the video codec.
/// </summary>
[JsonProperty("info", NullValueHandling = NullValueHandling.Ignore)]
public VideoCodecInfo Info { get; set; }
/// <summary>
/// Indicates whether the codec is currently in a call.
/// </summary>
[JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsInCall { get; set; }
/// <summary>
/// Indicates whether the codec is ready.
/// </summary>
[JsonProperty("isReady", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsReady { get; set; }
/// <summary>
/// Indicates whether the codec is a Zoom Room.
/// </summary>
[JsonProperty("isZoomRoom", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsZoomRoom { get; set; }
/// <summary>
/// Gets the meeting information for the codec, if available.
/// </summary>
[JsonProperty("meetingInfo", NullValueHandling = NullValueHandling.Ignore)]
public MeetingInfo MeetingInfo { get; set; }
/// <summary>
/// Gets the list of presets for the codec.
/// </summary>
[JsonProperty("presets", NullValueHandling = NullValueHandling.Ignore)]
public List<CodecRoomPreset> Presets { get; set; }
/// <summary>
/// Indicates whether the privacy mode is currently enabled.
/// </summary>
[JsonProperty("privacyModeIsOn", NullValueHandling = NullValueHandling.Ignore)]
public bool? PrivacyModeIsOn { get; set; }
/// <summary>
/// Indicates whether the codec is currently receiving content.
/// </summary>
[JsonProperty("receivingContent", NullValueHandling = NullValueHandling.Ignore)]
public bool? ReceivingContent { get; set; }
/// <summary>
/// Gets the list of recent calls for the codec, if available.
/// </summary>
[JsonProperty("recentCalls", NullValueHandling = NullValueHandling.Ignore)]
public List<CodecCallHistory.CallHistoryEntry> RecentCalls { get; set; }
/// <summary>
/// Indicates whether the codec is currently sharing content.
/// </summary>
[JsonProperty("sharingContentIsOn", NullValueHandling = NullValueHandling.Ignore)]
public bool? SharingContentIsOn { get; set; }
/// <summary>
/// Gets the source of the shared content, if available.
/// </summary>
[JsonProperty("sharingSource", NullValueHandling = NullValueHandling.Ignore)]
public string SharingSource { get; set; }
/// <summary>
/// Indicates whether the cameras should be shown when not in a call.
/// </summary>
[JsonProperty("showCamerasWhenNotInCall", NullValueHandling = NullValueHandling.Ignore)]
public bool? ShowCamerasWhenNotInCall { get; set; }
/// <summary>
/// Indicates whether the self-view is shown by default.
/// </summary>
[JsonProperty("showSelfViewByDefault", NullValueHandling = NullValueHandling.Ignore)]
public bool? ShowSelfViewByDefault { get; set; }
/// <summary>
/// Indicates whether the codec is currently in standby mode.
/// </summary>
[JsonProperty("standbyIsOn", NullValueHandling = NullValueHandling.Ignore)]
public bool? StandbyIsOn { get; set; }
/// <summary>
/// Indicates whether the codec supports ad-hoc meetings.
/// </summary>
[JsonProperty("supportsAdHocMeeting", NullValueHandling = NullValueHandling.Ignore)]
public bool? SupportsAdHocMeeting { get; set; }
}
/// <summary>
/// Represents the status of the camera.
/// </summary>
public class CameraStatus
{
/// <summary>
/// Indicates whether the camera manual control is supported.
/// </summary>
[JsonProperty("cameraManualSupported", NullValueHandling = NullValueHandling.Ignore)]
public bool? CameraManualIsSupported { get; set; }
/// <summary>
/// Indicates whether the camera auto control is supported.
/// </summary>
[JsonProperty("cameraAutoSupported", NullValueHandling = NullValueHandling.Ignore)]
public bool? CameraAutoIsSupported { get; set; }
/// <summary>
/// Indicates whether the camera off control is supported.
/// </summary>
[JsonProperty("cameraOffSupported", NullValueHandling = NullValueHandling.Ignore)]
public bool? CameraOffIsSupported { get; set; }
/// <summary>
/// Indicates the current mode of the camera.
/// </summary>
[JsonProperty("cameraMode", NullValueHandling = NullValueHandling.Ignore)]
public string CameraMode { get; set; }
/// <summary>
/// Represents the list of cameras available.
/// </summary>
[JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)]
public List<CameraBase> Cameras { get; set; }
/// <summary>
/// Represents the currently selected camera.
/// </summary>
[JsonProperty("selectedCamera", NullValueHandling = NullValueHandling.Ignore)]
public Camera SelectedCamera { get; set; }
public Camera SelectedCamera { get; set; }
}
/// <summary>
/// Represents a camera in the video codec system.
/// </summary>
public class Camera
{
/// <summary>
/// The unique identifier for the camera.
/// </summary>
[JsonProperty("key", NullValueHandling = NullValueHandling.Ignore)]
public string Key { get; set; }
/// <summary>
/// The name of the camera.
/// </summary>
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; set; }
/// <summary>
/// Indicates whether the camera is a far-end camera.
/// </summary>
[JsonProperty("isFarEnd", NullValueHandling = NullValueHandling.Ignore)]
public bool? IsFarEnd { get; set; }
/// <summary>
/// Represents the capabilities of the camera.
/// </summary>
[JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)]
public CameraCapabilities Capabilities { get; set; }
}
/// <summary>
/// Represents the capabilities of the camera.
/// </summary>
public class CameraCapabilities
{
/// <summary>
/// Indicates whether the camera can pan.
/// </summary>
[JsonProperty("canPan", NullValueHandling = NullValueHandling.Ignore)]
public bool? CanPan { get; set; }
/// <summary>
/// Indicates whether the camera can tilt.
/// </summary>
[JsonProperty("canTilt", NullValueHandling = NullValueHandling.Ignore)]
public bool? CanTilt { get; set; }
/// <summary>
/// Indicates whether the camera can zoom.
/// </summary>
[JsonProperty("canZoom", NullValueHandling = NullValueHandling.Ignore)]
public bool? CanZoom { get; set; }
/// <summary>
/// Indicates whether the camera can focus.
/// </summary>
[JsonProperty("canFocus", NullValueHandling = NullValueHandling.Ignore)]
public bool? CanFocus { get; set; }
}
/// <summary>
/// Represents a video codec event message.
/// </summary>
public class VideoCodecBaseEventMessage : DeviceEventMessageBase
{
}
/// <summary>
/// Represents a password prompt event message.
/// </summary>
public class PasswordPromptEventMessage : VideoCodecBaseEventMessage
{
/// <summary>
/// The message to display in the password prompt.
/// </summary>
[JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)]
public string Message { get; set; }
/// <summary>
/// Indicates whether the last password attempt was incorrect.
/// </summary>
[JsonProperty("lastAttemptWasIncorrect", NullValueHandling = NullValueHandling.Ignore)]
public bool LastAttemptWasIncorrect { get; set; }
/// <summary>
/// Indicates whether the login attempt failed.
/// </summary>
[JsonProperty("loginAttemptFailed", NullValueHandling = NullValueHandling.Ignore)]
public bool LoginAttemptFailed { get; set; }
/// <summary>
/// Indicates whether the login attempt was cancelled.
/// </summary>
[JsonProperty("loginAttemptCancelled", NullValueHandling = NullValueHandling.Ignore)]
public bool LoginAttemptCancelled { get; set; }
}

View File

@@ -4,26 +4,14 @@ using PepperDash.Essentials.Core.DeviceTypeInterfaces;
namespace PepperDash.Essentials.AppServer.Messengers
{
/// <summary>
/// Represents a mobile control message that can be sent between clients and the system
/// </summary>
public class MobileControlMessage : IMobileControlMessage
{
/// <summary>
/// Gets or sets the message type/path for routing
/// </summary>
[JsonProperty("type")]
public string Type { get; set; }
/// <summary>
/// Gets or sets the client ID this message is intended for (null for broadcast)
/// </summary>
[JsonProperty("clientId")]
public string ClientId { get; set; }
/// <summary>
/// Gets or sets the JSON content of the message
/// </summary>
[JsonProperty("content")]
public JToken Content { get; set; }
}

View File

@@ -2,15 +2,8 @@
namespace PepperDash.Essentials.AppServer
{
/// <summary>
/// Generic container for simple mobile control message content with a single value
/// </summary>
/// <typeparam name="T">The type of the value contained in the message</typeparam>
public class MobileControlSimpleContent<T>
{
/// <summary>
/// Gets or sets the value of the message content
/// </summary>
[JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)]
public T Value { get; set; }
}

View File

@@ -1,74 +0,0 @@
using System;
using System.Threading;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.WebSocketServer;
using Serilog.Events;
namespace PepperDash.Essentials
{
public class MessageToClients : IQueueMessage
{
private readonly MobileControlWebsocketServer _server;
private readonly object msgToSend;
public MessageToClients(object msg, MobileControlWebsocketServer server)
{
_server = server;
msgToSend = msg;
}
public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server)
{
_server = server;
msgToSend = msg;
}
#region Implementation of IQueueMessage
public void Dispatch()
{
try
{
if (_server == null)
{
Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null");
return;
}
var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
var clientSpecificMessage = msgToSend as MobileControlMessage;
if (clientSpecificMessage.ClientId != null)
{
var clientId = clientSpecificMessage.ClientId;
_server.LogVerbose("Message TX To client {clientId} Message: {message}", clientId, message);
_server.SendMessageToClient(clientId, message);
return;
}
_server.SendMessageToAllClients(message);
_server.LogVerbose("Message TX To all clients: {message}", message);
}
catch (ThreadAbortException)
{
//Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace
}
catch (Exception ex)
{
Debug.LogMessage(ex, "Caught an exception in the Transmit Processor");
}
}
#endregion
}
}

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Crestron.SimplSharp;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Net.Http;
using Crestron.SimplSharp.WebScripting;
@@ -36,6 +30,12 @@ using PepperDash.Essentials.RoomBridges;
using PepperDash.Essentials.Services;
using PepperDash.Essentials.WebApiHandlers;
using PepperDash.Essentials.WebSocketServer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using WebSocketSharp;
namespace PepperDash.Essentials
@@ -570,7 +570,7 @@ namespace PepperDash.Essentials
{
this.LogVerbose(
"Adding ISetTopBoxControlMessenger for {deviceKey}"
);
);
var messenger = new ISetTopBoxControlsMessenger(
$"{device.Key}-stb-{Key}",
@@ -587,7 +587,7 @@ namespace PepperDash.Essentials
{
this.LogVerbose(
"Adding IChannelMessenger for {deviceKey}", device.Key
);
);
var messenger = new IChannelMessenger(
$"{device.Key}-channel-{Key}",
@@ -602,7 +602,7 @@ namespace PepperDash.Essentials
if (device is IColor colorDevice)
{
this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key);
this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key);
var messenger = new IColorMessenger(
$"{device.Key}-color-{Key}",
@@ -617,7 +617,7 @@ namespace PepperDash.Essentials
if (device is IDPad dPadDevice)
{
this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key);
this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key);
var messenger = new IDPadMessenger(
$"{device.Key}-dPad-{Key}",
@@ -632,7 +632,7 @@ namespace PepperDash.Essentials
if (device is INumericKeypad nkDevice)
{
this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key);
this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key);
var messenger = new INumericKeypadMessenger(
$"{device.Key}-numericKeypad-{Key}",
@@ -647,7 +647,7 @@ namespace PepperDash.Essentials
if (device is IHasPowerControl pcDevice)
{
this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key);
this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key);
var messenger = new IHasPowerMessenger(
$"{device.Key}-powerControl-{Key}",
@@ -681,7 +681,7 @@ namespace PepperDash.Essentials
{
this.LogVerbose(
"Adding ITransportMessenger for {deviceKey}", device.Key
);
);
var messenger = new ITransportMessenger(
$"{device.Key}-transport-{Key}",
@@ -1619,12 +1619,12 @@ Mobile Control Direct Server Information:
Tokens Defined: {0}
Clients Connected: {1}
",
_directServer.UiClientContexts.Count,
_directServer.UiClients.Count,
_directServer.ConnectedUiClientsCount
);
var clientNo = 1;
foreach (var clientContext in _directServer.UiClientContexts)
foreach (var clientContext in _directServer.UiClients)
{
var isAlive = false;
var duration = "Not Connected";
@@ -2238,7 +2238,7 @@ Mobile Control Direct Server Infromation:
{
this.LogInformation("-- Warning: Incoming message has no registered handler {type}", message.Type);
break;
}
}
foreach (var handler in handlers)
{

View File

@@ -491,7 +491,7 @@ namespace PepperDash.Essentials.Touchpanel
{
public MobileControlTouchpanelControllerFactory()
{
TypeNames = new List<string>() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel", "mcdge1000" };
TypeNames = new List<string>() { "mccrestronapp", "mctsw550", "mctsw750", "mctsw1050", "mctsw560", "mctsw760", "mctsw1060", "mctsw570", "mctsw770", "mcts770", "mctsw1070", "mcts1070", "mcxpanel" };
MinimumEssentialsFrameworkVersion = "2.0.0";
}
@@ -555,10 +555,7 @@ namespace PepperDash.Essentials.Touchpanel
return new Tsw1070(id, Global.ControlSystem);
else if (type == "ts1070")
return new Ts1070(id, Global.ControlSystem);
else if (type == "dge1000")
return new Dge1000(id, Global.ControlSystem);
else
else
{
Debug.LogMessage(Serilog.Events.LogEventLevel.Warning, "WARNING: Cannot create TSW controller with type '{0}'", type);
return null;

View File

@@ -1,10 +1,13 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using PepperDash.Core;
using PepperDash.Core.Logging;
using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.WebSocketServer;
using Serilog.Events;
using System;
using System.Threading;
using WebSocketSharp;
namespace PepperDash.Essentials
@@ -62,4 +65,66 @@ namespace PepperDash.Essentials
#endregion
}
public class MessageToClients : IQueueMessage
{
private readonly MobileControlWebsocketServer _server;
private readonly object msgToSend;
public MessageToClients(object msg, MobileControlWebsocketServer server)
{
_server = server;
msgToSend = msg;
}
public MessageToClients(DeviceStateMessageBase msg, MobileControlWebsocketServer server)
{
_server = server;
msgToSend = msg;
}
#region Implementation of IQueueMessage
public void Dispatch()
{
try
{
if (_server == null)
{
Debug.LogMessage(LogEventLevel.Warning, "Cannot send message. Server is null");
return;
}
var message = JsonConvert.SerializeObject(msgToSend, Formatting.None,
new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, Converters = { new IsoDateTimeConverter() } });
var clientSpecificMessage = msgToSend as MobileControlMessage;
if (clientSpecificMessage.ClientId != null)
{
var clientId = clientSpecificMessage.ClientId;
_server.LogVerbose("Message TX To client {clientId} Message: {message}", clientId, message);
_server.SendMessageToClient(clientId, message);
return;
}
_server.SendMessageToAllClients(message);
_server.LogVerbose("Message TX To all clients: {message}", message);
}
catch (ThreadAbortException)
{
//Swallowing this exception, as it occurs on shutdown and there's no need to print out a scary stack trace
}
catch (Exception ex)
{
Debug.LogMessage(ex, "Caught an exception in the Transmit Processor");
}
}
#endregion
}
}

View File

@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp.WebScripting;
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.WebSocketServer;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PepperDash.Essentials.WebApiHandlers
{
@@ -99,13 +99,13 @@ namespace PepperDash.Essentials.WebApiHandlers
public int ServerPort => directServer.Port;
[JsonProperty("tokensDefined")]
public int TokensDefined => directServer.UiClientContexts.Count;
public int TokensDefined => directServer.UiClients.Count;
[JsonProperty("clientsConnected")]
public int ClientsConnected => directServer.ConnectedUiClientsCount;
[JsonProperty("clients")]
public List<MobileControlDirectClient> Clients => directServer.UiClientContexts.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList();
public List<MobileControlDirectClient> Clients => directServer.UiClients.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList();
public MobileControlDirectServer(MobileControlWebsocketServer server)
{

View File

@@ -90,7 +90,7 @@ namespace PepperDash.Essentials.WebApiHandlers
if (!server.UiClientContexts.TryGetValue(request.Token, out UiClientContext clientContext))
if (!server.UiClients.TryGetValue(request.Token, out UiClientContext clientContext))
{
var response = new ClientResponse
{
@@ -131,7 +131,7 @@ namespace PepperDash.Essentials.WebApiHandlers
return;
}
server.UiClientContexts.Remove(request.Token);
server.UiClients.Remove(request.Token);
server.UpdateSecret();

View File

@@ -1,39 +0,0 @@
using System;
using Newtonsoft.Json;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents the structure of the join response
/// </summary>
public class JoinResponse
{
[JsonProperty("clientId")]
public string ClientId { get; set; }
[JsonProperty("roomKey")]
public string RoomKey { get; set; }
[JsonProperty("systemUUid")]
public string SystemUuid { get; set; }
[JsonProperty("roomUUid")]
public string RoomUuid { get; set; }
[JsonProperty("config")]
public object Config { get; set; }
[JsonProperty("codeExpires")]
public DateTime CodeExpires { get; set; }
[JsonProperty("userCode")]
public string UserCode { get; set; }
[JsonProperty("userAppUrl")]
public string UserAppUrl { get; set; }
[JsonProperty("enableDebug")]
public bool EnableDebug { get; set; }
}
}

View File

@@ -1,22 +0,0 @@
using Independentsoft.Exchange;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents a join token with the associated properties
/// </summary>
public class JoinToken
{
public string Code { get; set; }
public string RoomKey { get; set; }
public string Uuid { get; set; }
public string TouchpanelKey { get; set; } = "";
public string Token { get; set; } = null;
public string Id { get; set; }
}
}

View File

@@ -1,21 +0,0 @@
using System.Collections.Generic;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents the data structure for the grant code and UiClient tokens to be stored in the secrets manager
/// </summary>
public class ServerTokenSecrets
{
public string GrantCode { get; set; }
public Dictionary<string, JoinToken> Tokens { get; set; }
public ServerTokenSecrets(string grantCode)
{
GrantCode = grantCode;
Tokens = new Dictionary<string, JoinToken>();
}
}
}

View File

@@ -1,147 +0,0 @@
using System;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.RoomBridges;
using Serilog.Events;
using WebSocketSharp;
using WebSocketSharp.Server;
using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents the behaviour to associate with a UiClient for WebSocket communication
/// </summary>
public class UiClient : WebSocketBehavior
{
public MobileControlSystemController Controller { get; set; }
public string RoomKey { get; set; }
public string ClientId
{
get; private set;
}
private DateTime _connectionTime;
public TimeSpan ConnectedDuration
{
get
{
if (Context.WebSocket.IsAlive)
{
return DateTime.Now - _connectionTime;
}
else
{
return new TimeSpan(0);
}
}
}
public UiClient(string clientId)
{
ClientId = clientId;
}
protected override void OnOpen()
{
base.OnOpen();
var url = Context.WebSocket.Url;
Debug.LogMessage(LogEventLevel.Verbose, "New WebSocket Connection from: {0}", null, url);
var match = Regex.Match(url.AbsoluteUri, "(?:ws|wss):\\/\\/.*(?:\\/mc\\/api\\/ui\\/join\\/)(.*)");
if (!match.Success)
{
_connectionTime = DateTime.Now;
return;
}
var clientId = ClientId;
if (Controller == null)
{
Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Controller is null");
_connectionTime = DateTime.Now;
}
var clientJoinedMessage = new MobileControlMessage
{
Type = "/system/clientJoined",
Content = JToken.FromObject(new
{
clientId,
roomKey = RoomKey,
})
};
Controller.HandleClientMessage(JsonConvert.SerializeObject(clientJoinedMessage));
var bridge = Controller.GetRoomBridge(RoomKey);
if (bridge == null) return;
SendUserCodeToClient(bridge, clientId);
bridge.UserCodeChanged -= Bridge_UserCodeChanged;
bridge.UserCodeChanged += Bridge_UserCodeChanged;
// TODO: Future: Check token to see if there's already an open session using that token and reject/close the session
}
private void Bridge_UserCodeChanged(object sender, EventArgs e)
{
SendUserCodeToClient((MobileControlEssentialsRoomBridge)sender, ClientId);
}
private void SendUserCodeToClient(MobileControlBridgeBase bridge, string clientId)
{
var content = new
{
userCode = bridge.UserCode,
qrUrl = bridge.QrCodeUrl,
};
var message = new MobileControlMessage
{
Type = "/system/userCodeChanged",
ClientId = clientId,
Content = JToken.FromObject(content)
};
Controller.SendMessageObjectToDirectClient(message);
}
protected override void OnMessage(MessageEventArgs e)
{
base.OnMessage(e);
if (e.IsText && e.Data.Length > 0 && Controller != null)
{
// Forward the message to the controller to be put on the receive queue
Controller.HandleClientMessage(e.Data);
}
}
protected override void OnClose(CloseEventArgs e)
{
base.OnClose(e);
Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Closing: {0} reason: {1}", null, e.Code, e.Reason);
}
protected override void OnError(ErrorEventArgs e)
{
base.OnError(e);
Debug.LogMessage(LogEventLevel.Verbose, "WebSocket UiClient Error: {exception} message: {message}", e.Exception, e.Message);
}
}
}

View File

@@ -1,22 +0,0 @@
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Represents an instance of a UiClient and the associated Token
/// </summary>
public class UiClientContext
{
public UiClient Client { get; private set; }
public JoinToken Token { get; private set; }
public UiClientContext(JoinToken token)
{
Token = token;
}
public void SetClient(UiClient client)
{
Client = client;
}
}
}

View File

@@ -1,22 +0,0 @@
using Newtonsoft.Json;
namespace PepperDash.Essentials.WebSocketServer
{
/// <summary>
/// Class to describe the server version info
/// </summary>
public class Version
{
[JsonProperty("serverVersion")]
public string ServerVersion { get; set; }
[JsonProperty("serverIsRunningOnProcessorHardware")]
public bool ServerIsRunningOnProcessorHardware { get; private set; }
public Version()
{
ServerIsRunningOnProcessorHardware = true;
}
}
}