Enhance logging and mobile control functionality

- Added error log level change notification in Debug.cs.
- Updated appdebug command usage to include sink options and timeout parameters in Debug.cs.
- Implemented AddDefaultMessengersForDevice method in IMobileControl interface for better messenger registration.
- Modified EssentialsDevice to create mobile control messengers based on available interfaces.
- Introduced MessengerFactoryRegistry to streamline messenger creation for various device types.
- Refactored MobileControlSystemController to utilize the new messenger registration system and removed redundant setup methods.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Neil Dorin 2026-05-06 13:44:09 -06:00
parent b0525b0f97
commit bc70aa629c
5 changed files with 445 additions and 799 deletions

View file

@ -17,22 +17,10 @@ using PepperDash.Essentials.AppServer;
using PepperDash.Essentials.AppServer.Messengers;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.CrestronIO;
using PepperDash.Essentials.Core.DeviceInfo;
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using PepperDash.Essentials.Core.Lighting;
using PepperDash.Essentials.Core.Monitoring;
using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.Core.Routing;
using PepperDash.Essentials.Core.Shades;
using PepperDash.Essentials.Core.Web;
using PepperDash.Essentials.Devices.Common.AudioCodec;
using PepperDash.Essentials.Devices.Common.Cameras;
using PepperDash.Essentials.Devices.Common.Displays;
using PepperDash.Essentials.Devices.Common.Lighting;
using PepperDash.Essentials.Devices.Common.SoftCodec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Room.MobileControl;
using PepperDash.Essentials.RoomBridges;
using PepperDash.Essentials.Services;
using PepperDash.Essentials.WebApiHandlers;
@ -138,7 +126,7 @@ namespace PepperDash.Essentials
"No system_url value defined in config. Checking for value from SIMPL Bridge."
);
if (!string.IsNullOrEmpty(SystemUrl))
if (string.IsNullOrEmpty(SystemUrl))
{
this.LogError(
"No system_url value defined in config or SIMPL Bridge. Unable to connect to Mobile Control."
@ -254,10 +242,6 @@ namespace PepperDash.Essentials
AddPreActivationAction(() => LinkSystemMonitorToAppServer());
AddPreActivationAction(() => SetupDefaultDeviceMessengers());
AddPreActivationAction(() => SetupDefaultRoomMessengers());
AddPreActivationAction(() => AddWebApiPaths());
AddPreActivationAction(() =>
@ -282,765 +266,36 @@ namespace PepperDash.Essentials
});
}
private void SetupDefaultRoomMessengers()
/// <inheritdoc />
public void AddDefaultMessengersForDevice(EssentialsDevice device, IEnumerable<Type> interfaces = null)
{
this.LogVerbose("Setting up room messengers");
var interfaceSet = interfaces != null ? new HashSet<Type>(interfaces) : [.. device.GetType().GetInterfaces()];
var messengerAdded = false;
foreach (var room in DeviceManager.AllDevices.OfType<IEssentialsRoom>())
foreach (var entry in MessengerFactoryRegistry.Entries)
{
this.LogVerbose(
"Setting up room messengers for room: {key}",
room.Key
);
if (interfaceSet != null && !interfaceSet.Contains(entry.InterfaceType))
continue;
var messenger = new MobileControlEssentialsRoomBridge(room);
if (!entry.Matches(device))
continue;
messenger.AddParent(this);
var messenger = entry.Factory(device, $"/device/{device.Key}", Key);
_roomBridges.Add(messenger);
if (messenger == null)
continue;
AddDefaultDeviceMessenger(messenger);
this.LogVerbose(
"Attempting to set up default room messengers for room: {0}",
room.Key
);
if (room is IRoomEventSchedule)
{
this.LogInformation("Setting up event schedule messenger for room: {key}", room.Key);
var scheduleMessenger = new RoomEventScheduleMessenger(
$"{room.Key}-schedule-{Key}",
string.Format("/room/{0}", room.Key),
room as IRoomEventSchedule
);
AddDefaultDeviceMessenger(scheduleMessenger);
}
if (room is ITechPassword)
{
this.LogInformation("Setting up tech password messenger for room: {key}", room.Key);
var techPasswordMessenger = new ITechPasswordMessenger(
$"{room.Key}-techPassword-{Key}",
string.Format("/room/{0}", room.Key),
room as ITechPassword
);
AddDefaultDeviceMessenger(techPasswordMessenger);
}
if (room is IShutdownPromptTimer)
{
this.LogInformation("Setting up shutdown prompt timer messenger for room: {key}", this, room.Key);
var shutdownPromptTimerMessenger = new IShutdownPromptTimerMessenger(
$"{room.Key}-shutdownPromptTimer-{Key}",
string.Format("/room/{0}", room.Key),
room as IShutdownPromptTimer
);
AddDefaultDeviceMessenger(shutdownPromptTimerMessenger);
}
if (room is ILevelControls levelControls)
{
this.LogInformation("Setting up level controls messenger for room: {key}", this, room.Key);
var levelControlsMessenger = new ILevelControlsMessenger(
$"{room.Key}-levelControls-{Key}",
$"/room/{room.Key}",
levelControls
);
AddDefaultDeviceMessenger(levelControlsMessenger);
}
messengerAdded = true;
}
}
/// <summary>
/// Set up the messengers for each device type
/// </summary>
private void SetupDefaultDeviceMessengers()
{
bool messengerAdded = false;
var allDevices = DeviceManager.AllDevices.Where((d) => !(d is IEssentialsRoom));
this.LogInformation(
"All Devices that aren't rooms count: {0}",
allDevices?.Count()
);
var count = allDevices.Count();
foreach (var device in allDevices)
if (!messengerAdded)
{
try
{
this.LogVerbose(
"Attempting to set up device messengers for {deviceKey}",
device.Key
);
// StatusMonitorBase which is prop of ICommunicationMonitor is not a PepperDash.Core.Device, but is in the device array
if (device is ICommunicationMonitor)
{
this.LogVerbose(
"Checking if {deviceKey} implements ICommunicationMonitor",
device.Key
);
if (!(device is ICommunicationMonitor commMonitor))
{
this.LogDebug(
"{deviceKey} does not implement ICommunicationMonitor. Skipping CommunicationMonitorMessenger",
device.Key
);
this.LogDebug("Created all messengers for {deviceKey}. Devices Left: {deviceCount}", device.Key, --count);
continue;
}
this.LogDebug(
"Adding CommunicationMonitorMessenger for {deviceKey}",
device.Key
);
var commMessenger = new ICommunicationMonitorMessenger(
$"{device.Key}-commMonitor-{Key}",
string.Format("/device/{0}", device.Key),
commMonitor
);
AddDefaultDeviceMessenger(commMessenger);
messengerAdded = true;
}
// Default to IHasCameraControls if CameraBase and IHasCameraControls
if (device is CameraBase cameraDevice && !(device is IHasCameraControls))
{
this.LogVerbose(
"Adding CameraBaseMessenger for {deviceKey}",
device.Key
);
var cameraMessenger = new CameraBaseMessenger<CameraBase>(
$"{device.Key}-cameraBase-{Key}",
cameraDevice,
$"/device/{device.Key}"
);
AddDefaultDeviceMessenger(cameraMessenger);
messengerAdded = true;
}
if (device is IHasCameraControls cameraControlDev)
{
this.LogVerbose(
"Adding IHasCamerasWithControlMessenger for {deviceKey}",
device.Key
);
var cameraControlMessenger = new CameraBaseMessenger<IHasCameraControls>(
$"{device.Key}-hasCamerasWithControls-{Key}",
cameraControlDev,
$"/device/{device.Key}"
);
AddDefaultDeviceMessenger(cameraControlMessenger);
messengerAdded = true;
}
if (device is BlueJeansPc)
{
this.LogVerbose(
"Adding IRunRouteActionMessnger for {deviceKey}",
device.Key
);
var routeMessenger = new RunRouteActionMessenger(
$"{device.Key}-runRouteAction-{Key}",
device as BlueJeansPc,
$"/device/{device.Key}"
);
AddDefaultDeviceMessenger(routeMessenger);
messengerAdded = true;
}
if (device is ITvPresetsProvider)
{
this.LogVerbose(
"Trying to cast to ITvPresetsProvider for {deviceKey}",
device.Key
);
var presetsDevice = device as ITvPresetsProvider;
this.LogVerbose(
"Adding ITvPresetsProvider for {deviceKey}",
device.Key
);
var presetsMessenger = new DevicePresetsModelMessenger(
$"{device.Key}-presets-{Key}",
$"/device/{device.Key}",
presetsDevice
);
AddDefaultDeviceMessenger(presetsMessenger);
messengerAdded = true;
}
if (device is DisplayBase)
{
this.LogVerbose("Adding actions for device: {0}", device.Key);
var dbMessenger = new DisplayBaseMessenger(
$"{device.Key}-displayBase-{Key}",
$"/device/{device.Key}",
device as DisplayBase
);
AddDefaultDeviceMessenger(dbMessenger);
messengerAdded = true;
}
if (device is TwoWayDisplayBase twoWayDisplay)
{
this.LogVerbose(
"Adding TwoWayDisplayBase for {deviceKey}",
device.Key
);
var twoWayDisplayMessenger = new TwoWayDisplayBaseMessenger(
$"{device.Key}-twoWayDisplay-{Key}",
string.Format("/device/{0}", device.Key),
twoWayDisplay
);
AddDefaultDeviceMessenger(twoWayDisplayMessenger);
messengerAdded = true;
}
if (device is IBasicVolumeControls)
{
var deviceKey = device.Key;
this.LogVerbose(
"Adding IBasicVolumeControls for {deviceKey}",
deviceKey
);
var volControlDevice = device as IBasicVolumeControls;
var messenger = new DeviceVolumeMessenger(
$"{device.Key}-volume-{Key}",
string.Format("/device/{0}", deviceKey),
volControlDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IBasicVideoMuteWithFeedback)
{
var deviceKey = device.Key;
this.LogVerbose(
"Adding IBasicVideoMuteWithFeedback for {deviceKey}",
deviceKey
);
var videoMuteControlDevice = device as IBasicVideoMuteWithFeedback;
var messenger = new IBasicVideoMuteWithFeedbackMessenger(
$"{device.Key}-videoMute-{Key}",
string.Format("/device/{0}", deviceKey),
videoMuteControlDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is ILightingScenes || device is LightingBase)
{
var deviceKey = device.Key;
this.LogVerbose(
"Adding LightingBaseMessenger for {deviceKey}",
deviceKey
);
var lightingDevice = device as ILightingScenes;
var messenger = new ILightingScenesMessenger(
$"{device.Key}-lighting-{Key}",
lightingDevice,
string.Format("/device/{0}", deviceKey)
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IShadesOpenCloseStop)
{
var deviceKey = device.Key;
var shadeDevice = device as IShadesOpenCloseStop;
this.LogVerbose(
"Adding ShadeBaseMessenger for {deviceKey}",
deviceKey
);
var messenger = new IShadesOpenCloseStopMessenger(
$"{device.Key}-shades-{Key}",
shadeDevice,
string.Format("/device/{0}", deviceKey)
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is VideoCodecBase codec)
{
this.LogVerbose(
"Adding VideoCodecBaseMessenger for {deviceKey}", codec.Key);
var messenger = new VideoCodecBaseMessenger(
$"{codec.Key}-videoCodec-{Key}",
codec,
$"/device/{codec.Key}"
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is AudioCodecBase audioCodec)
{
this.LogVerbose(
"Adding AudioCodecBaseMessenger for {deviceKey}", audioCodec.Key
);
var messenger = new AudioCodecBaseMessenger(
$"{audioCodec.Key}-audioCodec-{Key}",
audioCodec,
$"/device/{audioCodec.Key}"
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is ISetTopBoxControls stbDevice)
{
this.LogVerbose(
"Adding ISetTopBoxControlMessenger for {deviceKey}"
);
var messenger = new ISetTopBoxControlsMessenger(
$"{device.Key}-stb-{Key}",
$"/device/{device.Key}",
stbDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IChannel channelDevice)
{
this.LogVerbose(
"Adding IChannelMessenger for {deviceKey}", device.Key
);
var messenger = new IChannelMessenger(
$"{device.Key}-channel-{Key}",
$"/device/{device.Key}",
channelDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IColor colorDevice)
{
this.LogVerbose("Adding IColorMessenger for {deviceKey}", device.Key);
var messenger = new IColorMessenger(
$"{device.Key}-color-{Key}",
$"/device/{device.Key}",
colorDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IDPad dPadDevice)
{
this.LogVerbose("Adding IDPadMessenger for {deviceKey}", device.Key);
var messenger = new IDPadMessenger(
$"{device.Key}-dPad-{Key}",
$"/device/{device.Key}",
dPadDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is INumericKeypad nkDevice)
{
this.LogVerbose("Adding INumericKeyapdMessenger for {deviceKey}", device.Key);
var messenger = new INumericKeypadMessenger(
$"{device.Key}-numericKeypad-{Key}",
$"/device/{device.Key}",
nkDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IHasPowerControl pcDevice)
{
this.LogVerbose("Adding IHasPowerControlMessenger for {deviceKey}", device.Key);
var messenger = new IHasPowerMessenger(
$"{device.Key}-powerControl-{Key}",
$"/device/{device.Key}",
pcDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IHasPowerControlWithFeedback powerControl)
{
var deviceKey = device.Key;
this.LogVerbose(
"Adding IHasPowerControlWithFeedbackMessenger for {deviceKey}",
deviceKey
);
var messenger = new IHasPowerControlWithFeedbackMessenger(
$"{device.Key}-powerFeedback-{Key}",
string.Format("/device/{0}", deviceKey),
powerControl
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is ITransport transportDevice)
{
this.LogVerbose(
"Adding ITransportMessenger for {deviceKey}", device.Key
);
var messenger = new ITransportMessenger(
$"{device.Key}-transport-{Key}",
$"/device/{device.Key}",
transportDevice
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is ICurrentSources currentSources)
{
this.LogVerbose("Adding CurrentSourcesMessenger for {deviceKey}", device.Key);
var messenger = new ICurrentSourcesMessenger($"{device.Key}-currentSources-{Key}", $"/device/{device.Key}", currentSources);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is ISwitchedOutput switchedDevice)
{
this.LogVerbose(
"Adding ISwitchedOutputMessenger for {deviceKey}", device.Key
);
var messenger = new ISwitchedOutputMessenger(
$"{device.Key}-switchedOutput-{Key}",
switchedDevice,
$"/device/{device.Key}"
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IDeviceInfoProvider provider)
{
this.LogVerbose("Adding IHasDeviceInfoMessenger for {deviceKey}", device.Key
);
var messenger = new IDeviceInfoProviderMessenger(
$"{device.Key}-deviceInfo-{Key}",
$"/device/{device.Key}",
provider
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is ILevelControls levelControls)
{
this.LogVerbose(
"Adding LevelControlsMessenger for {deviceKey}", device.Key
);
var messenger = new ILevelControlsMessenger(
$"{device.Key}-levelControls-{Key}",
$"/device/{device.Key}",
levelControls
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IHasInputs<string> stringInputs)
{
this.LogVerbose("Adding InputsMessenger<string> for {deviceKey}", device.Key);
var messenger = new IHasInputsMessenger<string>(
$"{device.Key}-inputs-{Key}",
$"/device/{device.Key}",
stringInputs
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IHasInputs<byte> byteInputs)
{
this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key);
var messenger = new IHasInputsMessenger<byte>(
$"{device.Key}-inputs-{Key}",
$"/device/{device.Key}",
byteInputs
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IHasInputs<int> intInputs)
{
this.LogVerbose("Adding InputsMessenger for {deviceKey}", device.Key);
var messenger = new IHasInputsMessenger<int>(
$"{device.Key}-inputs-{Key}",
$"/device/{device.Key}",
intInputs
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IMatrixRouting matrix)
{
this.LogVerbose(
"Adding IMatrixRoutingMessenger for {deviceKey}",
device.Key
);
var messenger = new IMatrixRoutingMessenger(
$"{device.Key}-matrixRouting",
$"/device/{device.Key}",
matrix
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is ITemperatureSensor tempSensor)
{
this.LogVerbose(
"Adding ITemperatureSensor for {deviceKey}",
device.Key
);
var messenger = new ITemperatureSensorMessenger(
$"{device.Key}-tempSensor",
tempSensor,
$"/device/{device.Key}"
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IHumiditySensor humSensor)
{
this.LogVerbose(
"Adding IHumiditySensor for {deviceKey}",
device.Key
);
var messenger = new IHumiditySensorMessenger(
$"{device.Key}-humiditySensor",
humSensor,
$"/device/{device.Key}"
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IEssentialsRoomCombiner roomCombiner)
{
this.LogVerbose(
"Adding IEssentialsRoomCombinerMessenger for {deviceKey}", device.Key
);
var messenger = new IEssentialsRoomCombinerMessenger(
$"{device.Key}-roomCombiner-{Key}",
$"/device/{device.Key}",
roomCombiner
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IProjectorScreenLiftControl screenLiftControl)
{
this.LogVerbose("Adding IProjectorScreenLiftControlMessenger for {deviceKey}", device.Key
);
var messenger = new IProjectorScreenLiftControlMessenger(
$"{device.Key}-screenLiftControl-{Key}",
$"/device/{device.Key}",
screenLiftControl
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IDspPresets dspPresets)
{
this.LogVerbose("Adding IDspPresetsMessenger for {deviceKey}", device.Key
);
var messenger = new IDspPresetsMessenger(
$"{device.Key}-dspPresets-{Key}",
$"/device/{device.Key}",
dspPresets
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
if (device is IHasCamerasWithControls cameras2)
{
this.LogVerbose("Adding IHasCamerasWithControlsMessenger for {deviceKey}", device.Key
);
var messenger = new IHasCamerasWithControlMessenger(
$"{device.Key}-cameras-{Key}",
$"/device/{device.Key}",
cameras2
);
AddDefaultDeviceMessenger(messenger);
messengerAdded = true;
}
this.LogVerbose("Trying to cast to generic device for device: {key}", device.Key);
if (device is EssentialsDevice)
{
if (!(device is EssentialsDevice genericDevice) || messengerAdded)
{
this.LogVerbose(
"Skipping GenericMessenger for {deviceKey}. Messenger(s) Added: {messengersAdded}.",
device.Key,
messengerAdded
);
this.LogDebug(
"AllDevices Completed a device. Devices Left: {count}",
--count
);
continue;
}
this.LogDebug(
"Adding GenericMessenger for {deviceKey}",
this,
genericDevice?.Key
);
AddDefaultDeviceMessenger(
new GenericMessenger(
genericDevice.Key + "-" + Key + "-generic",
genericDevice,
string.Format("/device/{0}", genericDevice.Key)
)
);
}
else
{
this.LogVerbose(
"Not Essentials Device. Skipping GenericMessenger for {deviceKey}",
device.Key
);
}
this.LogDebug(
"AllDevices Completed a device. Devices Left: {count}",
--count
);
}
catch (Exception ex)
{
this.LogException(ex, "Exception setting up default device messengers");
}
this.LogDebug("Adding GenericMessenger for {deviceKey}", device.Key);
AddDefaultDeviceMessenger(new GenericMessenger(
$"{device.Key}-{Key}-generic",
device,
$"/device/{device.Key}"));
}
}