Compare commits

...

10 Commits

Author SHA1 Message Date
Neil Dorin
403c03491c Merge pull request #1245 from PepperDash/fix-add-client
Update `mobileadduiclient` command & `CrestronGenericBaseDevice.CustomActivate` method
2025-04-08 12:47:08 -06:00
Andrew Welker
3770c2a47d fix: call the EssentialsDevice custom activate
`CrestronGenericBaseDevice` was NOT calling `base.CustomActivate()` in
it's `CustomActivate` override, causing the
`CreateMobileControlMessengers` method to not be called as expected when
plugin devices were inheriting from `CrestronGenericBaseDevice` or
`CrestronGenericBridgeableBaseDevice`.
2025-04-08 13:35:58 -05:00
Andrew Welker
5f4a1f768e fix: check for grant code in mobileadduiclient
If the grant code was not provided, the `mobileadduiclient` console
command would fail silently. The command now checks that the correct
number of arguments was provided and prints an error to the console of
one is missing
2025-04-08 13:32:50 -05:00
Neil Dorin
7eed7866f1 Merge pull request #1243 from PepperDash/routing-fixes
Routing fixes
2025-04-04 09:50:27 -06:00
Andrew Welker
c5403f33c5 fix: add previous condition back to the flag check
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-04 10:49:04 -05:00
Andrew Welker
c9f10ecb90 build: delete clz files on build 2025-04-04 08:09:42 -05:00
Andrew Welker
ef2da21c2a chore: remove old InRoomPc class
class has moved to Devices.Common library
2025-04-04 08:09:32 -05:00
Andrew Welker
b0920746d1 feat: check base folder for cplz and ir files
In an effort to make things easier for devs and end users, the plugin loading logic will now find .cplz files that are in the `Global.FilePathPrefix` base folder (/user/program{programNumber}/` on an appliance, `/user/` on a server). The same applies for IR files. This should make it so that individual plugin cplzs can be loaded via the VC-4 web interface.
2025-04-04 08:09:24 -05:00
Andrew Welker
b531d724ff fix: add OverrideType property to TieLineConfig
The TielineConfig had no property for the `type` property from an Essentials configuration file to be deserialized into. This has been corrected so that the `type` property in a Tieline JSON configuration is now respected and used to build the tieline.
2025-04-04 00:04:53 -05:00
Andrew Welker
1b17d92ee0 fix: Essentials Routing now checks for SecondaryAudio if necessary
To support NVX Routing, checking for the SecondaryAudio routing type is necessary to find the correct path through the system for audio.
2025-04-04 00:03:21 -05:00
9 changed files with 103 additions and 106 deletions

View File

@@ -1,5 +1,9 @@
<Project>
<ItemGroup>
<ItemGroup>
<None Include="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).clz" Condition="$(ProjectType) == 'Library'">
<Pack>true</Pack>
<PackagePath>build;</PackagePath>
</None>
<None Include="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz" Condition="$(ProjectType) == 'Program'">
<Pack>true</Pack>
<PackagePath>build;</PackagePath>
@@ -9,30 +13,41 @@
<PackagePath>build;</PackagePath>
</None>
</ItemGroup>
<PropertyGroup Condition="$(ProjectType) == 'Library'">
<FileName>$(TargetDir)$(TargetName).$(Version).$(TargetFramework).clz</FileName>
</PropertyGroup>
<PropertyGroup Condition="$(ProjectType) == 'ProgramLibrary'">
<FileName>$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz</FileName>
</PropertyGroup>
<PropertyGroup Condition="$(ProjectType) == 'Program'">
<FileName>$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz</FileName>
</PropertyGroup>
<Target Name="DeleteCPLZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != '' And Exists($(FileName))">
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz">
<Target Name="DeleteCLZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'Library' And $(TargetDir) != '' And Exists($(FileName))">
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).clz">
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
</Delete>
<Message Text="Deleted files: '@(DeletedList)'" />
</Target>
<Target Name="CreateCPLZ" AfterTargets="Build" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''" DependsOnTargets="DeleteCPLZ">
<Message Text="Creating CPLZ $(TargetDir)"></Message>
<MakeDir Directories="$(PackageOutputPath)" Condition="!Exists($(PackageOutputPath))" />
<ZipDirectory SourceDirectory="$(TargetDir)" DestinationFile="$(PackageOutputPath)\$(TargetName).$(Version).$(TargetFramework).cplz" Overwrite="true"/>
<Copy SourceFiles="$(PackageOutputPath)\$(TargetName).$(Version).$(TargetFramework).cplz" DestinationFiles="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz" />
</Target>
<Target Name="DeleteCPZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'Program' And $(TargetDir) != '' And Exists($(FileName))">
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cpz">
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
</Delete>
<Message Text="Deleted files: '@(DeletedList)'" />
</Target>
<Target Name="DeleteCPLZ" BeforeTargets="PreBuildEvent" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != '' And Exists($(FileName))">
<Delete Files="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz">
<Output TaskParameter="DeletedFiles" ItemName="DeletedList"/>
</Delete>
<Message Text="Deleted files: '@(DeletedList)'" />
</Target>
<Target Name="CreateCPLZ" AfterTargets="Build" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''" DependsOnTargets="DeleteCPLZ">
<Message Text="Creating CPLZ $(TargetDir)"></Message>
<MakeDir Directories="$(PackageOutputPath)" Condition="!Exists($(PackageOutputPath))" />
<ZipDirectory SourceDirectory="$(TargetDir)" DestinationFile="$(PackageOutputPath)\$(TargetName).$(Version).$(TargetFramework).cplz" Overwrite="true"/>
<Copy SourceFiles="$(PackageOutputPath)\$(TargetName).$(Version).$(TargetFramework).cplz" DestinationFiles="$(TargetDir)$(TargetName).$(Version).$(TargetFramework).cplz" />
</Target>
<Target Name="Copy CLZ" AfterTargets="SimplSharpPostProcess" Condition="($(ProjectType) == 'Library')">
<Message Text="Copying CLZ"></Message>
<Move SourceFiles="$(TargetDir)\$(TargetName).clz" DestinationFiles="$(TargetDir)\$(TargetName).$(Version).$(TargetFramework).clz"/>

View File

@@ -104,7 +104,7 @@ namespace PepperDash.Essentials.Core
Hardware.OnlineStatusChange += Hardware_OnlineStatusChange;
CommunicationMonitor.Start();
return true;
return base.CustomActivate();
}
/// <summary>

View File

@@ -12,6 +12,8 @@ using PepperDash.Essentials.Core.Config;
using PepperDash.Core;
using Serilog.Events;
using System.IO;
using PepperDash.Core.Logging;
namespace PepperDash.Essentials.Core
{
@@ -69,7 +71,26 @@ namespace PepperDash.Essentials.Core
return;
}
var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value<string>();
// var filePath = Global.FilePathPrefix + "ir" + Global.DirectorySeparator + config.Properties["control"]["irFile"].Value<string>();
var fileName = config.Properties["control"]["irFile"].Value<string>();
var files = Directory.GetFiles(Global.FilePathPrefix, fileName, SearchOption.AllDirectories);
if(files.Length == 0)
{
this.LogError("IR file {fileName} not found in {path}", fileName, Global.FilePathPrefix);
return;
}
if(files.Length > 1)
{
this.LogError("IR file {fileName} found in multiple locations: {files}", fileName, files);
return;
}
var filePath = files[0];
Debug.LogMessage(LogEventLevel.Debug, "*************Attempting to load IR file: {0}***************", filePath);
LoadDriver(filePath);

View File

@@ -1,81 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharpPro;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Core;
using Serilog.Events;
namespace PepperDash.Essentials.Core.Devices
{
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
public class InRoomPc : EssentialsDevice, IHasFeedback, IRoutingOutputs, IAttachVideoStatus, IUiDisplayInfo, IUsageTracking
{
public uint DisplayUiType { get { return DisplayUiConstants.TypeLaptop; } }
public string IconName { get; set; }
public BoolFeedback HasPowerOnFeedback { get; private set; }
public RoutingOutputPort AnyVideoOut { get; private set; }
#region IRoutingOutputs Members
/// <summary>
/// Options: hdmi
/// </summary>
public RoutingPortCollection<RoutingOutputPort> OutputPorts { get; private set; }
#endregion
public InRoomPc(string key, string name)
: base(key, name)
{
IconName = "PC";
HasPowerOnFeedback = new BoolFeedback("HasPowerFeedback",
() => this.GetVideoStatuses() != VideoStatusOutputs.NoStatus);
OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
OutputPorts.Add(AnyVideoOut = new RoutingOutputPort(RoutingPortNames.AnyVideoOut, eRoutingSignalType.Audio | eRoutingSignalType.Video,
eRoutingPortConnectionType.None, 0, this));
}
#region IHasFeedback Members
/// <summary>
/// Passes through the VideoStatuses list
/// </summary>
public FeedbackCollection<Feedback> Feedbacks
{
get
{
var newList = new FeedbackCollection<Feedback>();
newList.AddRange(this.GetVideoStatuses().ToList());
return newList;
}
}
#endregion
#region IUsageTracking Members
public UsageTracking UsageTracker { get; set; }
#endregion
}
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
public class InRoomPcFactory : EssentialsDeviceFactory<InRoomPc>
{
public InRoomPcFactory()
{
TypeNames = new List<string>() { "inroompc" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new InRoomPc Device");
return new InRoomPc(dc.Key, dc.Name);
}
}
}

View File

@@ -2,13 +2,14 @@
using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
// using Crestron.SimplSharp.CrestronIO;
using System.Reflection;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using Serilog.Events;
using Newtonsoft.Json;
using System.IO;
namespace PepperDash.Essentials
{
@@ -283,11 +284,21 @@ namespace PepperDash.Essentials
/// </summary>
static void UnzipAndMoveCplzArchives()
{
Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from plugins folder...");
var di = new DirectoryInfo(_pluginDirectory);
var zFiles = di.GetFiles("*.cplz");
Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from user folder...");
//var di = new DirectoryInfo(_pluginDirectory);
//var zFiles = di.GetFiles("*.cplz");
if (zFiles.Length > 0)
//// Find cplz files at the root of the user folder. Makes development/testing easier for VC-4, and helps with mistakes by end users
//var userDi = new DirectoryInfo(Global.FilePathPrefix);
//var userZFiles = userDi.GetFiles("*.cplz");
Debug.LogInformation("Checking {folder} for .cplz files", Global.FilePathPrefix);
var cplzFiles = Directory.GetFiles(Global.FilePathPrefix, "*.cplz", SearchOption.AllDirectories)
.Select(f => new FileInfo(f))
.ToArray();
if (cplzFiles.Length > 0)
{
if (!Directory.Exists(_loadedPluginsDirectoryPath))
{
@@ -295,12 +306,12 @@ namespace PepperDash.Essentials
}
}
foreach (var zfi in zFiles)
foreach (var zfi in cplzFiles)
{
Directory.CreateDirectory(_tempDirectory);
var tempDi = new DirectoryInfo(_tempDirectory);
Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.Name);
Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.FullName);
var result = CrestronZIP.Unzip(zfi.FullName, tempDi.FullName);
Debug.LogMessage(LogEventLevel.Information, "UnZip Result: {0}", result.ToString());

View File

@@ -1,4 +1,5 @@
using PepperDash.Essentials.Core.Queues;
using Crestron.SimplSharpPro.Keypads;
using PepperDash.Essentials.Core.Queues;
using PepperDash.Essentials.Core.Routing;
using Serilog.Events;
using System;
@@ -88,9 +89,17 @@ namespace PepperDash.Essentials.Core
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key);
var audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio);
RouteDescriptor audioRouteDescriptor;
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort);
if (signalType.HasFlag(eRoutingSignalType.SecondaryAudio))
{
audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.SecondaryAudio);
} else
{
audioRouteDescriptor = new RouteDescriptor(source, destination, destinationPort, eRoutingSignalType.Audio);
}
var audioSuccess = destination.GetRouteToSource(source, null, null, signalType.HasFlag(eRoutingSignalType.SecondaryAudio) ? eRoutingSignalType.SecondaryAudio : eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort);
if (!audioSuccess)
Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key);
@@ -268,13 +277,12 @@ namespace PepperDash.Essentials.Core
if (destinationPort == null)
{
destinationTieLines = TieLineCollection.Default.Where(t =>
t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo)));
t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type.HasFlag(signalType) || signalType == eRoutingSignalType.AudioVideo));
}
else
{
destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo)));
destinationTieLines = TieLineCollection.Default.Where(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && (t.Type.HasFlag(signalType)));
}
// find the TieLine without a port

View File

@@ -57,6 +57,16 @@ namespace PepperDash.Essentials.Core
DestinationPort = destinationPort;
}
/// <summary>
/// Creates a tie line with an overriding Type. See help for OverrideType property for info
/// </summary>
/// <param name="overrideType">The signal type to limit the link to. Overrides DestinationPort.Type</param>
public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType? overrideType) :
this(sourcePort, destinationPort)
{
OverrideType = overrideType;
}
/// <summary>
/// Creates a tie line with an overriding Type. See help for OverrideType property for info
/// </summary>

View File

@@ -7,6 +7,7 @@ using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
@@ -23,6 +24,10 @@ namespace PepperDash.Essentials.Core.Config
public string DestinationCard { get; set; }
public string DestinationPort { get; set; }
[JsonProperty("type", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(StringEnumConverter))]
public eRoutingSignalType? OverrideType { get; set; }
/// <summary>
/// Returns the appropriate tie line for either a card-based device or
/// regular device with ports on-device.
@@ -65,7 +70,7 @@ namespace PepperDash.Essentials.Core.Config
return null;
}
return new TieLine(sourceOutputPort, destinationInputPort);
return new TieLine(sourceOutputPort, destinationInputPort, OverrideType);
}
void LogError(string msg)

View File

@@ -679,6 +679,14 @@ namespace PepperDash.Essentials.WebSocketServer
}
var values = s.Split(' ');
if(values.Length < 2)
{
CrestronConsole.ConsoleCommandResponse("Invalid number of arguments. Please provide a room key and a grant code");
return;
}
var roomKey = values[0];
var grantCode = values[1];