mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-08-31 19:08:29 +00:00
Merge pull request #1194 from PepperDash/feature-2.0.0/routing-extension-changes
Feature 2.0.0/routing extension changes
This commit is contained in:
commit
49852d25e8
62 changed files with 1202 additions and 937 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -391,3 +391,4 @@ FodyWeavers.xsd
|
||||||
essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/PepperDash_Essentials_Interfaces.csproj
|
essentials-framework/Essentials Interfaces/PepperDash_Essentials_Interfaces/PepperDash_Essentials_Interfaces.csproj
|
||||||
.DS_Store
|
.DS_Store
|
||||||
/._PepperDash.Essentials.sln
|
/._PepperDash.Essentials.sln
|
||||||
|
.vscode/settings.json
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
using Crestron.SimplSharpPro;
|
using Crestron.SimplSharpPro;
|
||||||
using Crestron.SimplSharpPro.DeviceSupport;
|
using Crestron.SimplSharpPro.DeviceSupport;
|
||||||
using Crestron.SimplSharpPro.EthernetCommunication;
|
using Crestron.SimplSharpPro.EthernetCommunication;
|
||||||
|
|
@ -168,7 +168,7 @@ namespace PepperDash.Essentials.Core.Bridges
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, this, "Linking Device: '{0}'", device.Key);
|
Debug.LogMessage(LogEventLevel.Debug, this, "Linking Device: '{0}'", device.Key);
|
||||||
|
|
||||||
if (!typeof(IBridgeAdvanced).IsAssignableFrom(device.GetType().GetCType()))
|
if (!typeof(IBridgeAdvanced).IsAssignableFrom(device.GetType().GetType()))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, this,
|
Debug.LogMessage(LogEventLevel.Information, this,
|
||||||
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
|
"{0} is not compatible with this bridge type. Please use 'eiscapi' instead, or updae the device.",
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ namespace PepperDash.Essentials.Core
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes));
|
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", ComTextHelper.GetEscapedText(bytes));
|
||||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
var textHandler = TextReceived;
|
var textHandler = TextReceived;
|
||||||
if (textHandler != null)
|
if (textHandler != null)
|
||||||
|
|
@ -108,7 +109,10 @@ namespace PepperDash.Essentials.Core
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s);
|
Debug.LogMessage(LogEventLevel.Information, this, "Received: '{0}'", s);
|
||||||
textHandler(this, new GenericCommMethodReceiveTextArgs(s));
|
textHandler(this, new GenericCommMethodReceiveTextArgs(s));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, this, "Received data but no handler is registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Deactivate()
|
public override bool Deactivate()
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
using System;
|
using Crestron.SimplSharp.Net.Http;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharp.Net.Http;
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
[Obsolete("Please use the builtin HttpClient class instead: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines")]
|
[Obsolete("Please use the builtin HttpClient class instead: https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines")]
|
||||||
public class GenericHttpClient : Device, IBasicCommunication
|
public class GenericHttpClient : Device, IBasicCommunication
|
||||||
{
|
{
|
||||||
public HttpClient Client;
|
public HttpClient Client;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Crestron.SimplSharpPro;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core.Config
|
||||||
|
{
|
||||||
|
public class AudioControlPointListItem
|
||||||
|
{
|
||||||
|
[JsonProperty("levelControls")]
|
||||||
|
public Dictionary<string, LevelControlListItem> LevelControls { get; set; } = new Dictionary<string, LevelControlListItem>();
|
||||||
|
|
||||||
|
[JsonProperty("presets")]
|
||||||
|
public Dictionary<string, PresetListItem> Presets { get; set; } = new Dictionary<string, PresetListItem>();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,10 @@ namespace PepperDash.Essentials.Core.Config
|
||||||
public Dictionary<string, Dictionary<string, SourceListItem>> SourceLists { get; set; }
|
public Dictionary<string, Dictionary<string, SourceListItem>> SourceLists { get; set; }
|
||||||
|
|
||||||
[JsonProperty("destinationLists")]
|
[JsonProperty("destinationLists")]
|
||||||
public Dictionary<string, Dictionary<string,DestinationListItem>> DestinationLists { get; set; }
|
public Dictionary<string, Dictionary<string, DestinationListItem>> DestinationLists { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("audioControlPointLists")]
|
||||||
|
public Dictionary<string, AudioControlPointListItem> AudioControlPointLists { get; set; }
|
||||||
|
|
||||||
[JsonProperty("tieLines")]
|
[JsonProperty("tieLines")]
|
||||||
public List<TieLineConfig> TieLines { get; set; }
|
public List<TieLineConfig> TieLines { get; set; }
|
||||||
|
|
@ -37,6 +40,7 @@ namespace PepperDash.Essentials.Core.Config
|
||||||
Devices = new List<DeviceConfig>();
|
Devices = new List<DeviceConfig>();
|
||||||
SourceLists = new Dictionary<string, Dictionary<string, SourceListItem>>();
|
SourceLists = new Dictionary<string, Dictionary<string, SourceListItem>>();
|
||||||
DestinationLists = new Dictionary<string, Dictionary<string, DestinationListItem>>();
|
DestinationLists = new Dictionary<string, Dictionary<string, DestinationListItem>>();
|
||||||
|
AudioControlPointLists = new Dictionary<string, AudioControlPointListItem>();
|
||||||
TieLines = new List<TieLineConfig>();
|
TieLines = new List<TieLineConfig>();
|
||||||
JoinMaps = new Dictionary<string, JObject>();
|
JoinMaps = new Dictionary<string, JObject>();
|
||||||
}
|
}
|
||||||
|
|
@ -55,8 +59,8 @@ namespace PepperDash.Essentials.Core.Config
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a DestinationListItem based on the key
|
/// Retrieves a DestinationListItem based on the key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">key of the item to retrieve</param>
|
/// <param name="key">key of the list to retrieve</param>
|
||||||
/// <returns>DestinationListItem if the key exists, null otherwise</returns>
|
/// <returns>DestinationList if the key exists, null otherwise</returns>
|
||||||
public Dictionary<string, DestinationListItem> GetDestinationListForKey(string key)
|
public Dictionary<string, DestinationListItem> GetDestinationListForKey(string key)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(key) || !DestinationLists.ContainsKey(key))
|
if (string.IsNullOrEmpty(key) || !DestinationLists.ContainsKey(key))
|
||||||
|
|
@ -65,7 +69,20 @@ namespace PepperDash.Essentials.Core.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
return DestinationLists[key];
|
return DestinationLists[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a AudioControlPointList based on the key
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">key of the list to retrieve</param>
|
||||||
|
/// <returns>AudioControlPointList if the key exists, null otherwise</returns>
|
||||||
|
public AudioControlPointListItem GetAudioControlPointListForKey(string key)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(key) || !AudioControlPointLists.ContainsKey(key))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return AudioControlPointLists[key];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks Devices for an item with a Key that matches and returns it if found. Otherwise, retunes null
|
/// Checks Devices for an item with a Key that matches and returns it if found. Otherwise, retunes null
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
|
|
||||||
|
|
||||||
|
using Crestron.SimplSharp;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharp.Reflection;
|
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core.Config
|
namespace PepperDash.Essentials.Core.Config
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the info section of a Config file
|
/// Represents the info section of a Config file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InfoConfig
|
public class InfoConfig
|
||||||
{
|
{
|
||||||
[JsonProperty("name")]
|
[JsonProperty("name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,22 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||||
/// <example>
|
/// <example>
|
||||||
/// See MockDisplay for example implemntation
|
/// See MockDisplay for example implemntation
|
||||||
/// </example>
|
/// </example>
|
||||||
public interface IHasInputs<TKey, TSelector>: IKeyName
|
[Obsolete("Use IHasInputs<T> instead. Will be removed for 2.0 release")]
|
||||||
|
public interface IHasInputs<T, TSelector>: IKeyName
|
||||||
{
|
{
|
||||||
ISelectableItems<TKey> Inputs { get; }
|
ISelectableItems<T> Inputs { get; }
|
||||||
|
}
|
||||||
|
|
||||||
void SetInput(TSelector selector);
|
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a device that has selectable inputs
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">the type to use as the key for each input item. Most likely an enum or string</typeparam>\
|
||||||
|
/// <example>
|
||||||
|
/// See MockDisplay for example implemntation
|
||||||
|
/// </example>
|
||||||
|
public interface IHasInputs<T> : IKeyName
|
||||||
|
{
|
||||||
|
ISelectableItems<T> Inputs { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,10 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||||
void AddDeviceMessenger(IMobileControlMessenger messenger);
|
void AddDeviceMessenger(IMobileControlMessenger messenger);
|
||||||
|
|
||||||
bool CheckForDeviceMessenger(string key);
|
bool CheckForDeviceMessenger(string key);
|
||||||
}
|
|
||||||
|
IMobileControlRoomMessenger GetRoomMessenger(string key);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes a mobile control messenger
|
/// Describes a mobile control messenger
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
using Crestron.SimplSharpPro.DeviceSupport;
|
||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a class that has warm up and cool down
|
||||||
|
/// </summary>
|
||||||
|
public interface IProjectorScreenLiftControl
|
||||||
|
{
|
||||||
|
void Raise();
|
||||||
|
void Lower();
|
||||||
|
BoolFeedback IsInUpPosition { get; }
|
||||||
|
bool InUpPosition { get; }
|
||||||
|
event EventHandler<EventArgs> PositionChanged;
|
||||||
|
string DisplayDeviceKey { get; }
|
||||||
|
eScreenLiftControlType Type { get; } // screen/lift
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum eScreenLiftControlType
|
||||||
|
{
|
||||||
|
lift,
|
||||||
|
screen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,6 @@ namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
|
||||||
Dictionary<TKey, ISelectableItem> Items { get; set; }
|
Dictionary<TKey, ISelectableItem> Items { get; set; }
|
||||||
|
|
||||||
[JsonProperty("currentItem")]
|
[JsonProperty("currentItem")]
|
||||||
string CurrentItem { get; set; }
|
TKey CurrentItem { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
public abstract class AudioControlListItemBase
|
||||||
|
{
|
||||||
|
[JsonProperty("parentDeviceKey")]
|
||||||
|
public string ParentDeviceKey { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("itemKey")]
|
||||||
|
public string ItemKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A name that will override the items's name on the UI
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if the item should be included in the user accessible list
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("includeInUserList")]
|
||||||
|
public bool IncludeInUserList { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to specify the order of the items in the source list when displayed
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("order")]
|
||||||
|
public int Order { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
|
@ -64,7 +64,7 @@ namespace PepperDash.Essentials.Core
|
||||||
action.Params = new object[0];
|
action.Params = new object[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
CType t = obj.GetType();
|
Type t = obj.GetType();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList();
|
var methods = t.GetMethods().Where(m => m.Name == action.MethodName).ToList();
|
||||||
|
|
@ -84,7 +84,18 @@ namespace PepperDash.Essentials.Core
|
||||||
.Select((p, i) => ConvertType(action.Params[i], p.ParameterType))
|
.Select((p, i) => ConvertType(action.Params[i], p.ParameterType))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
Task.Run(() => method.Invoke(obj, convertedParams));
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "Calling method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey);
|
||||||
|
method.Invoke(obj, convertedParams);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(e, "Error invoking method {methodName} on device {deviceKey}", null, method.Name, action.DeviceKey);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name,
|
CrestronConsole.ConsoleCommandResponse("Method {0} successfully called on device {1}", method.Name,
|
||||||
action.DeviceKey);
|
action.DeviceKey);
|
||||||
|
|
@ -123,7 +134,7 @@ namespace PepperDash.Essentials.Core
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
return "{ \"error\":\"No Device\"}";
|
return "{ \"error\":\"No Device\"}";
|
||||||
|
|
||||||
CType t = obj.GetType();
|
Type t = obj.GetType();
|
||||||
// get the properties and set them into a new collection of NameType wrappers
|
// get the properties and set them into a new collection of NameType wrappers
|
||||||
var props = t.GetProperties().Select(p => new PropertyNameType(p, obj));
|
var props = t.GetProperties().Select(p => new PropertyNameType(p, obj));
|
||||||
return JsonConvert.SerializeObject(props, Formatting.Indented);
|
return JsonConvert.SerializeObject(props, Formatting.Indented);
|
||||||
|
|
@ -141,7 +152,7 @@ namespace PepperDash.Essentials.Core
|
||||||
if(dev == null)
|
if(dev == null)
|
||||||
return "{ \"error\":\"No Device\"}";
|
return "{ \"error\":\"No Device\"}";
|
||||||
|
|
||||||
object prop = dev.GetType().GetCType().GetProperty(propertyName).GetValue(dev, null);
|
object prop = dev.GetType().GetType().GetProperty(propertyName).GetValue(dev, null);
|
||||||
|
|
||||||
// var prop = t.GetProperty(propertyName);
|
// var prop = t.GetProperty(propertyName);
|
||||||
if (prop != null)
|
if (prop != null)
|
||||||
|
|
@ -167,7 +178,7 @@ namespace PepperDash.Essentials.Core
|
||||||
return "{ \"error\":\"No Device\"}";
|
return "{ \"error\":\"No Device\"}";
|
||||||
|
|
||||||
// Package up method names using helper objects
|
// Package up method names using helper objects
|
||||||
CType t = obj.GetType();
|
Type t = obj.GetType();
|
||||||
var methods = t.GetMethods()
|
var methods = t.GetMethods()
|
||||||
.Where(m => !m.IsSpecialName)
|
.Where(m => !m.IsSpecialName)
|
||||||
.Select(p => new MethodNameParams(p));
|
.Select(p => new MethodNameParams(p));
|
||||||
|
|
@ -181,7 +192,7 @@ namespace PepperDash.Essentials.Core
|
||||||
return "{ \"error\":\"No Device\"}";
|
return "{ \"error\":\"No Device\"}";
|
||||||
|
|
||||||
// Package up method names using helper objects
|
// Package up method names using helper objects
|
||||||
CType t = obj.GetType();
|
Type t = obj.GetType();
|
||||||
var methods = t.GetMethods()
|
var methods = t.GetMethods()
|
||||||
.Where(m => !m.IsSpecialName)
|
.Where(m => !m.IsSpecialName)
|
||||||
.Where(m => m.GetCustomAttributes(typeof(ApiAttribute), true).Any())
|
.Where(m => m.GetCustomAttributes(typeof(ApiAttribute), true).Any())
|
||||||
|
|
@ -228,7 +239,7 @@ namespace PepperDash.Essentials.Core
|
||||||
Debug.LogMessage(LogEventLevel.Information, dev, " Checking for collection '{0}', index '{1}'", objName, indexStr);
|
Debug.LogMessage(LogEventLevel.Information, dev, " Checking for collection '{0}', index '{1}'", objName, indexStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
CType oType = obj.GetType();
|
Type oType = obj.GetType();
|
||||||
var prop = oType.GetProperty(objName);
|
var prop = oType.GetProperty(objName);
|
||||||
if (prop == null)
|
if (prop == null)
|
||||||
{
|
{
|
||||||
|
|
@ -258,7 +269,7 @@ namespace PepperDash.Essentials.Core
|
||||||
obj = indexedPropInfo.GetValue(collection, new object[] { properParam });
|
obj = indexedPropInfo.GetValue(collection, new object[] { properParam });
|
||||||
}
|
}
|
||||||
// if the index is bad, catch it here.
|
// if the index is bad, catch it here.
|
||||||
catch (Crestron.SimplSharp.Reflection.TargetInvocationException e)
|
catch (TargetInvocationException e)
|
||||||
{
|
{
|
||||||
if (e.InnerException is ArgumentOutOfRangeException)
|
if (e.InnerException is ArgumentOutOfRangeException)
|
||||||
Debug.LogMessage(LogEventLevel.Information, " Index Out of range");
|
Debug.LogMessage(LogEventLevel.Information, " Index Out of range");
|
||||||
|
|
@ -289,7 +300,7 @@ namespace PepperDash.Essentials.Core
|
||||||
//if (obj == null)
|
//if (obj == null)
|
||||||
// return "{\"error\":\"No object found\"}";
|
// return "{\"error\":\"No object found\"}";
|
||||||
|
|
||||||
//CType t = obj.GetType();
|
//Type t = obj.GetType();
|
||||||
|
|
||||||
|
|
||||||
//// get the properties and set them into a new collection of NameType wrappers
|
//// get the properties and set them into a new collection of NameType wrappers
|
||||||
|
|
@ -367,7 +378,7 @@ namespace PepperDash.Essentials.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.All)]
|
[AttributeUsage(AttributeTargets.All)]
|
||||||
public class ApiAttribute : CAttribute
|
public class ApiAttribute : Attribute
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ namespace PepperDash.Essentials.Core
|
||||||
// var dev = GetDeviceForKey(devKey);
|
// var dev = GetDeviceForKey(devKey);
|
||||||
// if(dev != null)
|
// if(dev != null)
|
||||||
// {
|
// {
|
||||||
// var type = dev.GetType().GetCType();
|
// var type = dev.GetType().GetType();
|
||||||
// var methods = type.GetMethods(BindingFlags.Public|BindingFlags.Instance);
|
// var methods = type.GetMethods(BindingFlags.Public|BindingFlags.Instance);
|
||||||
// var sb = new StringBuilder();
|
// var sb = new StringBuilder();
|
||||||
// sb.AppendLine(string.Format("{2} methods on [{0}] ({1}):", dev.Key, type.Name, methods.Length));
|
// sb.AppendLine(string.Format("{2} methods on [{0}] ({1}):", dev.Key, type.Name, methods.Length));
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core.Config;
|
using PepperDash.Essentials.Core.Config;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
|
||||||
{
|
|
||||||
public interface IHasDspPresets
|
|
||||||
{
|
|
||||||
List<IDspPreset> Presets { get; }
|
|
||||||
|
|
||||||
void RecallPreset(IDspPreset preset);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IDspPreset
|
|
||||||
{
|
|
||||||
string Name { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12
src/PepperDash.Essentials.Core/Devices/IDspPresets.cs
Normal file
12
src/PepperDash.Essentials.Core/Devices/IDspPresets.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
using PepperDash.Core;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
public interface IDspPresets
|
||||||
|
{
|
||||||
|
Dictionary<string, IKeyName> Presets { get; }
|
||||||
|
|
||||||
|
void RecallPreset(string key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Crestron.SimplSharpPro.DeviceSupport;
|
|
||||||
using Crestron.SimplSharp.Reflection;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
|
@ -23,7 +21,7 @@ namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
public static void DumpFeedbacksToConsole(this IHasFeedback source, bool getCurrentStates)
|
public static void DumpFeedbacksToConsole(this IHasFeedback source, bool getCurrentStates)
|
||||||
{
|
{
|
||||||
CType t = source.GetType();
|
Type t = source.GetType();
|
||||||
// get the properties and set them into a new collection of NameType wrappers
|
// get the properties and set them into a new collection of NameType wrappers
|
||||||
var props = t.GetProperties().Select(p => new PropertyNameType(p, t));
|
var props = t.GetProperties().Select(p => new PropertyNameType(p, t));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Essentials.Core.Devices;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
public class LevelControlListItem : AudioControlListItemBase
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public IBasicVolumeWithFeedback LevelControl
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_levelControl == null)
|
||||||
|
_levelControl = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IBasicVolumeWithFeedback;
|
||||||
|
return _levelControl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IBasicVolumeWithFeedback _levelControl;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name from the device if it implements IKeyName or else returns the Name property
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("preferredName")]
|
||||||
|
public string PreferredName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Name)) return Name;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (LevelControl is IKeyName namedLevelControl)
|
||||||
|
{
|
||||||
|
if (namedLevelControl == null)
|
||||||
|
return "---";
|
||||||
|
return namedLevelControl.Name;
|
||||||
|
}
|
||||||
|
else return "---";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The key of the device in the DeviceManager for control
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("deviceKey")]
|
||||||
|
public string DeviceKey => DeviceManager.AllDevices.
|
||||||
|
Where(d => d.Key.Contains(ParentDeviceKey) && d.Key.Contains(ItemKey)).FirstOrDefault()?.Key ?? $"{ParentDeviceKey}--{ItemKey}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if the item is a level, mute , or both
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("type")]
|
||||||
|
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
|
||||||
|
public eLevelControlType Type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum eLevelControlType
|
||||||
|
{
|
||||||
|
Level = 0,
|
||||||
|
Mute = 1,
|
||||||
|
LevelAndMute = Level | Mute,
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/PepperDash.Essentials.Core/Devices/PresetListItem.cs
Normal file
45
src/PepperDash.Essentials.Core/Devices/PresetListItem.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PepperDash.Core;
|
||||||
|
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core
|
||||||
|
{
|
||||||
|
public class PresetListItem : AudioControlListItemBase
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public IKeyName Preset
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_preset == null)
|
||||||
|
{
|
||||||
|
var parent = DeviceManager.GetDeviceForKey(ParentDeviceKey) as IDspPresets;
|
||||||
|
if (parent == null || !parent.Presets.ContainsKey(ItemKey))
|
||||||
|
return null;
|
||||||
|
_preset = parent.Presets[ItemKey];
|
||||||
|
}
|
||||||
|
return _preset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private IKeyName _preset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name from the device if it implements IKeyName or else returns the Name property
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("preferredName")]
|
||||||
|
public string PreferredName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Name)) return Name;
|
||||||
|
|
||||||
|
else return Preset.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -266,16 +266,16 @@ namespace PepperDash.Essentials.Core
|
||||||
abstract protected Func<bool> PowerIsOnFeedbackFunc { get; }
|
abstract protected Func<bool> PowerIsOnFeedbackFunc { get; }
|
||||||
|
|
||||||
|
|
||||||
public static MockDisplay DefaultDisplay
|
// public static MockDisplay DefaultDisplay
|
||||||
{
|
// {
|
||||||
get
|
// get
|
||||||
{
|
// {
|
||||||
if (_DefaultDisplay == null)
|
// if (_DefaultDisplay == null)
|
||||||
_DefaultDisplay = new MockDisplay("default", "Default Display");
|
// _DefaultDisplay = new MockDisplay("default", "Default Display");
|
||||||
return _DefaultDisplay;
|
// return _DefaultDisplay;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
static MockDisplay _DefaultDisplay;
|
//static MockDisplay _DefaultDisplay;
|
||||||
|
|
||||||
public TwoWayDisplayBase(string key, string name)
|
public TwoWayDisplayBase(string key, string name)
|
||||||
: base(key, name)
|
: base(key, name)
|
||||||
|
|
|
||||||
|
|
@ -1,237 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharpPro;
|
|
||||||
using Crestron.SimplSharpPro.DeviceSupport;
|
|
||||||
using Crestron.SimplSharpPro.DM;
|
|
||||||
using Crestron.SimplSharpPro.DM.Endpoints;
|
|
||||||
using Crestron.SimplSharpPro.DM.Endpoints.Transmitters;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
|
||||||
using PepperDash.Essentials.Core.Bridges;
|
|
||||||
using PepperDash.Essentials.Core.Config;
|
|
||||||
using Serilog.Events;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
|
||||||
{
|
|
||||||
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
|
|
||||||
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback, IBridgeAdvanced
|
|
||||||
|
|
||||||
{
|
|
||||||
public RoutingInputPort HdmiIn1 { get; private set; }
|
|
||||||
public RoutingInputPort HdmiIn2 { get; private set; }
|
|
||||||
public RoutingInputPort HdmiIn3 { get; private set; }
|
|
||||||
public RoutingInputPort ComponentIn1 { get; private set; }
|
|
||||||
public RoutingInputPort VgaIn1 { get; private set; }
|
|
||||||
|
|
||||||
bool _PowerIsOn;
|
|
||||||
bool _IsWarmingUp;
|
|
||||||
bool _IsCoolingDown;
|
|
||||||
|
|
||||||
protected override Func<bool> PowerIsOnFeedbackFunc
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "*************************************************** Display Power is {0}", _PowerIsOn ? "on" : "off");
|
|
||||||
return _PowerIsOn;
|
|
||||||
};
|
|
||||||
} }
|
|
||||||
protected override Func<bool> IsCoolingDownFeedbackFunc
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "*************************************************** {0}", _IsCoolingDown ? "Display is cooling down" : "Display has finished cooling down");
|
|
||||||
return _IsCoolingDown;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected override Func<bool> IsWarmingUpFeedbackFunc
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "*************************************************** {0}", _IsWarmingUp ? "Display is warming up" : "Display has finished warming up");
|
|
||||||
return _IsWarmingUp;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected override Func<string> CurrentInputFeedbackFunc { get { return () => "Not Implemented"; } }
|
|
||||||
|
|
||||||
int VolumeHeldRepeatInterval = 200;
|
|
||||||
ushort VolumeInterval = 655;
|
|
||||||
ushort _FakeVolumeLevel = 31768;
|
|
||||||
bool _IsMuted;
|
|
||||||
|
|
||||||
public MockDisplay(string key, string name)
|
|
||||||
: base(key, name)
|
|
||||||
{
|
|
||||||
HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
||||||
eRoutingPortConnectionType.Hdmi, null, this);
|
|
||||||
HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
||||||
eRoutingPortConnectionType.Hdmi, null, this);
|
|
||||||
HdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.Audio | eRoutingSignalType.Video,
|
|
||||||
eRoutingPortConnectionType.Hdmi, null, this);
|
|
||||||
ComponentIn1 = new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Video,
|
|
||||||
eRoutingPortConnectionType.Component, null, this);
|
|
||||||
VgaIn1 = new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Video,
|
|
||||||
eRoutingPortConnectionType.Composite, null, this);
|
|
||||||
InputPorts.AddRange(new[] { HdmiIn1, HdmiIn2, HdmiIn3, ComponentIn1, VgaIn1 });
|
|
||||||
|
|
||||||
VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; });
|
|
||||||
MuteFeedback = new BoolFeedback("MuteOn", () => _IsMuted);
|
|
||||||
|
|
||||||
WarmupTime = 10000;
|
|
||||||
CooldownTime = 10000;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PowerOn()
|
|
||||||
{
|
|
||||||
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
|
|
||||||
{
|
|
||||||
_IsWarmingUp = true;
|
|
||||||
IsWarmingUpFeedback.InvokeFireUpdate();
|
|
||||||
// Fake power-up cycle
|
|
||||||
WarmupTimer = new CTimer(o =>
|
|
||||||
{
|
|
||||||
_IsWarmingUp = false;
|
|
||||||
_PowerIsOn = true;
|
|
||||||
IsWarmingUpFeedback.InvokeFireUpdate();
|
|
||||||
PowerIsOnFeedback.InvokeFireUpdate();
|
|
||||||
}, WarmupTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PowerOff()
|
|
||||||
{
|
|
||||||
// If a display has unreliable-power off feedback, just override this and
|
|
||||||
// remove this check.
|
|
||||||
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
|
|
||||||
{
|
|
||||||
_IsCoolingDown = true;
|
|
||||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
|
||||||
// Fake cool-down cycle
|
|
||||||
CooldownTimer = new CTimer(o =>
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Cooldown timer ending");
|
|
||||||
_IsCoolingDown = false;
|
|
||||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
|
||||||
_PowerIsOn = false;
|
|
||||||
PowerIsOnFeedback.InvokeFireUpdate();
|
|
||||||
}, CooldownTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PowerToggle()
|
|
||||||
{
|
|
||||||
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
|
|
||||||
PowerOff();
|
|
||||||
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
|
|
||||||
PowerOn();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExecuteSwitch(object selector)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "ExecuteSwitch: {0}", selector);
|
|
||||||
|
|
||||||
if (!_PowerIsOn)
|
|
||||||
{
|
|
||||||
PowerOn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region IBasicVolumeWithFeedback Members
|
|
||||||
|
|
||||||
public IntFeedback VolumeLevelFeedback { get; private set; }
|
|
||||||
|
|
||||||
public void SetVolume(ushort level)
|
|
||||||
{
|
|
||||||
_FakeVolumeLevel = level;
|
|
||||||
VolumeLevelFeedback.InvokeFireUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MuteOn()
|
|
||||||
{
|
|
||||||
_IsMuted = true;
|
|
||||||
MuteFeedback.InvokeFireUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MuteOff()
|
|
||||||
{
|
|
||||||
_IsMuted = false;
|
|
||||||
MuteFeedback.InvokeFireUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BoolFeedback MuteFeedback { get; private set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region IBasicVolumeControls Members
|
|
||||||
|
|
||||||
public void VolumeUp(bool pressRelease)
|
|
||||||
{
|
|
||||||
//while (pressRelease)
|
|
||||||
//{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Down {0}", pressRelease);
|
|
||||||
if (pressRelease)
|
|
||||||
{
|
|
||||||
var newLevel = _FakeVolumeLevel + VolumeInterval;
|
|
||||||
SetVolume((ushort)newLevel);
|
|
||||||
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void VolumeDown(bool pressRelease)
|
|
||||||
{
|
|
||||||
//while (pressRelease)
|
|
||||||
//{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Volume Up {0}", pressRelease);
|
|
||||||
if (pressRelease)
|
|
||||||
{
|
|
||||||
var newLevel = _FakeVolumeLevel - VolumeInterval;
|
|
||||||
SetVolume((ushort)newLevel);
|
|
||||||
CrestronEnvironment.Sleep(VolumeHeldRepeatInterval);
|
|
||||||
}
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MuteToggle()
|
|
||||||
{
|
|
||||||
_IsMuted = !_IsMuted;
|
|
||||||
MuteFeedback.InvokeFireUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
|
|
||||||
{
|
|
||||||
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[Obsolete("Please use PepperDash.Essentials.Devices.Common, this will be removed in 2.1")]
|
|
||||||
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
|
|
||||||
{
|
|
||||||
public MockDisplayFactory()
|
|
||||||
{
|
|
||||||
TypeNames = new List<string>() { "mockdisplay" };
|
|
||||||
}
|
|
||||||
|
|
||||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device");
|
|
||||||
return new MockDisplay(dc.Key, dc.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -14,13 +14,13 @@ namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
public class DeviceFactoryWrapper
|
public class DeviceFactoryWrapper
|
||||||
{
|
{
|
||||||
public Type CType { get; set; }
|
public Type Type { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public Func<DeviceConfig, IKeyed> FactoryMethod { get; set; }
|
public Func<DeviceConfig, IKeyed> FactoryMethod { get; set; }
|
||||||
|
|
||||||
public DeviceFactoryWrapper()
|
public DeviceFactoryWrapper()
|
||||||
{
|
{
|
||||||
CType = null;
|
Type = null;
|
||||||
Description = "Not Available";
|
Description = "Not Available";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,7 +40,7 @@ namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var factory = (IDeviceFactory)Crestron.SimplSharp.Reflection.Activator.CreateInstance(type);
|
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||||
factory.LoadTypeFactories();
|
factory.LoadTypeFactories();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
@ -69,7 +69,7 @@ namespace PepperDash.Essentials.Core
|
||||||
DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
|
DeviceFactory.FactoryMethods.Add(typeName, new DeviceFactoryWrapper() { FactoryMethod = method});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddFactoryForType(string typeName, string description, Type cType, Func<DeviceConfig, IKeyed> method)
|
public static void AddFactoryForType(string typeName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
||||||
{
|
{
|
||||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ namespace PepperDash.Essentials.Core
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var wrapper = new DeviceFactoryWrapper() { CType = cType, Description = description, FactoryMethod = method };
|
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||||
DeviceFactory.FactoryMethods.Add(typeName, wrapper);
|
DeviceFactory.FactoryMethods.Add(typeName, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,17 +169,17 @@ namespace PepperDash.Essentials.Core
|
||||||
foreach (var type in types.OrderBy(t => t.Key))
|
foreach (var type in types.OrderBy(t => t.Key))
|
||||||
{
|
{
|
||||||
var description = type.Value.Description;
|
var description = type.Value.Description;
|
||||||
var cType = "Not Specified by Plugin";
|
var Type = "Not Specified by Plugin";
|
||||||
|
|
||||||
if (type.Value.CType != null)
|
if (type.Value.Type != null)
|
||||||
{
|
{
|
||||||
cType = type.Value.CType.FullName;
|
Type = type.Value.Type.FullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
CrestronConsole.ConsoleCommandResponse(
|
CrestronConsole.ConsoleCommandResponse(
|
||||||
@"Type: '{0}'
|
@"Type: '{0}'
|
||||||
CType: '{1}'
|
Type: '{1}'
|
||||||
Description: {2}{3}", type.Key, cType, description, CrestronEnvironment.NewLine);
|
Description: {2}{3}", type.Key, Type, description, CrestronEnvironment.NewLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,4 @@
|
||||||
using System;
|
namespace PepperDash.Essentials.Core
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharp.Reflection;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
|
||||||
using PepperDash.Essentials.Core.Config;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a class that is capable of loading device types
|
/// Defines a class that is capable of loading device types
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var factory = (IProcessorExtensionDeviceFactory)Crestron.SimplSharp.Reflection.Activator.CreateInstance(extension);
|
var factory = (IProcessorExtensionDeviceFactory)Activator.CreateInstance(extension);
|
||||||
factory.LoadFactories();
|
factory.LoadFactories();
|
||||||
}
|
}
|
||||||
catch( Exception e )
|
catch( Exception e )
|
||||||
|
|
@ -55,7 +55,7 @@ namespace PepperDash.Essentials.Core
|
||||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, new DeviceFactoryWrapper() { FactoryMethod = method });
|
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, new DeviceFactoryWrapper() { FactoryMethod = method });
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddFactoryForType(string extensionName, string description, Type cType, Func<DeviceConfig, IKeyed> method)
|
public static void AddFactoryForType(string extensionName, string description, Type Type, Func<DeviceConfig, IKeyed> method)
|
||||||
{
|
{
|
||||||
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
//Debug.LogMessage(LogEventLevel.Debug, "Adding factory method for type '{0}'", typeName);
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ namespace PepperDash.Essentials.Core
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var wrapper = new DeviceFactoryWrapper() { CType = cType, Description = description, FactoryMethod = method };
|
var wrapper = new DeviceFactoryWrapper() { Type = Type, Description = description, FactoryMethod = method };
|
||||||
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, wrapper);
|
ProcessorExtensionDeviceFactory.ProcessorExtensionFactoryMethods.Add(extensionName, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,7 @@ namespace PepperDash.Essentials.Core
|
||||||
public static void SetFilePathPrefix(string prefix)
|
public static void SetFilePathPrefix(string prefix)
|
||||||
{
|
{
|
||||||
FilePathPrefix = prefix;
|
FilePathPrefix = prefix;
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "File Path Prefix set to '{0}'", FilePathPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string _AssemblyVersion;
|
static string _AssemblyVersion;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
|
|
||||||
|
|
@ -109,7 +109,7 @@ namespace PepperDash.Essentials.Core
|
||||||
protected void AddJoins(Type type)
|
protected void AddJoins(Type type)
|
||||||
{
|
{
|
||||||
var fields =
|
var fields =
|
||||||
type.GetCType()
|
type.GetType()
|
||||||
.GetFields(BindingFlags.Public | BindingFlags.Instance)
|
.GetFields(BindingFlags.Public | BindingFlags.Instance)
|
||||||
.Where(f => f.IsDefined(typeof (JoinNameAttribute), true));
|
.Where(f => f.IsDefined(typeof (JoinNameAttribute), true));
|
||||||
|
|
||||||
|
|
@ -501,7 +501,7 @@ namespace PepperDash.Essentials.Core
|
||||||
public string GetNameAttribute(MemberInfo memberInfo)
|
public string GetNameAttribute(MemberInfo memberInfo)
|
||||||
{
|
{
|
||||||
var name = string.Empty;
|
var name = string.Empty;
|
||||||
var attribute = (JoinNameAttribute)CAttribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute));
|
var attribute = (JoinNameAttribute)Attribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute));
|
||||||
|
|
||||||
if (attribute == null) return name;
|
if (attribute == null) return name;
|
||||||
|
|
||||||
|
|
@ -514,7 +514,7 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.All)]
|
[AttributeUsage(AttributeTargets.All)]
|
||||||
public class JoinNameAttribute : CAttribute
|
public class JoinNameAttribute : Attribute
|
||||||
{
|
{
|
||||||
private string _Name;
|
private string _Name;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ namespace PepperDash.Essentials.Core.Monitoring
|
||||||
_uptimePollTimer = null;
|
_uptimePollTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PollUptime(object obj)
|
public void PollUptime(object obj)
|
||||||
{
|
{
|
||||||
var consoleResponse = string.Empty;
|
var consoleResponse = string.Empty;
|
||||||
|
|
||||||
|
|
@ -142,19 +142,22 @@ namespace PepperDash.Essentials.Core.Monitoring
|
||||||
_uptime = uptimeRaw.Substring(forIndex + 4);
|
_uptime = uptimeRaw.Substring(forIndex + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ProcessorReboot()
|
public static void ProcessorReboot()
|
||||||
{
|
{
|
||||||
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return;
|
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return;
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "Rebooting...");
|
||||||
|
|
||||||
var response = string.Empty;
|
|
||||||
|
var response = string.Empty;
|
||||||
CrestronConsole.SendControlSystemCommand("reboot", ref response);
|
CrestronConsole.SendControlSystemCommand("reboot", ref response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ProgramReset(uint index)
|
public static void ProgramReset(uint index)
|
||||||
{
|
{
|
||||||
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return;
|
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server) return;
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "Resetting Program {0}...", index);
|
||||||
|
|
||||||
if (index <= 0 || index > 10) return;
|
if (index <= 0 || index > 10) return;
|
||||||
|
|
||||||
var cmd = string.Format("progreset -p:{0}", index);
|
var cmd = string.Format("progreset -p:{0}", index);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
|
using PepperDash.Core;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
|
|
@ -17,9 +18,31 @@ namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
private IPartitionStateProvider _partitionSensor;
|
private IPartitionStateProvider _partitionSensor;
|
||||||
|
|
||||||
private bool isInAutoMode;
|
public bool IsInAutoMode { get; private set; }
|
||||||
|
|
||||||
private bool partitionPresent;
|
private bool _partitionPresent;
|
||||||
|
|
||||||
|
public bool PartitionPresent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _partitionPresent;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_partitionPresent == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_partitionPresent = value;
|
||||||
|
|
||||||
|
if (PartitionPresentFeedback != null)
|
||||||
|
{
|
||||||
|
PartitionPresentFeedback.FireUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List<string> adjacentRoomKeys)
|
public EssentialsPartitionController(string key, string name, IPartitionStateProvider sensor, bool defaultToManualMode, List<string> adjacentRoomKeys)
|
||||||
{
|
{
|
||||||
|
|
@ -52,7 +75,7 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
void PartitionPresentFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||||
{
|
{
|
||||||
if (isInAutoMode)
|
if (IsInAutoMode)
|
||||||
{
|
{
|
||||||
PartitionPresentFeedback.FireUpdate();
|
PartitionPresentFeedback.FireUpdate();
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +87,7 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
public void SetAutoMode()
|
public void SetAutoMode()
|
||||||
{
|
{
|
||||||
isInAutoMode = true;
|
IsInAutoMode = true;
|
||||||
if (PartitionPresentFeedback != null)
|
if (PartitionPresentFeedback != null)
|
||||||
{
|
{
|
||||||
PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue);
|
PartitionPresentFeedback.SetValueFunc(() => _partitionSensor.PartitionPresentFeedback.BoolValue);
|
||||||
|
|
@ -76,20 +99,21 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
if (_partitionSensor != null)
|
if (_partitionSensor != null)
|
||||||
{
|
{
|
||||||
|
_partitionSensor.PartitionPresentFeedback.OutputChange -= PartitionPresentFeedback_OutputChange;
|
||||||
_partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange;
|
_partitionSensor.PartitionPresentFeedback.OutputChange += PartitionPresentFeedback_OutputChange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetManualMode()
|
public void SetManualMode()
|
||||||
{
|
{
|
||||||
isInAutoMode = false;
|
IsInAutoMode = false;
|
||||||
if (PartitionPresentFeedback != null)
|
if (PartitionPresentFeedback != null)
|
||||||
{
|
{
|
||||||
PartitionPresentFeedback.SetValueFunc(() => partitionPresent);
|
PartitionPresentFeedback.SetValueFunc(() => _partitionPresent);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PartitionPresentFeedback = new BoolFeedback(() => partitionPresent);
|
PartitionPresentFeedback = new BoolFeedback(() => _partitionPresent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_partitionSensor != null)
|
if (_partitionSensor != null)
|
||||||
|
|
@ -101,27 +125,30 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
public void SetPartitionStatePresent()
|
public void SetPartitionStatePresent()
|
||||||
{
|
{
|
||||||
if (!isInAutoMode)
|
if (!IsInAutoMode)
|
||||||
{
|
{
|
||||||
partitionPresent = true;
|
PartitionPresent = true;
|
||||||
PartitionPresentFeedback.FireUpdate();
|
PartitionPresentFeedback.FireUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetPartitionStateNotPresent()
|
public void SetPartitionStateNotPresent()
|
||||||
{
|
{
|
||||||
if (!isInAutoMode)
|
if (!IsInAutoMode)
|
||||||
{
|
{
|
||||||
partitionPresent = false;
|
PartitionPresent = false;
|
||||||
PartitionPresentFeedback.FireUpdate();
|
PartitionPresentFeedback.FireUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggglePartitionState()
|
public void ToggglePartitionState()
|
||||||
{
|
{
|
||||||
if (!isInAutoMode)
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Toggling Partition State for {Key}", this);
|
||||||
|
Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"IsInAutoMode: {IsInAutoMode}", this);
|
||||||
|
|
||||||
|
if (!IsInAutoMode)
|
||||||
{
|
{
|
||||||
partitionPresent = !partitionPresent;
|
PartitionPresent = !PartitionPresent;
|
||||||
PartitionPresentFeedback.FireUpdate();
|
PartitionPresentFeedback.FireUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
using Newtonsoft.Json;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
|
|
@ -13,7 +9,11 @@ namespace PepperDash.Essentials.Core
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPartitionStateProvider : IKeyName
|
public interface IPartitionStateProvider : IKeyName
|
||||||
{
|
{
|
||||||
|
[JsonIgnore]
|
||||||
BoolFeedback PartitionPresentFeedback { get; }
|
BoolFeedback PartitionPresentFeedback { get; }
|
||||||
|
|
||||||
|
[JsonProperty("partitionPresent")]
|
||||||
|
bool PartitionPresent { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -21,8 +21,12 @@ namespace PepperDash.Essentials.Core
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPartitionController : IPartitionStateProvider
|
public interface IPartitionController : IPartitionStateProvider
|
||||||
{
|
{
|
||||||
|
[JsonProperty("adjacentRoomKeys")]
|
||||||
List<string> AdjacentRoomKeys { get; }
|
List<string> AdjacentRoomKeys { get; }
|
||||||
|
|
||||||
|
[JsonProperty("isInAutoMode")]
|
||||||
|
bool IsInAutoMode { get; }
|
||||||
|
|
||||||
void SetPartitionStatePresent();
|
void SetPartitionStatePresent();
|
||||||
|
|
||||||
void SetPartitionStateNotPresent();
|
void SetPartitionStateNotPresent();
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
<Title>PepperDash Essentials Core</Title>
|
<Title>PepperDash Essentials Core</Title>
|
||||||
<PackageId>PepperDash.Essentials.Core</PackageId>
|
<PackageId>PepperDash.Essentials.Core</PackageId>
|
||||||
<InformationalVersion>$(Version)</InformationalVersion>
|
<InformationalVersion>$(Version)</InformationalVersion>
|
||||||
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
|
<Version>2.0.0-local</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
|
|
@ -22,13 +24,9 @@
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Compile Remove="Routing\GenericExtensions.cs" />
|
|
||||||
<Compile Remove="Routing\IRoutingSinkWithFeedback.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
|
||||||
<PackageReference Include="PepperDashCore" Version="2.0.0-beta-423" />
|
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-424" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />
|
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
@ -9,6 +8,7 @@ using System.Reflection;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
|
|
@ -27,24 +27,31 @@ namespace PepperDash.Essentials
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
||||||
|
|
||||||
|
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
||||||
|
|
||||||
|
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
||||||
|
|
||||||
|
public static List<LoadedAssembly> EssentialsPluginAssemblies { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The directory to look in for .cplz plugin packages
|
/// The directory to look in for .cplz plugin packages
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static string _pluginDirectory = Global.FilePathPrefix + "plugins";
|
static string _pluginDirectory => Global.FilePathPrefix + "plugins";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The directory where plugins will be moved to and loaded from
|
/// The directory where plugins will be moved to and loaded from
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static string _loadedPluginsDirectoryPath = _pluginDirectory + Global.DirectorySeparator + "loadedAssemblies";
|
static string _loadedPluginsDirectoryPath => _pluginDirectory + Global.DirectorySeparator + "loadedAssemblies";
|
||||||
|
|
||||||
// The temp directory where .cplz archives will be unzipped to
|
// The temp directory where .cplz archives will be unzipped to
|
||||||
static string _tempDirectory = _pluginDirectory + Global.DirectorySeparator + "temp";
|
static string _tempDirectory => _pluginDirectory + Global.DirectorySeparator + "temp";
|
||||||
|
|
||||||
|
|
||||||
static PluginLoader()
|
static PluginLoader()
|
||||||
{
|
{
|
||||||
LoadedAssemblies = new List<LoadedAssembly>();
|
LoadedAssemblies = new List<LoadedAssembly>();
|
||||||
LoadedPluginFolderAssemblies = new List<LoadedAssembly>();
|
LoadedPluginFolderAssemblies = new List<LoadedAssembly>();
|
||||||
|
EssentialsPluginAssemblies = new List<LoadedAssembly>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -69,6 +76,7 @@ namespace PepperDash.Essentials
|
||||||
case ("PepperDashEssentials.dll"):
|
case ("PepperDashEssentials.dll"):
|
||||||
{
|
{
|
||||||
version = Global.AssemblyVersion;
|
version = Global.AssemblyVersion;
|
||||||
|
EssentialsAssembly = new LoadedAssembly(fi.Name, version, assembly);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ("PepperDash_Essentials_Core.dll"):
|
case ("PepperDash_Essentials_Core.dll"):
|
||||||
|
|
@ -81,9 +89,12 @@ namespace PepperDash.Essentials
|
||||||
version = Global.AssemblyVersion;
|
version = Global.AssemblyVersion;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ("PepperDash_Core.dll"):
|
case ("PepperDashCore.dll"):
|
||||||
{
|
{
|
||||||
version = PepperDash.Core.Debug.PepperDashCoreVersion;
|
Debug.LogMessage(LogEventLevel.Verbose, "Found PepperDash_Core.dll");
|
||||||
|
version = Debug.PepperDashCoreVersion;
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "PepperDash_Core Version: {0}", version);
|
||||||
|
PepperDashCoreAssembly = new LoadedAssembly(fi.Name, version, assembly);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +162,7 @@ namespace PepperDash.Essentials
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="assembly"></param>
|
/// <param name="assembly"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
static string GetAssemblyVersion(Assembly assembly)
|
public static string GetAssemblyVersion(Assembly assembly)
|
||||||
{
|
{
|
||||||
var ver = assembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false);
|
var ver = assembly.GetCustomAttributes(typeof(AssemblyInformationalVersionAttribute), false);
|
||||||
if (ver != null && ver.Length > 0)
|
if (ver != null && ver.Length > 0)
|
||||||
|
|
@ -197,12 +208,19 @@ namespace PepperDash.Essentials
|
||||||
/// <param name="command"></param>
|
/// <param name="command"></param>
|
||||||
public static void ReportAssemblyVersions(string command)
|
public static void ReportAssemblyVersions(string command)
|
||||||
{
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Essentials Version: {0}" + CrestronEnvironment.NewLine, Global.AssemblyVersion);
|
||||||
CrestronConsole.ConsoleCommandResponse("Loaded Assemblies:" + CrestronEnvironment.NewLine);
|
CrestronConsole.ConsoleCommandResponse("PepperDash Core Version: {0}" + CrestronEnvironment.NewLine, PepperDashCoreAssembly.Version);
|
||||||
foreach (var assembly in LoadedAssemblies)
|
CrestronConsole.ConsoleCommandResponse("Essentials Plugin Versions:" + CrestronEnvironment.NewLine);
|
||||||
|
foreach (var assembly in EssentialsPluginAssemblies)
|
||||||
{
|
{
|
||||||
CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
|
CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//CrestronConsole.ConsoleCommandResponse("Loaded Assemblies:" + CrestronEnvironment.NewLine);
|
||||||
|
//foreach (var assembly in LoadedAssemblies)
|
||||||
|
//{
|
||||||
|
// CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder
|
/// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder
|
||||||
|
|
@ -382,7 +400,7 @@ namespace PepperDash.Essentials
|
||||||
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
|
if (typeof (IPluginDeviceFactory).IsAssignableFrom(type) && !type.IsAbstract)
|
||||||
{
|
{
|
||||||
var plugin =
|
var plugin =
|
||||||
(IPluginDeviceFactory) Crestron.SimplSharp.Reflection.Activator.CreateInstance(type);
|
(IPluginDeviceFactory)Activator.CreateInstance(type);
|
||||||
LoadCustomPlugin(plugin, loadedAssembly);
|
LoadCustomPlugin(plugin, loadedAssembly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -439,6 +457,9 @@ namespace PepperDash.Essentials
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading plugin: {0}", loadedAssembly.Name);
|
Debug.LogMessage(LogEventLevel.Information, "Loading plugin: {0}", loadedAssembly.Name);
|
||||||
plugin.LoadTypeFactories();
|
plugin.LoadTypeFactories();
|
||||||
|
|
||||||
|
if(!EssentialsPluginAssemblies.Contains(loadedAssembly))
|
||||||
|
EssentialsPluginAssemblies.Add(loadedAssembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -493,6 +514,8 @@ namespace PepperDash.Essentials
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void LoadPlugins()
|
public static void LoadPlugins()
|
||||||
{
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "Attempting to Load Plugins from {_pluginDirectory}", _pluginDirectory);
|
||||||
|
|
||||||
if (Directory.Exists(_pluginDirectory))
|
if (Directory.Exists(_pluginDirectory))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Plugins directory found, checking for plugins");
|
Debug.LogMessage(LogEventLevel.Information, "Plugins directory found, checking for plugins");
|
||||||
|
|
@ -521,8 +544,11 @@ namespace PepperDash.Essentials
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LoadedAssembly
|
public class LoadedAssembly
|
||||||
{
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
|
[JsonProperty("version")]
|
||||||
public string Version { get; private set; }
|
public string Version { get; private set; }
|
||||||
|
[JsonIgnore]
|
||||||
public Assembly Assembly { get; private set; }
|
public Assembly Assembly { get; private set; }
|
||||||
|
|
||||||
public LoadedAssembly(string name, string version, Assembly assembly)
|
public LoadedAssembly(string name, string version, Assembly assembly)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +17,33 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
private List<IEssentialsRoom> _rooms;
|
private List<IEssentialsRoom> _rooms;
|
||||||
|
|
||||||
private bool isInAutoMode;
|
public List<IKeyName> Rooms
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _rooms.Cast<IKeyName>().ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isInAutoMode;
|
||||||
|
|
||||||
|
public bool IsInAutoMode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _isInAutoMode;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if(value == _isInAutoMode)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isInAutoMode = value;
|
||||||
|
IsInAutoModeFeedback.FireUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private CTimer _scenarioChangeDebounceTimer;
|
private CTimer _scenarioChangeDebounceTimer;
|
||||||
|
|
||||||
|
|
@ -36,14 +62,14 @@ namespace PepperDash.Essentials.Core
|
||||||
_scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds;
|
_scenarioChangeDebounceTimeSeconds = _propertiesConfig.ScenarioChangeDebounceTimeSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
IsInAutoModeFeedback = new BoolFeedback(() => isInAutoMode);
|
IsInAutoModeFeedback = new BoolFeedback(() => _isInAutoMode);
|
||||||
|
|
||||||
// default to auto mode
|
// default to auto mode
|
||||||
isInAutoMode = true;
|
IsInAutoMode = true;
|
||||||
|
|
||||||
if (_propertiesConfig.defaultToManualMode)
|
if (_propertiesConfig.defaultToManualMode)
|
||||||
{
|
{
|
||||||
isInAutoMode = false;
|
IsInAutoMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IsInAutoModeFeedback.FireUpdate();
|
IsInAutoModeFeedback.FireUpdate();
|
||||||
|
|
@ -56,7 +82,7 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
SetRooms();
|
SetRooms();
|
||||||
|
|
||||||
if (isInAutoMode)
|
if (IsInAutoMode)
|
||||||
{
|
{
|
||||||
DetermineRoomCombinationScenario();
|
DetermineRoomCombinationScenario();
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +137,11 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
void StartDebounceTimer()
|
void StartDebounceTimer()
|
||||||
{
|
{
|
||||||
var time = _scenarioChangeDebounceTimeSeconds * 1000;
|
// default to 500ms for manual mode
|
||||||
|
var time = 500;
|
||||||
|
|
||||||
|
// if in auto mode, debounce the scenario change
|
||||||
|
if(IsInAutoMode) time = _scenarioChangeDebounceTimeSeconds * 1000;
|
||||||
|
|
||||||
if (_scenarioChangeDebounceTimer == null)
|
if (_scenarioChangeDebounceTimer == null)
|
||||||
{
|
{
|
||||||
|
|
@ -185,7 +215,7 @@ namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
_currentScenario.Activate();
|
_currentScenario.Activate();
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, this, "Current Scenario: {0}", _currentScenario.Name);
|
Debug.LogMessage(LogEventLevel.Debug, $"Current Scenario: {_currentScenario.Name}", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
var handler = RoomCombinationScenarioChanged;
|
var handler = RoomCombinationScenarioChanged;
|
||||||
|
|
@ -201,20 +231,17 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
public void SetAutoMode()
|
public void SetAutoMode()
|
||||||
{
|
{
|
||||||
isInAutoMode = true;
|
IsInAutoMode = true;
|
||||||
IsInAutoModeFeedback.FireUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetManualMode()
|
public void SetManualMode()
|
||||||
{
|
{
|
||||||
isInAutoMode = false;
|
IsInAutoMode = false;
|
||||||
IsInAutoModeFeedback.FireUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleMode()
|
public void ToggleMode()
|
||||||
{
|
{
|
||||||
isInAutoMode = !isInAutoMode;
|
IsInAutoMode = !IsInAutoMode;
|
||||||
IsInAutoModeFeedback.FireUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IRoomCombinationScenario> RoomCombinationScenarios { get; private set; }
|
public List<IRoomCombinationScenario> RoomCombinationScenarios { get; private set; }
|
||||||
|
|
@ -223,7 +250,7 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
public void TogglePartitionState(string partitionKey)
|
public void TogglePartitionState(string partitionKey)
|
||||||
{
|
{
|
||||||
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey)) as IPartitionController;
|
var partition = Partitions.FirstOrDefault((p) => p.Key.Equals(partitionKey));
|
||||||
|
|
||||||
if (partition != null)
|
if (partition != null)
|
||||||
{
|
{
|
||||||
|
|
@ -233,7 +260,7 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
public void SetRoomCombinationScenario(string scenarioKey)
|
public void SetRoomCombinationScenario(string scenarioKey)
|
||||||
{
|
{
|
||||||
if (isInAutoMode)
|
if (IsInAutoMode)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, this, "Cannot set room combination scenario when in auto mode. Set to auto mode first.");
|
Debug.LogMessage(LogEventLevel.Information, this, "Cannot set room combination scenario when in auto mode. Set to auto mode first.");
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using Newtonsoft.Json;
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
|
|
@ -21,13 +18,21 @@ namespace PepperDash.Essentials.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current room combination scenario
|
/// The current room combination scenario
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonProperty("currentScenario")]
|
||||||
IRoomCombinationScenario CurrentScenario { get; }
|
IRoomCombinationScenario CurrentScenario { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When true, indicates the current mode is auto mode
|
/// When true, indicates the current mode is auto mode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
BoolFeedback IsInAutoModeFeedback {get;}
|
BoolFeedback IsInAutoModeFeedback {get;}
|
||||||
|
|
||||||
|
[JsonProperty("isInAutoMode")]
|
||||||
|
bool IsInAutoMode { get; }
|
||||||
|
|
||||||
|
[JsonProperty("rooms")]
|
||||||
|
List<IKeyName> Rooms { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets auto mode
|
/// Sets auto mode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -46,11 +51,13 @@ namespace PepperDash.Essentials.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The available room combinatino scenarios
|
/// The available room combinatino scenarios
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonProperty("roomCombinationScenarios")]
|
||||||
List<IRoomCombinationScenario> RoomCombinationScenarios { get; }
|
List<IRoomCombinationScenario> RoomCombinationScenarios { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The partition
|
/// The partition
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonProperty("partitions")]
|
||||||
List<IPartitionController> Partitions { get; }
|
List<IPartitionController> Partitions { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -71,8 +78,12 @@ namespace PepperDash.Essentials.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When true, indicates that this room combination scenario is active
|
/// When true, indicates that this room combination scenario is active
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
BoolFeedback IsActiveFeedback { get; }
|
BoolFeedback IsActiveFeedback { get; }
|
||||||
|
|
||||||
|
[JsonProperty("isActive")]
|
||||||
|
bool IsActive { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Activates this room combination scenario
|
/// Activates this room combination scenario
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -86,11 +97,13 @@ namespace PepperDash.Essentials.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The state of the partitions that would activate this scenario
|
/// The state of the partitions that would activate this scenario
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonProperty("partitionStates")]
|
||||||
List<PartitionState> PartitionStates { get; }
|
List<PartitionState> PartitionStates { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The mapping of UIs by key to rooms by key
|
/// The mapping of UIs by key to rooms by key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonProperty("uiMap")]
|
||||||
Dictionary<string, string> UiMap { get; set; }
|
Dictionary<string, string> UiMap { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,20 +16,41 @@ namespace PepperDash.Essentials.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a room combination scenario
|
/// Represents a room combination scenario
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RoomCombinationScenario: IRoomCombinationScenario
|
public class RoomCombinationScenario: IRoomCombinationScenario, IKeyName
|
||||||
{
|
{
|
||||||
private RoomCombinationScenarioConfig _config;
|
private RoomCombinationScenarioConfig _config;
|
||||||
|
|
||||||
|
[JsonProperty("key")]
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("partitionStates")]
|
||||||
public List<PartitionState> PartitionStates { get; private set; }
|
public List<PartitionState> PartitionStates { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty("uiMap")]
|
||||||
public Dictionary<string, string> UiMap { get; set; }
|
public Dictionary<string, string> UiMap { get; set; }
|
||||||
|
|
||||||
private bool _isActive;
|
private bool _isActive;
|
||||||
|
|
||||||
|
[JsonProperty("isActive")]
|
||||||
|
public bool IsActive
|
||||||
|
{
|
||||||
|
get { return _isActive; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if(value == _isActive)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isActive = value;
|
||||||
|
IsActiveFeedback.FireUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
public BoolFeedback IsActiveFeedback { get; private set; }
|
public BoolFeedback IsActiveFeedback { get; private set; }
|
||||||
|
|
||||||
private List<DeviceActionWrapper> activationActions;
|
private List<DeviceActionWrapper> activationActions;
|
||||||
|
|
@ -67,8 +88,7 @@ namespace PepperDash.Essentials.Core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_isActive = true;
|
IsActive = true;
|
||||||
IsActiveFeedback.FireUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deactivate()
|
public void Deactivate()
|
||||||
|
|
@ -83,8 +103,7 @@ namespace PepperDash.Essentials.Core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_isActive = false;
|
IsActive = false;
|
||||||
IsActiveFeedback.FireUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,9 @@ namespace PepperDash.Essentials.Room.Config
|
||||||
public string SourceListKey { get; set; }
|
public string SourceListKey { get; set; }
|
||||||
[JsonProperty("destinationListKey")]
|
[JsonProperty("destinationListKey")]
|
||||||
public string DestinationListKey { get; set; }
|
public string DestinationListKey { get; set; }
|
||||||
|
[JsonProperty("audioControlPointListKey")]
|
||||||
|
public string AudioControlPointListKey { get; set; }
|
||||||
|
|
||||||
[JsonProperty("defaultSourceItem")]
|
[JsonProperty("defaultSourceItem")]
|
||||||
public string DefaultSourceItem { get; set; }
|
public string DefaultSourceItem { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -59,28 +59,81 @@ namespace PepperDash.Essentials.Core
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IMobileControlRoomMessenger MobileControlRoomBridge { get; private set; }
|
public IMobileControlRoomMessenger MobileControlRoomBridge { get; private set; }
|
||||||
|
|
||||||
|
protected const string _defaultListKey = "default";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The config name of the source list
|
/// The config name of the source list
|
||||||
/// </summary>
|
/// </summary>
|
||||||
///
|
///
|
||||||
protected string _SourceListKey;
|
private string _sourceListKey;
|
||||||
public string SourceListKey {
|
public string SourceListKey {
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _SourceListKey;
|
if(string.IsNullOrEmpty(_sourceListKey))
|
||||||
}
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
if (value != _SourceListKey)
|
|
||||||
{
|
{
|
||||||
_SourceListKey = value;
|
return _defaultListKey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _sourceListKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
if (value != _sourceListKey)
|
||||||
|
{
|
||||||
|
_sourceListKey = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string DestinationListKey { get; private set; }
|
private string _destinationListKey;
|
||||||
|
public string DestinationListKey
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_destinationListKey))
|
||||||
|
{
|
||||||
|
return _defaultListKey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _destinationListKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
if (value != _destinationListKey)
|
||||||
|
{
|
||||||
|
_destinationListKey = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _audioControlPointListKey;
|
||||||
|
public string AudioControlPointListKey
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_audioControlPointListKey))
|
||||||
|
{
|
||||||
|
return _defaultListKey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _destinationListKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
if (value != _audioControlPointListKey)
|
||||||
|
{
|
||||||
|
_audioControlPointListKey = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected const string _defaultSourceListKey = "default";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Timer used for informing the UIs of a shutdown
|
/// Timer used for informing the UIs of a shutdown
|
||||||
|
|
@ -141,6 +194,7 @@ namespace PepperDash.Essentials.Core
|
||||||
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
|
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
|
||||||
ShutdownType = eShutdownType.None;
|
ShutdownType = eShutdownType.None;
|
||||||
};
|
};
|
||||||
|
|
||||||
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
|
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
|
||||||
|
|
||||||
ShutdownPromptSeconds = 60;
|
ShutdownPromptSeconds = 60;
|
||||||
|
|
@ -191,7 +245,7 @@ namespace PepperDash.Essentials.Core
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sourceListKey = _defaultSourceListKey;
|
sourceListKey = _defaultListKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
string DestinationListKey { get; }
|
string DestinationListKey { get; }
|
||||||
|
|
||||||
|
string AudioControlPointListKey { get; }
|
||||||
|
|
||||||
SecondsCountdownTimer ShutdownPromptTimer { get; }
|
SecondsCountdownTimer ShutdownPromptTimer { get; }
|
||||||
int ShutdownPromptSeconds { get; }
|
int ShutdownPromptSeconds { get; }
|
||||||
int ShutdownVacancySeconds { get; }
|
int ShutdownVacancySeconds { get; }
|
||||||
|
|
|
||||||
|
|
@ -159,4 +159,13 @@ namespace PepperDash.Essentials.Core
|
||||||
Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; }
|
Core.Privacy.MicrophonePrivacyController MicrophonePrivacy { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface IHasAccessoryDevices : IKeyName
|
||||||
|
{
|
||||||
|
List<string> AccessoryDeviceKeys { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IHasCiscoNavigatorTouchpanel
|
||||||
|
{
|
||||||
|
string CiscoNavigatorTouchpanelKey { get; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
|
@ -12,20 +13,37 @@ namespace PepperDash.Essentials.Core
|
||||||
/// on those destinations.
|
/// on those destinations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, RouteRequest> RouteRequests = new Dictionary<string, RouteRequest>();
|
private static readonly Dictionary<string, RouteRequest> RouteRequests = new Dictionary<string, RouteRequest>();
|
||||||
/// <summary>
|
|
||||||
/// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
|
/// <summary>
|
||||||
/// and then attempts a new Route and if sucessful, stores that RouteDescriptor
|
/// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
|
||||||
/// in RouteDescriptorCollection.DefaultCollection
|
/// and then attempts a new Route and if sucessful, stores that RouteDescriptor
|
||||||
/// </summary>
|
/// in RouteDescriptorCollection.DefaultCollection
|
||||||
public static void ReleaseAndMakeRoute(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
|
/// </summary>
|
||||||
{
|
public static void ReleaseAndMakeRoute(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, string destinationPortKey = "", string sourcePortKey = "")
|
||||||
var routeRequest = new RouteRequest {
|
{
|
||||||
Destination = destination,
|
var inputPort = string.IsNullOrEmpty(destinationPortKey) ? null : destination.InputPorts.FirstOrDefault(p => p.Key == destinationPortKey);
|
||||||
Source = source,
|
var outputPort = string.IsNullOrEmpty(sourcePortKey) ? null : source.OutputPorts.FirstOrDefault(p => p.Key == sourcePortKey);
|
||||||
SignalType = signalType
|
|
||||||
};
|
ReleaseAndMakeRoute(destination, source, signalType, inputPort, outputPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReleaseAndMakeRoute(IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort = null, RoutingOutputPort sourcePort = null)
|
||||||
|
{
|
||||||
|
if (destination == null) throw new ArgumentNullException(nameof(destination));
|
||||||
|
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||||
|
if (destinationPort == null) Debug.LogMessage(LogEventLevel.Verbose, "Destination port is null");
|
||||||
|
if (sourcePort == null) Debug.LogMessage(LogEventLevel.Verbose, "Source port is null");
|
||||||
|
|
||||||
|
var routeRequest = new RouteRequest
|
||||||
|
{
|
||||||
|
Destination = destination,
|
||||||
|
DestinationPort = destinationPort,
|
||||||
|
Source = source,
|
||||||
|
SourcePort = sourcePort,
|
||||||
|
SignalType = signalType
|
||||||
|
};
|
||||||
|
|
||||||
var coolingDevice = destination as IWarmingCooling;
|
var coolingDevice = destination as IWarmingCooling;
|
||||||
|
|
||||||
|
|
@ -65,33 +83,39 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
destination.ReleaseRoute();
|
destination.ReleaseRoute();
|
||||||
|
|
||||||
RunRouteRequest(routeRequest);
|
RunRouteRequest(routeRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RunRouteRequest(RouteRequest request)
|
private static void RunRouteRequest(RouteRequest request)
|
||||||
{
|
{
|
||||||
if (request.Source == null)
|
if (request.Source == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType);
|
|
||||||
|
|
||||||
if (newRoute == null)
|
var (audioOrSingleRoute, videoRoute) = request.Destination.GetRouteToSource(request.Source, request.SignalType, request.DestinationPort, request.SourcePort);
|
||||||
|
|
||||||
|
if (audioOrSingleRoute == null && videoRoute == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute);
|
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(audioOrSingleRoute);
|
||||||
|
|
||||||
|
if (videoRoute != null)
|
||||||
|
{
|
||||||
|
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(videoRoute);
|
||||||
|
}
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination);
|
Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination);
|
||||||
|
|
||||||
newRoute.ExecuteRoutes();
|
audioOrSingleRoute.ExecuteRoutes();
|
||||||
|
videoRoute?.ExecuteRoutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Will release the existing route on the destination, if it is found in
|
/// Will release the existing route on the destination, if it is found in
|
||||||
/// RouteDescriptorCollection.DefaultCollection
|
/// RouteDescriptorCollection.DefaultCollection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="destination"></param>
|
/// <param name="destination"></param>
|
||||||
public static void ReleaseRoute(this IRoutingSink destination)
|
public static void ReleaseRoute(this IRoutingInputs destination)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling)
|
if (RouteRequests.TryGetValue(destination.Key, out RouteRequest existingRequest) && destination is IWarmingCooling)
|
||||||
{
|
{
|
||||||
|
|
@ -102,138 +126,191 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
RouteRequests.Remove(destination.Key);
|
RouteRequests.Remove(destination.Key);
|
||||||
|
|
||||||
var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination);
|
var current = RouteDescriptorCollection.DefaultCollection.RemoveRouteDescriptor(destination);
|
||||||
if (current != null)
|
if (current != null)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Releasing current route: {0}", destination, current.Source.Key);
|
Debug.LogMessage(LogEventLevel.Debug, "Releasing current route: {0}", destination, current.Source.Key);
|
||||||
current.ReleaseRoutes();
|
current.ReleaseRoutes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds a RouteDescriptor that contains the steps necessary to make a route between devices.
|
/// Builds a RouteDescriptor that contains the steps necessary to make a route between devices.
|
||||||
/// Routes of type AudioVideo will be built as two separate routes, audio and video. If
|
/// Routes of type AudioVideo will be built as two separate routes, audio and video. If
|
||||||
/// a route is discovered, a new RouteDescriptor is returned. If one or both parts
|
/// a route is discovered, a new RouteDescriptor is returned. If one or both parts
|
||||||
/// of an audio/video route are discovered a route descriptor is returned. If no route is
|
/// of an audio/video route are discovered a route descriptor is returned. If no route is
|
||||||
/// discovered, then null is returned
|
/// discovered, then null is returned
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static RouteDescriptor GetRouteToSource(this IRoutingSink destination, IRoutingOutputs source, eRoutingSignalType signalType)
|
public static (RouteDescriptor, RouteDescriptor) GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source, eRoutingSignalType signalType, RoutingInputPort destinationPort, RoutingOutputPort sourcePort)
|
||||||
{
|
{
|
||||||
var routeDescriptor = new RouteDescriptor(source, destination, signalType);
|
// if it's a single signal type, find the route
|
||||||
|
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo))
|
||||||
|
{
|
||||||
|
var singleTypeRouteDescriptor = new RouteDescriptor(source, destination, signalType);
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key, signalType);
|
||||||
|
|
||||||
// if it's a single signal type, find the route
|
if (!destination.GetRouteToSource(source, null, null, signalType, 0, singleTypeRouteDescriptor, destinationPort, sourcePort))
|
||||||
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo))
|
singleTypeRouteDescriptor = null;
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {0}", null, source.Key);
|
|
||||||
|
|
||||||
if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescriptor))
|
foreach (var route in singleTypeRouteDescriptor.Routes)
|
||||||
routeDescriptor = null;
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "Route for device: {route}", destination, route.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
return routeDescriptor;
|
return (singleTypeRouteDescriptor, null);
|
||||||
}
|
}
|
||||||
// otherwise, audioVideo needs to be handled as two steps.
|
// otherwise, audioVideo needs to be handled as two steps.
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build audio and video routes from {0}", destination, source.Key);
|
|
||||||
|
|
||||||
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescriptor);
|
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {sourceKey} of type {type}", destination, source.Key);
|
||||||
|
|
||||||
if (!audioSuccess)
|
var audioRouteDescriptor = new RouteDescriptor(source, destination, eRoutingSignalType.Audio);
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key);
|
|
||||||
|
|
||||||
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescriptor);
|
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, audioRouteDescriptor, destinationPort, sourcePort);
|
||||||
|
|
||||||
if (!videoSuccess)
|
if (!audioSuccess)
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key);
|
Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key);
|
||||||
|
|
||||||
if (!audioSuccess && !videoSuccess)
|
var videoRouteDescriptor = new RouteDescriptor(source, destination, eRoutingSignalType.Video);
|
||||||
routeDescriptor = null;
|
|
||||||
|
|
||||||
|
|
||||||
return routeDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, videoRouteDescriptor, destinationPort, sourcePort);
|
||||||
/// The recursive part of this. Will stop on each device, search its inputs for the
|
|
||||||
/// desired source and if not found, invoke this function for the each input port
|
|
||||||
/// hoping to find the source.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="destination"></param>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <param name="outputPortToUse">The RoutingOutputPort whose link is being checked for a route</param>
|
|
||||||
/// <param name="alreadyCheckedDevices">Prevents Devices from being twice-checked</param>
|
|
||||||
/// <param name="signalType">This recursive function should not be called with AudioVideo</param>
|
|
||||||
/// <param name="cycle">Just an informational counter</param>
|
|
||||||
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
|
|
||||||
/// <returns>true if source is hit</returns>
|
|
||||||
static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
|
|
||||||
RoutingOutputPort outputPortToUse, List<IRoutingInputsOutputs> alreadyCheckedDevices,
|
|
||||||
eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable)
|
|
||||||
{
|
|
||||||
cycle++;
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {0} {1}--> {2}", null, cycle, source.Key, destination.Key);
|
if (!videoSuccess)
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key);
|
||||||
|
|
||||||
RoutingInputPort goodInputPort = null;
|
foreach (var route in audioRouteDescriptor.Routes)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "Audio route for device: {route}", destination, route.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
var destinationTieLines = TieLineCollection.Default.Where(t =>
|
foreach (var route in videoRouteDescriptor.Routes)
|
||||||
t.DestinationPort.ParentDevice == destination && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo)));
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "Video route for device: {route}", destination, route.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
// find a direct tie
|
|
||||||
var directTie = destinationTieLines.FirstOrDefault(
|
|
||||||
t => t.DestinationPort.ParentDevice == destination
|
|
||||||
&& t.SourcePort.ParentDevice == source);
|
|
||||||
if (directTie != null) // Found a tie directly to the source
|
|
||||||
{
|
|
||||||
goodInputPort = directTie.DestinationPort;
|
|
||||||
}
|
|
||||||
else // no direct-connect. Walk back devices.
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {0}. Walking down tie lines", destination, source.Key);
|
|
||||||
|
|
||||||
// No direct tie? Run back out on the inputs' attached devices...
|
if (!audioSuccess && !videoSuccess)
|
||||||
// Only the ones that are routing devices
|
return (null, null);
|
||||||
var attachedMidpoints = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
|
|
||||||
|
|
||||||
|
return (audioRouteDescriptor, videoRouteDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The recursive part of this. Will stop on each device, search its inputs for the
|
||||||
|
/// desired source and if not found, invoke this function for the each input port
|
||||||
|
/// hoping to find the source.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination"></param>
|
||||||
|
/// <param name="source"></param>
|
||||||
|
/// <param name="destinationPort">The RoutingOutputPort whose link is being checked for a route</param>
|
||||||
|
/// <param name="alreadyCheckedDevices">Prevents Devices from being twice-checked</param>
|
||||||
|
/// <param name="signalType">This recursive function should not be called with AudioVideo</param>
|
||||||
|
/// <param name="cycle">Just an informational counter</param>
|
||||||
|
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
|
||||||
|
/// <returns>true if source is hit</returns>
|
||||||
|
private static bool GetRouteToSource(this IRoutingInputs destination, IRoutingOutputs source,
|
||||||
|
RoutingOutputPort outputPortToUse, List<IRoutingInputsOutputs> alreadyCheckedDevices,
|
||||||
|
eRoutingSignalType signalType, int cycle, RouteDescriptor routeTable, RoutingInputPort destinationPort, RoutingOutputPort sourcePort)
|
||||||
|
{
|
||||||
|
cycle++;
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {cycle} {sourceKey}:{sourcePortKey}--> {destinationKey}:{destinationPortKey} {type}", null, cycle, source.Key, sourcePort?.Key ?? "auto", destination.Key, destinationPort?.Key ?? "auto", signalType.ToString());
|
||||||
|
|
||||||
|
RoutingInputPort goodInputPort = null;
|
||||||
|
|
||||||
|
IEnumerable<TieLine> destinationTieLines;
|
||||||
|
TieLine directTie = null;
|
||||||
|
|
||||||
|
if (destinationPort == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
destinationTieLines = TieLineCollection.Default.Where(t =>
|
||||||
|
t.DestinationPort.ParentDevice.Key == destination.Key && (t.Type == signalType || t.Type.HasFlag(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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the TieLine without a port
|
||||||
|
if (destinationPort == null && sourcePort == null)
|
||||||
|
{
|
||||||
|
directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.SourcePort.ParentDevice.Key == source.Key);
|
||||||
|
}
|
||||||
|
// find a tieLine to a specific destination port without a specific source port
|
||||||
|
else if (destinationPort != null && sourcePort == null)
|
||||||
|
{
|
||||||
|
directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key);
|
||||||
|
}
|
||||||
|
// find a tieline to a specific source port without a specific destination port
|
||||||
|
else if (destinationPort == null & sourcePort != null)
|
||||||
|
{
|
||||||
|
directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key);
|
||||||
|
}
|
||||||
|
// find a tieline to a specific source port and destination port
|
||||||
|
else if (destinationPort != null && sourcePort != null)
|
||||||
|
{
|
||||||
|
directTie = destinationTieLines.FirstOrDefault(t => t.DestinationPort.ParentDevice.Key == destination.Key && t.DestinationPort.Key == destinationPort.Key && t.SourcePort.ParentDevice.Key == source.Key && t.SourcePort.Key == sourcePort.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (directTie != null) // Found a tie directly to the source
|
||||||
|
{
|
||||||
|
goodInputPort = directTie.DestinationPort;
|
||||||
|
}
|
||||||
|
else // no direct-connect. Walk back devices.
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {sourceKey}. Walking down tie lines", destination, source.Key);
|
||||||
|
|
||||||
|
// No direct tie? Run back out on the inputs' attached devices...
|
||||||
|
// Only the ones that are routing devices
|
||||||
|
var midpointTieLines = destinationTieLines.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
|
||||||
|
|
||||||
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
|
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
|
||||||
if (alreadyCheckedDevices == null)
|
if (alreadyCheckedDevices == null)
|
||||||
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
|
alreadyCheckedDevices = new List<IRoutingInputsOutputs>();
|
||||||
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
|
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs);
|
||||||
|
|
||||||
foreach (var inputTieToTry in attachedMidpoints)
|
foreach (var tieLine in midpointTieLines)
|
||||||
{
|
{
|
||||||
var upstreamDeviceOutputPort = inputTieToTry.SourcePort;
|
var midpointDevice = tieLine.SourcePort.ParentDevice as IRoutingInputsOutputs;
|
||||||
var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs;
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {0}", destination, upstreamRoutingDevice.Key);
|
|
||||||
|
|
||||||
// Check if this previous device has already been walked
|
// Check if this previous device has already been walked
|
||||||
if (alreadyCheckedDevices.Contains(upstreamRoutingDevice))
|
if (alreadyCheckedDevices.Contains(midpointDevice))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {0} on {1}, this was already checked", destination, upstreamRoutingDevice.Key, destination.Key);
|
Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {midpointDeviceKey} on {destinationKey}, this was already checked", destination, midpointDevice.Key, destination.Key);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var midpointOutputPort = tieLine.SourcePort;
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {midpointDeviceKey}", destination, midpointDevice.Key);
|
||||||
|
|
||||||
// haven't seen this device yet. Do it. Pass the output port to the next
|
// haven't seen this device yet. Do it. Pass the output port to the next
|
||||||
// level to enable switching on success
|
// level to enable switching on success
|
||||||
var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
|
var upstreamRoutingSuccess = midpointDevice.GetRouteToSource(source, midpointOutputPort,
|
||||||
alreadyCheckedDevices, signalType, cycle, routeTable);
|
alreadyCheckedDevices, signalType, cycle, routeTable, null, sourcePort);
|
||||||
|
|
||||||
if (upstreamRoutingSuccess)
|
if (upstreamRoutingSuccess)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination);
|
Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination);
|
||||||
goodInputPort = inputTieToTry.DestinationPort;
|
Debug.LogMessage(LogEventLevel.Verbose, "Route found on {midpointDeviceKey}", destination, midpointDevice.Key);
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, "TieLine: SourcePort: {SourcePort} DestinationPort: {DestinationPort}", destination, tieLine.SourcePort, tieLine.DestinationPort);
|
||||||
|
goodInputPort = tieLine.DestinationPort;
|
||||||
break; // Stop looping the inputs in this cycle
|
break; // Stop looping the inputs in this cycle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (goodInputPort == null)
|
if (goodInputPort == null)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key);
|
Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we have a route on corresponding inputPort. *** Do the route ***
|
// we have a route on corresponding inputPort. *** Do the route ***
|
||||||
|
|
||||||
if (outputPortToUse == null)
|
if (destination is IRoutingSink)
|
||||||
{
|
{
|
||||||
// it's a sink device
|
// it's a sink device
|
||||||
routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
|
routeTable.Routes.Add(new RouteSwitchDescriptor(goodInputPort));
|
||||||
|
|
@ -244,8 +321,8 @@ namespace PepperDash.Essentials.Core
|
||||||
}
|
}
|
||||||
else // device is merely IRoutingInputOutputs
|
else // device is merely IRoutingInputOutputs
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination);
|
Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,261 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharpPro;
|
|
||||||
using Crestron.SimplSharpPro.DM;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
|
||||||
using Serilog.Events;
|
|
||||||
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extensions added to any IRoutingInputs classes to provide discovery-based routing
|
|
||||||
/// on those destinations.
|
|
||||||
/// </summary>
|
|
||||||
public static class GenericExtensions
|
|
||||||
{
|
|
||||||
//private static readonly Dictionary<string, RouteRequest<TInputSelector, TOutputSelector>> RouteRequests = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets any existing RouteDescriptor for a destination, clears it using ReleaseRoute
|
|
||||||
/// and then attempts a new Route and if sucessful, stores that RouteDescriptor
|
|
||||||
/// in RouteDescriptorCollection.DefaultCollection
|
|
||||||
/// </summary>
|
|
||||||
public static void ReleaseAndMakeRoute<TInputSelector, TOutputSelector>(this IRoutingSink<TInputSelector> destination, IRoutingOutputs<TOutputSelector> source, eRoutingSignalType signalType)
|
|
||||||
{
|
|
||||||
var routeRequest = new RouteRequest<TInputSelector, TOutputSelector> {
|
|
||||||
Destination = destination,
|
|
||||||
Source = source,
|
|
||||||
SignalType = signalType
|
|
||||||
};
|
|
||||||
|
|
||||||
var coolingDevice = destination as IWarmingCooling;
|
|
||||||
var existingRouteRequest = destination.GetRouteRequest<TOutputSelector>();
|
|
||||||
|
|
||||||
//We already have a route request for this device, and it's a cooling device and is cooling
|
|
||||||
if (existingRouteRequest != null && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
|
|
||||||
{
|
|
||||||
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
|
|
||||||
|
|
||||||
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
|
|
||||||
|
|
||||||
destination.UpdateRouteRequest(routeRequest);
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is cooling down and already has a routing request stored. Storing new route request to route to source key: {1}", null, destination.Key, routeRequest.Source.Key);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//New Request
|
|
||||||
if (coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == true)
|
|
||||||
{
|
|
||||||
coolingDevice.IsCoolingDownFeedback.OutputChange -= routeRequest.HandleCooldown;
|
|
||||||
|
|
||||||
coolingDevice.IsCoolingDownFeedback.OutputChange += routeRequest.HandleCooldown;
|
|
||||||
|
|
||||||
destination.UpdateRouteRequest(routeRequest);
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is cooling down. Storing route request to route to source key: {1}", null, destination.Key, routeRequest.Source.Key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingRouteRequest != null && coolingDevice != null && coolingDevice.IsCoolingDownFeedback.BoolValue == false)
|
|
||||||
{
|
|
||||||
destination.UpdateRouteRequest<TOutputSelector>(null);
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Device: {0} is NOT cooling down. Removing stored route request and routing to source key: {1}", null, destination.Key, routeRequest.Source.Key);
|
|
||||||
}
|
|
||||||
|
|
||||||
destination.ReleaseRoute();
|
|
||||||
|
|
||||||
RunRouteRequest(routeRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RunRouteRequest<TInputSelector, TOutputSelector>(RouteRequest<TInputSelector, TOutputSelector> request)
|
|
||||||
{
|
|
||||||
if (request.Source == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var newRoute = request.Destination.GetRouteToSource(request.Source, request.SignalType);
|
|
||||||
|
|
||||||
if (newRoute == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
RouteDescriptorCollection.DefaultCollection.AddRouteDescriptor(newRoute);
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Executing full route", request.Destination);
|
|
||||||
|
|
||||||
newRoute.ExecuteRoutes();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will release the existing route on the destination, if it is found in
|
|
||||||
/// RouteDescriptorCollection.DefaultCollection
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="destination"></param>
|
|
||||||
public static void ReleaseRoute<TInputSelector, TOutputSelector>(this IRoutingSink<TInputSelector> destination)
|
|
||||||
{
|
|
||||||
var existingRouteRequest = destination.GetRouteRequest<TOutputSelector>();
|
|
||||||
|
|
||||||
if (existingRouteRequest != null && destination is IWarmingCooling)
|
|
||||||
{
|
|
||||||
var coolingDevice = destination as IWarmingCooling;
|
|
||||||
|
|
||||||
coolingDevice.IsCoolingDownFeedback.OutputChange -= existingRouteRequest.HandleCooldown;
|
|
||||||
}
|
|
||||||
|
|
||||||
destination.UpdateRouteRequest<TOutputSelector>(null);
|
|
||||||
|
|
||||||
var current = RouteDescriptorCollection<TInputSelector, TOutputSelector>.DefaultCollection.RemoveRouteDescriptor(destination);
|
|
||||||
if (current != null)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Releasing current route: {0}", destination, current.Source.Key);
|
|
||||||
current.ReleaseRoutes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Builds a RouteDescriptor that contains the steps necessary to make a route between devices.
|
|
||||||
/// Routes of type AudioVideo will be built as two separate routes, audio and video. If
|
|
||||||
/// a route is discovered, a new RouteDescriptor is returned. If one or both parts
|
|
||||||
/// of an audio/video route are discovered a route descriptor is returned. If no route is
|
|
||||||
/// discovered, then null is returned
|
|
||||||
/// </summary>
|
|
||||||
public static RouteDescriptor<TInputSelector, TOutputSelector> GetRouteToSource<TInputSelector, TOutputSelector>(this IRoutingSink<TInputSelector> destination, IRoutingOutputs<TOutputSelector> source, eRoutingSignalType signalType)
|
|
||||||
{
|
|
||||||
var routeDescriptor = new RouteDescriptor<TInputSelector, TOutputSelector>(source, destination, signalType);
|
|
||||||
|
|
||||||
// if it's a single signal type, find the route
|
|
||||||
if (!signalType.HasFlag(eRoutingSignalType.AudioVideo))
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build source route from {0}", null, source.Key);
|
|
||||||
|
|
||||||
if (!destination.GetRouteToSource(source, null, null, signalType, 0, routeDescriptor))
|
|
||||||
routeDescriptor = null;
|
|
||||||
|
|
||||||
return routeDescriptor;
|
|
||||||
}
|
|
||||||
// otherwise, audioVideo needs to be handled as two steps.
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Attempting to build audio and video routes from {0}", destination, source.Key);
|
|
||||||
|
|
||||||
var audioSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Audio, 0, routeDescriptor);
|
|
||||||
|
|
||||||
if (!audioSuccess)
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Cannot find audio route to {0}", destination, source.Key);
|
|
||||||
|
|
||||||
var videoSuccess = destination.GetRouteToSource(source, null, null, eRoutingSignalType.Video, 0, routeDescriptor);
|
|
||||||
|
|
||||||
if (!videoSuccess)
|
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Cannot find video route to {0}", destination, source.Key);
|
|
||||||
|
|
||||||
if (!audioSuccess && !videoSuccess)
|
|
||||||
routeDescriptor = null;
|
|
||||||
|
|
||||||
|
|
||||||
return routeDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The recursive part of this. Will stop on each device, search its inputs for the
|
|
||||||
/// desired source and if not found, invoke this function for the each input port
|
|
||||||
/// hoping to find the source.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="destination"></param>
|
|
||||||
/// <param name="source"></param>
|
|
||||||
/// <param name="outputPortToUse">The RoutingOutputPort whose link is being checked for a route</param>
|
|
||||||
/// <param name="alreadyCheckedDevices">Prevents Devices from being twice-checked</param>
|
|
||||||
/// <param name="signalType">This recursive function should not be called with AudioVideo</param>
|
|
||||||
/// <param name="cycle">Just an informational counter</param>
|
|
||||||
/// <param name="routeTable">The RouteDescriptor being populated as the route is discovered</param>
|
|
||||||
/// <returns>true if source is hit</returns>
|
|
||||||
static bool GetRouteToSource<TInputSelector, TOutputSelector>(this IRoutingInputs<TInputSelector> destination, IRoutingOutputs<TOutputSelector> source,
|
|
||||||
RoutingOutputPort<TOutputSelector> outputPortToUse, List<IRoutingInputsOutputs<TInputSelector, TOutputSelector>> alreadyCheckedDevices,
|
|
||||||
eRoutingSignalType signalType, int cycle, RouteDescriptor<TInputSelector, TOutputSelector> routeTable)
|
|
||||||
{
|
|
||||||
|
|
||||||
cycle++;
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "GetRouteToSource: {0} {1}--> {2}", null, cycle, source.Key, destination.Key);
|
|
||||||
|
|
||||||
RoutingInputPort<TInputSelector> goodInputPort = null;
|
|
||||||
|
|
||||||
var destDevInputTies = TieLineCollection.Default.Where(t =>
|
|
||||||
t.DestinationPort.ParentDevice == destination && (t.Type == signalType || t.Type.HasFlag(eRoutingSignalType.AudioVideo)));
|
|
||||||
|
|
||||||
// find a direct tie
|
|
||||||
var directTie = destDevInputTies.FirstOrDefault(
|
|
||||||
t => t.DestinationPort.ParentDevice == destination
|
|
||||||
&& t.SourcePort.ParentDevice == source);
|
|
||||||
if (directTie != null) // Found a tie directly to the source
|
|
||||||
{
|
|
||||||
goodInputPort = directTie.DestinationPort;
|
|
||||||
}
|
|
||||||
else // no direct-connect. Walk back devices.
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "is not directly connected to {0}. Walking down tie lines", destination, source.Key);
|
|
||||||
|
|
||||||
// No direct tie? Run back out on the inputs' attached devices...
|
|
||||||
// Only the ones that are routing devices
|
|
||||||
var attachedMidpoints = destDevInputTies.Where(t => t.SourcePort.ParentDevice is IRoutingInputsOutputs);
|
|
||||||
|
|
||||||
//Create a list for tracking already checked devices to avoid loops, if it doesn't already exist from previous iteration
|
|
||||||
if (alreadyCheckedDevices == null)
|
|
||||||
alreadyCheckedDevices = new List<IRoutingInputsOutputs<TInputSelector, TOutputSelector>>();
|
|
||||||
alreadyCheckedDevices.Add(destination as IRoutingInputsOutputs<TInputSelector, TOutputSelector>);
|
|
||||||
|
|
||||||
foreach (var inputTieToTry in attachedMidpoints)
|
|
||||||
{
|
|
||||||
var upstreamDeviceOutputPort = inputTieToTry.SourcePort;
|
|
||||||
var upstreamRoutingDevice = upstreamDeviceOutputPort.ParentDevice as IRoutingInputsOutputs<TInputSelector, TOutputSelector>;
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Trying to find route on {0}", destination, upstreamRoutingDevice.Key);
|
|
||||||
|
|
||||||
// Check if this previous device has already been walked
|
|
||||||
if (alreadyCheckedDevices.Contains(upstreamRoutingDevice))
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Skipping input {0} on {1}, this was already checked", destination, upstreamRoutingDevice.Key, destination.Key);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// haven't seen this device yet. Do it. Pass the output port to the next
|
|
||||||
// level to enable switching on success
|
|
||||||
var upstreamRoutingSuccess = upstreamRoutingDevice.GetRouteToSource(source, upstreamDeviceOutputPort,
|
|
||||||
alreadyCheckedDevices, signalType, cycle, routeTable);
|
|
||||||
if (upstreamRoutingSuccess)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Upstream device route found", destination);
|
|
||||||
goodInputPort = inputTieToTry.DestinationPort;
|
|
||||||
break; // Stop looping the inputs in this cycle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (goodInputPort == null)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "No route found to {0}", destination, source.Key);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we have a route on corresponding inputPort. *** Do the route ***
|
|
||||||
|
|
||||||
if (outputPortToUse == null)
|
|
||||||
{
|
|
||||||
// it's a sink device
|
|
||||||
routeTable.Routes.Add(new RouteSwitchDescriptor<TInputSelector, TOutputSelector>(goodInputPort));
|
|
||||||
}
|
|
||||||
else if (destination is IRouting)
|
|
||||||
{
|
|
||||||
routeTable.Routes.Add(new RouteSwitchDescriptor<TInputSelector, TOutputSelector>(outputPortToUse, goodInputPort));
|
|
||||||
}
|
|
||||||
else // device is merely IRoutingInputOutputs
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "No routing. Passthrough device", destination);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines an IRoutingOutputs devices as being a source - the start of the chain
|
/// Defines an IRoutingOutputs devices as being a source - the start of the chain
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IRoutingSource
|
public interface IRoutingSource : IRoutingOutputs
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,19 +2,22 @@
|
||||||
{
|
{
|
||||||
public class RouteRequest
|
public class RouteRequest
|
||||||
{
|
{
|
||||||
public IRoutingSink Destination {get; set;}
|
public RoutingInputPort DestinationPort { get; set; }
|
||||||
public IRoutingOutputs Source {get; set;}
|
|
||||||
public eRoutingSignalType SignalType {get; set;}
|
public RoutingOutputPort SourcePort { get; set; }
|
||||||
|
public IRoutingInputs Destination { get; set; }
|
||||||
|
public IRoutingOutputs Source { get; set; }
|
||||||
|
public eRoutingSignalType SignalType { get; set; }
|
||||||
|
|
||||||
public void HandleCooldown(object sender, FeedbackEventArgs args)
|
public void HandleCooldown(object sender, FeedbackEventArgs args)
|
||||||
{
|
{
|
||||||
var coolingDevice = sender as IWarmingCooling;
|
var coolingDevice = sender as IWarmingCooling;
|
||||||
|
|
||||||
if(args.BoolValue == false)
|
if (args.BoolValue == false)
|
||||||
{
|
{
|
||||||
Destination.ReleaseAndMakeRoute(Source, SignalType);
|
Destination.ReleaseAndMakeRoute(Source, SignalType);
|
||||||
|
|
||||||
if(sender == null) return;
|
if (sender == null) return;
|
||||||
|
|
||||||
coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown;
|
coolingDevice.IsCoolingDownFeedback.OutputChange -= HandleCooldown;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -239,5 +239,13 @@ namespace PepperDash.Essentials.Core
|
||||||
/// HdBaseTOut
|
/// HdBaseTOut
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string HdBaseTOut = "hdBaseTOut";
|
public const string HdBaseTOut = "hdBaseTOut";
|
||||||
|
/// <summary>
|
||||||
|
/// SdiIn
|
||||||
|
/// </summary>
|
||||||
|
public const string SdiIn = "sdiIn";
|
||||||
|
/// <summary>
|
||||||
|
/// SdiOut
|
||||||
|
/// </summary>
|
||||||
|
public const string SdiOut = "sdiOut";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,98 +1,91 @@
|
||||||
using System;
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharpPro;
|
|
||||||
using Crestron.SimplSharpPro.DM;
|
|
||||||
|
|
||||||
using PepperDash.Core;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core
|
namespace PepperDash.Essentials.Core
|
||||||
{
|
{
|
||||||
public class TieLine
|
public class TieLine
|
||||||
{
|
{
|
||||||
public RoutingOutputPort SourcePort { get; private set; }
|
public RoutingOutputPort SourcePort { get; private set; }
|
||||||
public RoutingInputPort DestinationPort { get; private set; }
|
public RoutingInputPort DestinationPort { get; private set; }
|
||||||
//public int InUseCount { get { return DestinationUsingThis.Count; } }
|
//public int InUseCount { get { return DestinationUsingThis.Count; } }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the type of this tie line. Will either be the type of the desination port
|
/// Gets the type of this tie line. Will either be the type of the desination port
|
||||||
/// or the type of OverrideType when it is set.
|
/// or the type of OverrideType when it is set.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public eRoutingSignalType Type
|
public eRoutingSignalType Type
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (OverrideType.HasValue) return OverrideType.Value;
|
if (OverrideType.HasValue) return OverrideType.Value;
|
||||||
return DestinationPort.Type;
|
return DestinationPort.Type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Use this to override the Type property for the destination port. For example,
|
/// Use this to override the Type property for the destination port. For example,
|
||||||
/// when the tie line is type AudioVideo, and the signal flow should be limited to
|
/// when the tie line is type AudioVideo, and the signal flow should be limited to
|
||||||
/// Audio-only or Video only, changing this type will alter the signal paths
|
/// Audio-only or Video only, changing this type will alter the signal paths
|
||||||
/// available to the routing algorithm without affecting the actual Type
|
/// available to the routing algorithm without affecting the actual Type
|
||||||
/// of the destination port.
|
/// of the destination port.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public eRoutingSignalType? OverrideType { get; set; }
|
public eRoutingSignalType? OverrideType { get; set; }
|
||||||
|
|
||||||
//List<IRoutingInputs> DestinationUsingThis = new List<IRoutingInputs>();
|
//List<IRoutingInputs> DestinationUsingThis = new List<IRoutingInputs>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// For tie lines that represent internal links, like from cards to the matrix in a DM.
|
/// For tie lines that represent internal links, like from cards to the matrix in a DM.
|
||||||
/// This property is true if SourcePort and DestinationPort IsInternal
|
/// This property is true if SourcePort and DestinationPort IsInternal
|
||||||
/// property are both true
|
/// property are both true
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsInternal { get { return SourcePort.IsInternal && DestinationPort.IsInternal; } }
|
public bool IsInternal { get { return SourcePort.IsInternal && DestinationPort.IsInternal; } }
|
||||||
public bool TypeMismatch { get { return SourcePort.Type != DestinationPort.Type; } }
|
public bool TypeMismatch { get { return SourcePort.Type != DestinationPort.Type; } }
|
||||||
public bool ConnectionTypeMismatch { get { return SourcePort.ConnectionType != DestinationPort.ConnectionType; } }
|
public bool ConnectionTypeMismatch { get { return SourcePort.ConnectionType != DestinationPort.ConnectionType; } }
|
||||||
public string TypeMismatchNote { get; set; }
|
public string TypeMismatchNote { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sourcePort"></param>
|
/// <param name="sourcePort"></param>
|
||||||
/// <param name="destinationPort"></param>
|
/// <param name="destinationPort"></param>
|
||||||
public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort)
|
public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort)
|
||||||
{
|
{
|
||||||
if (sourcePort == null || destinationPort == null)
|
if (sourcePort == null || destinationPort == null)
|
||||||
throw new ArgumentNullException("source or destination port");
|
throw new ArgumentNullException("source or destination port");
|
||||||
SourcePort = sourcePort;
|
SourcePort = sourcePort;
|
||||||
DestinationPort = destinationPort;
|
DestinationPort = destinationPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a tie line with an overriding Type. See help for OverrideType property for info
|
/// Creates a tie line with an overriding Type. See help for OverrideType property for info
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="overrideType">The signal type to limit the link to. Overrides DestinationPort.Type</param>
|
/// <param name="overrideType">The signal type to limit the link to. Overrides DestinationPort.Type</param>
|
||||||
public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType overrideType) :
|
public TieLine(RoutingOutputPort sourcePort, RoutingInputPort destinationPort, eRoutingSignalType overrideType) :
|
||||||
this(sourcePort, destinationPort)
|
this(sourcePort, destinationPort)
|
||||||
{
|
{
|
||||||
OverrideType = overrideType;
|
OverrideType = overrideType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Will link up video status from supporting inputs to connected outputs
|
/// Will link up video status from supporting inputs to connected outputs
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Activate()
|
public void Activate()
|
||||||
{
|
{
|
||||||
// Now does nothing
|
// Now does nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Deactivate()
|
public void Deactivate()
|
||||||
{
|
{
|
||||||
// Now does nothing
|
// Now does nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return string.Format("Tie line: {0}:{1} --> {2}:{3}", SourcePort.ParentDevice.Key, SourcePort.Key,
|
return string.Format("Tie line: {0}:{1} --> {2}:{3} {4}", SourcePort.ParentDevice.Key, SourcePort.Key,
|
||||||
DestinationPort.ParentDevice.Key, DestinationPort.Key);
|
DestinationPort.ParentDevice.Key, DestinationPort.Key, Type.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//********************************************************************************
|
//********************************************************************************
|
||||||
|
|
||||||
|
|
@ -109,6 +102,6 @@ namespace PepperDash.Essentials.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
static TieLineCollection _Default;
|
private static TieLineCollection _Default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,8 +52,8 @@ namespace PepperDash.Essentials.Core
|
||||||
|
|
||||||
var timeSpan = FinishTime - DateTime.Now;
|
var timeSpan = FinishTime - DateTime.Now;
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this,
|
Debug.LogMessage(LogEventLevel.Verbose,
|
||||||
"timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}",
|
"timeSpan.Minutes == {0}, timeSpan.Seconds == {1}, timeSpan.TotalSeconds == {2}", this,
|
||||||
timeSpan.Minutes, timeSpan.Seconds, timeSpan.TotalSeconds);
|
timeSpan.Minutes, timeSpan.Seconds, timeSpan.TotalSeconds);
|
||||||
|
|
||||||
if (Math.Floor(timeSpan.TotalSeconds) < 60 && Math.Floor(timeSpan.TotalSeconds) >= 0) //ignore milliseconds
|
if (Math.Floor(timeSpan.TotalSeconds) < 60 && Math.Floor(timeSpan.TotalSeconds) >= 0) //ignore milliseconds
|
||||||
|
|
@ -103,6 +103,7 @@ namespace PepperDash.Essentials.Core
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
|
IsRunningFeedback.FireUpdate();
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,7 +134,11 @@ namespace PepperDash.Essentials.Core
|
||||||
void StopHelper()
|
void StopHelper()
|
||||||
{
|
{
|
||||||
if (_secondTimer != null)
|
if (_secondTimer != null)
|
||||||
|
{
|
||||||
_secondTimer.Stop();
|
_secondTimer.Stop();
|
||||||
|
_secondTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
_isRunning = false;
|
_isRunning = false;
|
||||||
IsRunningFeedback.FireUpdate();
|
IsRunningFeedback.FireUpdate();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ namespace PepperDash.Essentials.Core.Web
|
||||||
{
|
{
|
||||||
Type = device.Key,
|
Type = device.Key,
|
||||||
Description = device.Value.Description,
|
Description = device.Value.Description,
|
||||||
CType = device.Value.CType == null ? "---": device.Value.CType.ToString()
|
CType = device.Value.Type == null ? "---": device.Value.Type.ToString()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,24 @@
|
||||||
using Crestron.SimplSharp.WebScripting;
|
using Crestron.SimplSharp.WebScripting;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PepperDash.Core.Web.RequestHandlers;
|
using PepperDash.Core.Web.RequestHandlers;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||||
{
|
{
|
||||||
public class GetTieLinesRequestHandler:WebApiBaseRequestHandler
|
public class GetTieLinesRequestHandler : WebApiBaseRequestHandler
|
||||||
{
|
{
|
||||||
public GetTieLinesRequestHandler() : base(true) { }
|
public GetTieLinesRequestHandler() : base(true) { }
|
||||||
|
|
||||||
protected override void HandleGet(HttpCwsContext context)
|
protected override void HandleGet(HttpCwsContext context)
|
||||||
{
|
{
|
||||||
var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new {
|
var tieLineString = JsonConvert.SerializeObject(TieLineCollection.Default.Select((tl) => new
|
||||||
|
{
|
||||||
sourceKey = tl.SourcePort.ParentDevice.Key,
|
sourceKey = tl.SourcePort.ParentDevice.Key,
|
||||||
sourcePort = tl.SourcePort.Key,
|
sourcePort = tl.SourcePort.Key,
|
||||||
destinationKey = tl.DestinationPort.ParentDevice.Key,
|
destinationKey = tl.DestinationPort.ParentDevice.Key,
|
||||||
destinationPort = tl.DestinationPort.Key
|
destinationPort = tl.DestinationPort.Key,
|
||||||
|
type = tl.Type.ToString(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
context.Response.StatusCode = 200;
|
context.Response.StatusCode = 200;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
using Crestron.SimplSharpPro.DeviceSupport;
|
using Crestron.SimplSharpPro.DeviceSupport;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ using PepperDash.Essentials.Core.Bridges;
|
||||||
using PepperDash.Essentials.Core.Config;
|
using PepperDash.Essentials.Core.Config;
|
||||||
using PepperDash.Essentials.Devices.Common.Codec;
|
using PepperDash.Essentials.Devices.Common.Codec;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace PepperDash.Essentials.Devices.Common
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var factory = (IDeviceFactory)Crestron.SimplSharp.Reflection.Activator.CreateInstance(type);
|
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||||
factory.LoadTypeFactories();
|
factory.LoadTypeFactories();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
||||||
// Fake cool-down cycle
|
// Fake cool-down cycle
|
||||||
CooldownTimer = new CTimer(o =>
|
CooldownTimer = new CTimer(o =>
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Cooldown timer ending");
|
Debug.LogMessage(LogEventLevel.Verbose, "Cooldown timer ending", this);
|
||||||
_IsCoolingDown = false;
|
_IsCoolingDown = false;
|
||||||
IsCoolingDownFeedback.InvokeFireUpdate();
|
IsCoolingDownFeedback.InvokeFireUpdate();
|
||||||
_PowerIsOn = false;
|
_PowerIsOn = false;
|
||||||
|
|
@ -143,10 +143,10 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector);
|
Debug.LogMessage(LogEventLevel.Verbose, "ExecuteSwitch: {0}", this, selector);
|
||||||
|
|
||||||
if (!_PowerIsOn)
|
if (!_PowerIsOn)
|
||||||
{
|
{
|
||||||
PowerOn();
|
PowerOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Inputs.Items.TryGetValue(selector.ToString(), out var input))
|
if (!Inputs.Items.TryGetValue(selector.ToString(), out var input))
|
||||||
return;
|
return;
|
||||||
|
|
@ -200,7 +200,6 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region IBasicVolumeWithFeedback Members
|
#region IBasicVolumeWithFeedback Members
|
||||||
|
|
||||||
public IntFeedback VolumeLevelFeedback { get; private set; }
|
public IntFeedback VolumeLevelFeedback { get; private set; }
|
||||||
|
|
@ -270,21 +269,19 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
||||||
{
|
{
|
||||||
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
|
LinkDisplayToApi(this, trilist, joinStart, joinMapKey, bridge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
|
public class MockDisplayFactory : EssentialsDeviceFactory<MockDisplay>
|
||||||
{
|
{
|
||||||
public MockDisplayFactory()
|
public MockDisplayFactory()
|
||||||
{
|
{
|
||||||
TypeNames = new List<string>() { "mockdisplay2" };
|
TypeNames = new List<string>() { "mockdisplay" , "mockdisplay2" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device");
|
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Mock Display Device");
|
||||||
return new MockDisplay(dc.Key, dc.Name);
|
return new MockDisplay(dc.Key, dc.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -54,8 +54,7 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
||||||
|
|
||||||
public class MockDisplayInput : ISelectableItem
|
public class MockDisplayInput : ISelectableItem
|
||||||
{
|
{
|
||||||
private IHasInputs<string, string> _parent;
|
private MockDisplay _parent;
|
||||||
|
|
||||||
|
|
||||||
private bool _isSelected;
|
private bool _isSelected;
|
||||||
|
|
||||||
|
|
@ -91,7 +90,12 @@ namespace PepperDash.Essentials.Devices.Common.Displays
|
||||||
|
|
||||||
public void Select()
|
public void Select()
|
||||||
{
|
{
|
||||||
_parent.SetInput(Key);
|
if (!_parent.PowerIsOnFeedback.BoolValue) _parent.PowerOn();
|
||||||
|
|
||||||
|
foreach(var input in _parent.Inputs.Items)
|
||||||
|
{
|
||||||
|
input.Value.IsSelected = input.Key == this.Key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,266 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Crestron.SimplSharp;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Essentials.Core;
|
||||||
|
using PepperDash.Essentials.Core.Config;
|
||||||
|
using PepperDash.Essentials.Core.CrestronIO;
|
||||||
|
using PepperDash.Essentials.Core.DeviceTypeInterfaces;
|
||||||
|
using PepperDash.Essentials.Devices.Common;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Devices.Common.Shades
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Controls a single shade using three relays
|
||||||
|
/// </summary>
|
||||||
|
public class ScreenLiftController : EssentialsDevice, IProjectorScreenLiftControl
|
||||||
|
{
|
||||||
|
readonly ScreenLiftControllerConfigProperties Config;
|
||||||
|
readonly ScreenLiftRelaysConfig RaiseRelayConfig;
|
||||||
|
readonly ScreenLiftRelaysConfig LowerRelayConfig;
|
||||||
|
readonly ScreenLiftRelaysConfig LatchedRelayConfig;
|
||||||
|
|
||||||
|
Displays.DisplayBase DisplayDevice;
|
||||||
|
ISwitchedOutput RaiseRelay;
|
||||||
|
ISwitchedOutput LowerRelay;
|
||||||
|
ISwitchedOutput LatchedRelay;
|
||||||
|
|
||||||
|
public bool InUpPosition
|
||||||
|
{
|
||||||
|
get { return _isInUpPosition; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _isInUpPosition) return;
|
||||||
|
_isInUpPosition = value;
|
||||||
|
IsInUpPosition.FireUpdate();
|
||||||
|
PositionChanged?.Invoke(this, new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isInUpPosition { get; set; }
|
||||||
|
public eScreenLiftControlType Type { get; private set; }
|
||||||
|
public eScreenLiftControlMode Mode { get; private set; }
|
||||||
|
|
||||||
|
public string DisplayDeviceKey { get; private set; }
|
||||||
|
public BoolFeedback IsInUpPosition { get; private set; }
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs> PositionChanged;
|
||||||
|
|
||||||
|
public ScreenLiftController(string key, string name, ScreenLiftControllerConfigProperties config)
|
||||||
|
: base(key, name)
|
||||||
|
{
|
||||||
|
Config = config;
|
||||||
|
DisplayDeviceKey = Config.DisplayDeviceKey;
|
||||||
|
Mode = Config.Mode;
|
||||||
|
Type = Config.Type;
|
||||||
|
|
||||||
|
IsInUpPosition = new BoolFeedback(() => _isInUpPosition);
|
||||||
|
|
||||||
|
switch (Mode)
|
||||||
|
{
|
||||||
|
case eScreenLiftControlMode.momentary:
|
||||||
|
{
|
||||||
|
RaiseRelayConfig = Config.Relays["raise"];
|
||||||
|
LowerRelayConfig = Config.Relays["lower"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case eScreenLiftControlMode.latched:
|
||||||
|
{
|
||||||
|
LatchedRelayConfig = Config.Relays["latched"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||||
|
{
|
||||||
|
if (!DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.lift)
|
||||||
|
{
|
||||||
|
Raise();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DisplayDevice.IsCoolingDownFeedback.BoolValue && Type == eScreenLiftControlType.screen)
|
||||||
|
{
|
||||||
|
Raise();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e)
|
||||||
|
{
|
||||||
|
if (DisplayDevice.IsWarmingUpFeedback.BoolValue)
|
||||||
|
{
|
||||||
|
Lower();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CustomActivate()
|
||||||
|
{
|
||||||
|
//Create ISwitchedOutput objects based on props
|
||||||
|
switch (Mode)
|
||||||
|
{
|
||||||
|
case eScreenLiftControlMode.momentary:
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, this, $"Getting relays for {Mode}");
|
||||||
|
RaiseRelay = GetSwitchedOutputFromDevice(RaiseRelayConfig.DeviceKey);
|
||||||
|
LowerRelay = GetSwitchedOutputFromDevice(LowerRelayConfig.DeviceKey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case eScreenLiftControlMode.latched:
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, this, $"Getting relays for {Mode}");
|
||||||
|
LatchedRelay = GetSwitchedOutputFromDevice(LatchedRelayConfig.DeviceKey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, this, $"Getting display with key {DisplayDeviceKey}");
|
||||||
|
DisplayDevice = GetDisplayBaseFromDevice(DisplayDeviceKey);
|
||||||
|
|
||||||
|
if (DisplayDevice != null)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, this, $"Subscribing to {DisplayDeviceKey} feedbacks");
|
||||||
|
|
||||||
|
DisplayDevice.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange;
|
||||||
|
DisplayDevice.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.CustomActivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Raise()
|
||||||
|
{
|
||||||
|
if (RaiseRelay == null && LatchedRelay == null) return;
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, this, $"Raising {Type}");
|
||||||
|
|
||||||
|
switch (Mode)
|
||||||
|
{
|
||||||
|
case eScreenLiftControlMode.momentary:
|
||||||
|
{
|
||||||
|
PulseOutput(RaiseRelay, RaiseRelayConfig.PulseTimeInMs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case eScreenLiftControlMode.latched:
|
||||||
|
{
|
||||||
|
LatchedRelay.Off();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InUpPosition = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Lower()
|
||||||
|
{
|
||||||
|
if (LowerRelay == null && LatchedRelay == null) return;
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, this, $"Lowering {Type}");
|
||||||
|
|
||||||
|
switch (Mode)
|
||||||
|
{
|
||||||
|
case eScreenLiftControlMode.momentary:
|
||||||
|
{
|
||||||
|
PulseOutput(LowerRelay, LowerRelayConfig.PulseTimeInMs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case eScreenLiftControlMode.latched:
|
||||||
|
{
|
||||||
|
LatchedRelay.On();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InUpPosition = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PulseOutput(ISwitchedOutput output, int pulseTime)
|
||||||
|
{
|
||||||
|
output.On();
|
||||||
|
CTimer pulseTimer = new CTimer(new CTimerCallbackFunction((o) => output.Off()), pulseTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to get the port on teh specified device from config
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="relayConfig"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ISwitchedOutput GetSwitchedOutputFromDevice(string relayKey)
|
||||||
|
{
|
||||||
|
var portDevice = DeviceManager.GetDeviceForKey(relayKey);
|
||||||
|
if (portDevice != null)
|
||||||
|
{
|
||||||
|
return (portDevice as ISwitchedOutput);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get relay device with key '{0}'", relayKey);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Displays.DisplayBase GetDisplayBaseFromDevice(string displayKey)
|
||||||
|
{
|
||||||
|
var displayDevice = DeviceManager.GetDeviceForKey(displayKey);
|
||||||
|
if (displayDevice != null)
|
||||||
|
{
|
||||||
|
return displayDevice as Displays.DisplayBase;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, this, "Error: Unable to get display device with key '{0}'", displayKey);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScreenLiftControllerConfigProperties
|
||||||
|
{
|
||||||
|
[JsonProperty("displayDeviceKey")]
|
||||||
|
public string DisplayDeviceKey { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("type")]
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public eScreenLiftControlType Type { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("mode")]
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public eScreenLiftControlMode Mode { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("relays")]
|
||||||
|
public Dictionary<string,ScreenLiftRelaysConfig> Relays { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
public class ScreenLiftRelaysConfig
|
||||||
|
{
|
||||||
|
[JsonProperty("deviceKey")]
|
||||||
|
public string DeviceKey { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("pulseTimeInMs")]
|
||||||
|
public int PulseTimeInMs { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScreenLiftControllerFactory : EssentialsDeviceFactory<RelayControlledShade>
|
||||||
|
{
|
||||||
|
public ScreenLiftControllerFactory()
|
||||||
|
{
|
||||||
|
TypeNames = new List<string>() { "screenliftcontroller" };
|
||||||
|
}
|
||||||
|
|
||||||
|
public override EssentialsDevice BuildDevice(DeviceConfig dc)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Debug, "Factory Attempting to create new Generic Comm Device");
|
||||||
|
var props = Newtonsoft.Json.JsonConvert.DeserializeObject<ScreenLiftControllerConfigProperties>(dc.Properties.ToString());
|
||||||
|
|
||||||
|
return new ScreenLiftController(dc.Key, dc.Name, props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum eScreenLiftControlMode
|
||||||
|
{
|
||||||
|
momentary,
|
||||||
|
latched
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,7 +13,7 @@ using Serilog.Events;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Devices.Common
|
namespace PepperDash.Essentials.Devices.Common
|
||||||
{
|
{
|
||||||
public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IRoutingOutputs, IUsageTracking
|
public class GenericSource : EssentialsDevice, IUiDisplayInfo, IRoutingSource, IUsageTracking
|
||||||
{
|
{
|
||||||
|
|
||||||
public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } }
|
public uint DisplayUiType { get { return DisplayUiConstants.TypeNoControls; } }
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<Title>PepperDash Essentials Devices Common</Title>
|
<Title>PepperDash Essentials Devices Common</Title>
|
||||||
<PackageId>PepperDash.Essentials.Devices.Common</PackageId>
|
<PackageId>PepperDash.Essentials.Devices.Common</PackageId>
|
||||||
|
<Version>2.0.0-local</Version>
|
||||||
<InformationalVersion>$(Version)</InformationalVersion>
|
<InformationalVersion>$(Version)</InformationalVersion>
|
||||||
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
|
|
@ -28,6 +30,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
|
||||||
<PackageReference Include="PepperDashCore" Version="2.0.0-beta-423" />
|
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-424" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -5,7 +5,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
using Crestron.SimplSharpPro;
|
using Crestron.SimplSharpPro;
|
||||||
using Crestron.SimplSharpPro.DeviceSupport;
|
using Crestron.SimplSharpPro.DeviceSupport;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
@ -42,7 +42,7 @@ namespace PepperDash.Essentials.Devices.Common
|
||||||
|
|
||||||
public void PrintExpectedIrCommands()
|
public void PrintExpectedIrCommands()
|
||||||
{
|
{
|
||||||
var cmds = typeof (AppleTvIrCommands).GetCType().GetFields(BindingFlags.Public | BindingFlags.Static);
|
var cmds = typeof (AppleTvIrCommands).GetType().GetFields(BindingFlags.Public | BindingFlags.Static);
|
||||||
|
|
||||||
foreach (var value in cmds.Select(cmd => cmd.GetValue(null)).OfType<string>())
|
foreach (var value in cmds.Select(cmd => cmd.GetValue(null)).OfType<string>())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1214,7 +1214,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
|
||||||
var entryIndex = counterIndex;
|
var entryIndex = counterIndex;
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, this, "Entry{2:0000} Name: {0}, Folder ID: {1}, Type: {3}, ParentFolderId: {4}",
|
Debug.LogMessage(LogEventLevel.Verbose, this, "Entry{2:0000} Name: {0}, Folder ID: {1}, Type: {3}, ParentFolderId: {4}",
|
||||||
entry.Name, entry.FolderId, entryIndex, entry.GetType().GetCType().FullName, entry.ParentFolderId);
|
entry.Name, entry.FolderId, entryIndex, entry.GetType().GetType().FullName, entry.ParentFolderId);
|
||||||
|
|
||||||
if (entry is DirectoryFolder)
|
if (entry is DirectoryFolder)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
using Crestron.SimplSharpPro;
|
using Crestron.SimplSharpPro;
|
||||||
using Crestron.SimplSharpPro.CrestronThread;
|
using Crestron.SimplSharpPro.CrestronThread;
|
||||||
using Crestron.SimplSharpPro.Diagnostics;
|
using Crestron.SimplSharpPro.Diagnostics;
|
||||||
|
|
@ -177,11 +177,7 @@ namespace PepperDash.Essentials
|
||||||
|
|
||||||
directoryPrefix = Directory.GetApplicationRootDirectory();
|
directoryPrefix = Directory.GetApplicationRootDirectory();
|
||||||
|
|
||||||
var fullVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
Global.SetAssemblyVersion(PluginLoader.GetAssemblyVersion(Assembly.GetExecutingAssembly()));
|
||||||
|
|
||||||
Global.SetAssemblyVersion(fullVersion);
|
|
||||||
|
|
||||||
//Global.SetAssemblyVersion(fullVersionAtt.InformationalVersion);
|
|
||||||
|
|
||||||
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows CE OS
|
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows CE OS
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
"supportedSystemTypes": [
|
"supportedSystemTypes": [
|
||||||
"hudType",
|
"hudType",
|
||||||
"presType",
|
"presType",
|
||||||
"vtcType",
|
"vtType",
|
||||||
"custom"
|
"custom"
|
||||||
],
|
],
|
||||||
"type": "rmc3",
|
"type": "rmc3",
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var factory = (IDeviceFactory)Crestron.SimplSharp.Reflection.Activator.CreateInstance(type);
|
var factory = (IDeviceFactory)Activator.CreateInstance(type);
|
||||||
factory.LoadTypeFactories();
|
factory.LoadTypeFactories();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<Title>PepperDash Essentials</Title>
|
<Title>PepperDash Essentials</Title>
|
||||||
<PackageId>PepperDashEssentials</PackageId>
|
<PackageId>PepperDashEssentials</PackageId>
|
||||||
|
<Version>2.0.0-local</Version>
|
||||||
<InformationalVersion>$(Version)</InformationalVersion>
|
<InformationalVersion>$(Version)</InformationalVersion>
|
||||||
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
|
|
@ -47,7 +49,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.20.66" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.20.66" />
|
||||||
<PackageReference Include="PepperDashCore" Version="2.0.0-beta-423" />
|
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-424" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
|
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue