Implementation of feature/glspartcn-partition-sensor

Resolves #270
This commit is contained in:
Jason DeVito
2020-06-30 10:06:39 -05:00
parent e8a8d481aa
commit 8f35d13d4b
25 changed files with 1154 additions and 642 deletions

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.Bridges.JoinMaps
{
public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced
{
[JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete(
new JoinData()
{
JoinNumber = 1,
JoinSpan = 1
},
new JoinMetadata()
{
Description = "Sensor Is Online",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("Name")]
public JoinDataComplete Name = new JoinDataComplete(
new JoinData()
{
JoinNumber = 1,
JoinSpan = 1
},
new JoinMetadata()
{
Description = "Sensor Name",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("Enable")]
public JoinDataComplete Enable = new JoinDataComplete(
new JoinData()
{
JoinNumber = 2,
JoinSpan = 1
},
new JoinMetadata()
{
Description = "Sensor Enable",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("PartitionSensed")]
public JoinDataComplete PartitionSensed = new JoinDataComplete(
new JoinData()
{
JoinNumber = 3,
JoinSpan = 1
},
new JoinMetadata()
{
Description = "Sensor Partition Sensed",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("PartitionNotSensed")]
public JoinDataComplete PartitionNotSensed = new JoinDataComplete(
new JoinData()
{
JoinNumber = 4,
JoinSpan = 1
},
new JoinMetadata()
{
Description = "Sensor Partition Not Sensed",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("IncreaseSensitivity")]
public JoinDataComplete IncreaseSensitivity = new JoinDataComplete(
new JoinData()
{
JoinNumber = 6,
JoinSpan = 1
},
new JoinMetadata()
{
Description = "Sensor Increase Sensitivity",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("DecreaseSensitivity")]
public JoinDataComplete DecreaseSensitivity = new JoinDataComplete(
new JoinData()
{
JoinNumber = 7,
JoinSpan = 1
},
new JoinMetadata()
{
Description = "Sensor Decrease Sensitivity",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
});
[JoinName("Sensitivity")]
public JoinDataComplete Sensitivity = new JoinDataComplete(
new JoinData()
{
JoinNumber = 2,
JoinSpan = 1
},
new JoinMetadata()
{
Description = "Sensor Sensitivity",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Analog
});
public GlsPartitionSensorJoinMap(uint joinStart)
: base(joinStart, typeof(GlsPartitionSensorJoinMap))
{
}
}
}

View File

@@ -18,9 +18,9 @@ namespace PepperDash.Essentials.Core.CrestronIO
public IntFeedback TemperatureFeedback { get; private set; }
public IntFeedback HumidityFeedback { get; private set; }
public C2nRthsController(string key, string name, GenericBase hardware) : base(key, name, hardware)
public C2nRthsController(string key, string name, GenericBase sensor) : base(key, name, sensor)
{
_device = hardware as C2nRths;
_device = sensor as C2nRths;
TemperatureFeedback = new IntFeedback(() => _device.TemperatureFeedback.UShortValue);
HumidityFeedback = new IntFeedback(() => _device.HumidityFeedback.UShortValue);

View File

@@ -7,9 +7,9 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
{
private readonly C3Card _card;
public C3CardControllerBase(string key, string name, C3Card hardware) : base(key, name, hardware)
public C3CardControllerBase(string key, string name, C3Card sensor) : base(key, name, sensor)
{
_card = hardware;
_card = sensor;
}
#region Overrides of Object

View File

@@ -7,9 +7,9 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
{
private readonly C3com3 _card;
public C3Com3Controller(string key, string name, C3com3 hardware) : base(key, name, hardware)
public C3Com3Controller(string key, string name, C3com3 sensor) : base(key, name, sensor)
{
_card = hardware;
_card = sensor;
}
#region Implementation of IComPorts

View File

@@ -7,9 +7,9 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
{
private readonly C3io16 _card;
public C3Io16Controller(string key, string name, C3io16 hardware) : base(key, name, hardware)
public C3Io16Controller(string key, string name, C3io16 sensor) : base(key, name, sensor)
{
_card = hardware;
_card = sensor;
}
#region Implementation of IIOPorts

View File

@@ -7,9 +7,9 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
{
private readonly C3ir8 _card;
public C3Ir8Controller(string key, string name, C3ir8 hardware) : base(key, name, hardware)
public C3Ir8Controller(string key, string name, C3ir8 sensor) : base(key, name, sensor)
{
_card = hardware;
_card = sensor;
}
#region Implementation of IIROutputPorts

View File

@@ -7,9 +7,9 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
{
private readonly C3ry16 _card;
public C3Ry16Controller(string key, string name, C3ry16 hardware) : base(key, name, hardware)
public C3Ry16Controller(string key, string name, C3ry16 sensor) : base(key, name, sensor)
{
_card = hardware;
_card = sensor;
}
#region Implementation of IRelayPorts

View File

@@ -7,9 +7,9 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
{
private readonly C3ry8 _card;
public C3Ry8Controller(string key, string name, C3ry8 hardware) : base(key, name, hardware)
public C3Ry8Controller(string key, string name, C3ry8 sensor) : base(key, name, sensor)
{
_card = hardware;
_card = sensor;
}
#region Implementation of IRelayPorts

View File

@@ -18,9 +18,9 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
private readonly Dictionary<string, Func<CenCi31, uint, C3CardControllerBase>> _cardDict;
public CenCi31Controller(string key, string name, CenCi31Configuration config, CenCi31 hardware) : base(key, name, hardware)
public CenCi31Controller(string key, string name, CenCi31Configuration config, CenCi31 sensor) : base(key, name, sensor)
{
_cardCage = hardware;
_cardCage = sensor;
_config = config;

View File

@@ -18,9 +18,9 @@ namespace PepperDash.Essentials.Core.CrestronIO.Cards
private readonly Dictionary<string, Func<CenCi33, uint, C3CardControllerBase>> _cardDict;
public CenCi33Controller(string key, string name, CenCi33Configuration config, CenCi33 hardware) : base(key, name, hardware)
public CenCi33Controller(string key, string name, CenCi33Configuration config, CenCi33 sensor) : base(key, name, sensor)
{
_cardCage = hardware;
_cardCage = sensor;
_config = config;

View File

@@ -23,9 +23,9 @@ namespace PepperDash.Essentials.Core.CrestronIO
public IntFeedback GreenLedBrightnessFeedback { get; private set; }
public IntFeedback BlueLedBrightnessFeedback { get; private set; }
public StatusSignController(string key, string name, GenericBase hardware) : base(key, name, hardware)
public StatusSignController(string key, string name, GenericBase sensor) : base(key, name, sensor)
{
_device = hardware as StatusSign;
_device = sensor as StatusSign;
RedLedEnabledFeedback =
new BoolFeedback(

View File

@@ -11,7 +11,7 @@ namespace PepperDash.Essentials.Core
/// </summary>
public abstract class CrestronGenericBaseDevice : EssentialsDevice, IOnline, IHasFeedback, ICommunicationMonitor, IUsageTracking
{
public virtual GenericBase Hardware { get; protected set; }
public virtual GenericBase Sensor { get; protected set; }
/// <summary>
/// Returns a list containing the Outputs that we want to expose.
@@ -28,18 +28,18 @@ namespace PepperDash.Essentials.Core
/// </summary>
public bool PreventRegistration { get; protected set; }
protected CrestronGenericBaseDevice(string key, string name, GenericBase hardware)
protected CrestronGenericBaseDevice(string key, string name, GenericBase sensor)
: base(key, name)
{
Feedbacks = new FeedbackCollection<Feedback>();
Hardware = hardware;
IsOnline = new BoolFeedback("IsOnlineFeedback", () => Hardware.IsOnline);
IsRegistered = new BoolFeedback("IsRegistered", () => Hardware.Registered);
IpConnectionsText = new StringFeedback("IpConnectionsText", () => Hardware.ConnectedIpList != null ? string.Join(",", Hardware.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray()) : string.Empty);
Sensor = sensor;
IsOnline = new BoolFeedback("IsOnlineFeedback", () => Sensor.IsOnline);
IsRegistered = new BoolFeedback("IsRegistered", () => Sensor.Registered);
IpConnectionsText = new StringFeedback("IpConnectionsText", () => Sensor.ConnectedIpList != null ? string.Join(",", Sensor.ConnectedIpList.Select(cip => cip.DeviceIpAddress).ToArray()) : string.Empty);
AddToFeedbackList(IsOnline, IpConnectionsText);
CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, hardware, 120000, 300000);
CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, sensor, 120000, 300000);
}
/// <summary>
@@ -53,7 +53,7 @@ namespace PepperDash.Essentials.Core
{
//Debug.Console(1, this, " Does not require registration. Skipping");
var response = Hardware.RegisterWithLogging(Key);
var response = Sensor.RegisterWithLogging(Key);
if (response != eDeviceRegistrationUnRegistrationResponse.Success)
{
//Debug.Console(0, this, "ERROR: Cannot register Crestron device: {0}", response);
@@ -68,7 +68,7 @@ namespace PepperDash.Essentials.Core
f.FireUpdate();
}
Hardware.OnlineStatusChange += Hardware_OnlineStatusChange;
Sensor.OnlineStatusChange += Hardware_OnlineStatusChange;
CommunicationMonitor.Start();
return true;
@@ -81,9 +81,9 @@ namespace PepperDash.Essentials.Core
public override bool Deactivate()
{
CommunicationMonitor.Stop();
Hardware.OnlineStatusChange -= Hardware_OnlineStatusChange;
Sensor.OnlineStatusChange -= Hardware_OnlineStatusChange;
var success = Hardware.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success;
var success = Sensor.UnRegister() == eDeviceRegistrationUnRegistrationResponse.Success;
IsRegistered.FireUpdate();
@@ -131,7 +131,7 @@ namespace PepperDash.Essentials.Core
public abstract class CrestronGenericBridgeableBaseDevice : CrestronGenericBaseDevice, IBridgeAdvanced
{
protected CrestronGenericBridgeableBaseDevice(string key, string name, GenericBase hardware) : base(key, name, hardware)
protected CrestronGenericBridgeableBaseDevice(string key, string name, GenericBase sensor) : base(key, name, sensor)
{
}

View File

@@ -1,113 +1,113 @@
using System;
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>
/// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class
/// </summary>
[Description("The base Essentials Device Class")]
public abstract class EssentialsDevice : Device
{
protected EssentialsDevice(string key)
: base(key)
{
}
protected EssentialsDevice(string key, string name)
: base(key, name)
{
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class DescriptionAttribute : Attribute
{
private string _Description;
public DescriptionAttribute(string description)
{
Debug.Console(2, "Setting Description: {0}", description);
_Description = description;
}
public string Description
{
get { return _Description; }
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class ConfigSnippetAttribute : Attribute
{
private string _ConfigSnippet;
public ConfigSnippetAttribute(string configSnippet)
{
Debug.Console(2, "Setting Config Snippet {0}", configSnippet);
_ConfigSnippet = configSnippet;
}
public string ConfigSnippet
{
get { return _ConfigSnippet; }
}
}
/// <summary>
/// Devices the basic needs for a Device Factory
/// </summary>
public abstract class EssentialsDeviceFactory<T> : IDeviceFactory where T:EssentialsDevice
{
#region IDeviceFactory Members
/// <summary>
/// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
/// </summary>
public List<string> TypeNames { get; protected set; }
/// <summary>
/// Loads an item to the DeviceFactory.FactoryMethods dictionary for each entry in the TypeNames list
/// </summary>
public void LoadTypeFactories()
{
foreach (var typeName in TypeNames)
{
Debug.Console(2, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
using System;
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>
/// Defines the basic needs for an EssentialsDevice to enable it to be build by an IDeviceFactory class
/// </summary>
[Description("The base Essentials Device Class")]
public abstract class EssentialsDevice : Device
{
protected EssentialsDevice(string key)
: base(key)
{
}
protected EssentialsDevice(string key, string name)
: base(key, name)
{
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class DescriptionAttribute : Attribute
{
private string _Description;
public DescriptionAttribute(string description)
{
Debug.Console(2, "Setting Description: {0}", description);
_Description = description;
}
public string Description
{
get { return _Description; }
}
}
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class ConfigSnippetAttribute : Attribute
{
private string _ConfigSnippet;
public ConfigSnippetAttribute(string configSnippet)
{
Debug.Console(2, "Setting Config Snippet {0}", configSnippet);
_ConfigSnippet = configSnippet;
}
public string ConfigSnippet
{
get { return _ConfigSnippet; }
}
}
/// <summary>
/// Devices the basic needs for a Device Factory
/// </summary>
public abstract class EssentialsDeviceFactory<T> : IDeviceFactory where T:EssentialsDevice
{
#region IDeviceFactory Members
/// <summary>
/// A list of strings that can be used in the type property of a DeviceConfig object to build an instance of this device
/// </summary>
public List<string> TypeNames { get; protected set; }
/// <summary>
/// Loads an item to the DeviceFactory.FactoryMethods dictionary for each entry in the TypeNames list
/// </summary>
public void LoadTypeFactories()
{
foreach (var typeName in TypeNames)
{
Debug.Console(2, "Getting Description Attribute from class: '{0}'", typeof(T).FullName);
var descriptionAttribute = typeof(T).GetCustomAttributes(typeof(DescriptionAttribute), true) as DescriptionAttribute[];
string description = descriptionAttribute[0].Description;
var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
}
}
/// <summary>
/// The method that will build the device
/// </summary>
/// <param name="dc">The device config</param>
/// <returns>An instance of the device</returns>
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
#endregion
}
/// <summary>
/// Devices the basic needs for a Device Factory
/// </summary>
public abstract class EssentialsPluginDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDeviceFactory where T : EssentialsDevice
{
/// <summary>
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
/// </summary>
public string MinimumEssentialsFrameworkVersion { get; protected set; }
}
var snippetAttribute = typeof(T).GetCustomAttributes(typeof(ConfigSnippetAttribute), true) as ConfigSnippetAttribute[];
DeviceFactory.AddFactoryForType(typeName.ToLower(), description, typeof(T), BuildDevice);
}
}
/// <summary>
/// The method that will build the device
/// </summary>
/// <param name="dc">The device config</param>
/// <returns>An instance of the device</returns>
public abstract EssentialsDevice BuildDevice(DeviceConfig dc);
#endregion
}
/// <summary>
/// Devices the basic needs for a Device Factory
/// </summary>
public abstract class EssentialsPluginDeviceFactory<T> : EssentialsDeviceFactory<T>, IPluginDeviceFactory where T : EssentialsDevice
{
/// <summary>
/// Specifies the minimum version of Essentials required for a plugin to run. Must use the format Major.Minor.Build (ex. "1.4.33")
/// </summary>
public string MinimumEssentialsFrameworkVersion { get; protected set; }
}
}

View File

@@ -1,488 +1,488 @@
using System;
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Crestron.SimplSharp.Reflection;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core
{
public static class JoinMapHelper
{
/// <summary>
/// Attempts to get the serialized join map from config
/// </summary>
/// <param name="joinMapKey"></param>
/// <returns></returns>
public static string GetSerializedJoinMapForDevice(string joinMapKey)
{
if (string.IsNullOrEmpty(joinMapKey))
return null;
var joinMap = ConfigReader.ConfigObject.JoinMaps[joinMapKey];
return joinMap;
}
/// <summary>
/// Attempts to get the serialized join map from config
/// </summary>
/// <param name="joinMapKey"></param>
/// <returns></returns>
public static string GetJoinMapForDevice(string joinMapKey)
{
return GetSerializedJoinMapForDevice(joinMapKey);
}
/// <summary>
/// Attempts to find a custom join map by key and returns it deserialized if found
/// </summary>
/// <param name="joinMapKey"></param>
/// <returns></returns>
public static Dictionary<string, JoinData> TryGetJoinMapAdvancedForDevice(string joinMapKey)
{
if (string.IsNullOrEmpty(joinMapKey))
return null;
var joinMapSerialzed = ConfigReader.ConfigObject.JoinMaps[joinMapKey];
if (joinMapSerialzed == null) return null;
var joinMapData = JsonConvert.DeserializeObject<Dictionary<string, JoinData>>(joinMapSerialzed);
return joinMapData;
}
}
/// <summary>
/// Base class for join maps
/// </summary>
[Obsolete("This is being deprecated in favor of JoinMapBaseAdvanced")]
public abstract class JoinMapBase
{
/// <summary>
/// Modifies all the join numbers by adding the offset. This should never be called twice
/// </summary>
/// <param name="joinStart"></param>
public abstract void OffsetJoinNumbers(uint joinStart);
/// <summary>
/// The collection of joins and associated metadata
/// </summary>
public Dictionary<string, JoinMetadata> Joins = new Dictionary<string, JoinMetadata>();
/// <summary>
/// Prints the join information to console
/// </summary>
public void PrintJoinMapInfo()
{
Debug.Console(0, "{0}:\n", GetType().Name);
// Get the joins of each type and print them
Debug.Console(0, "Digitals:");
var digitals = Joins.Where(j => (j.Value.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Digital Joins", digitals.Count);
PrintJoinList(GetSortedJoins(digitals));
Debug.Console(0, "Analogs:");
var analogs = Joins.Where(j => (j.Value.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Analog Joins", analogs.Count);
PrintJoinList(GetSortedJoins(analogs));
Debug.Console(0, "Serials:");
var serials = Joins.Where(j => (j.Value.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Serial Joins", serials.Count);
PrintJoinList(GetSortedJoins(serials));
}
/// <summary>
/// Returns a sorted list by JoinNumber
/// </summary>
/// <param name="joins"></param>
/// <returns></returns>
List<KeyValuePair<string, JoinMetadata>> GetSortedJoins(Dictionary<string, JoinMetadata> joins)
{
var sortedJoins = joins.ToList();
sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber));
return sortedJoins;
}
void PrintJoinList(List<KeyValuePair<string, JoinMetadata>> joins)
{
foreach (var join in joins)
{
Debug.Console(0,
@"Join Number: {0} | Label: '{1}' | JoinSpan: '{2}' | Type: '{3}' | Capabilities: '{4}'",
join.Value.JoinNumber,
join.Value.Label,
join.Value.JoinSpan,
join.Value.JoinType.ToString(),
join.Value.JoinCapabilities.ToString());
}
}
/// <summary>
/// Returns the join number for the join with the specified key
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public uint GetJoinForKey(string key)
{
return Joins.ContainsKey(key) ? Joins[key].JoinNumber : 0;
}
/// <summary>
/// Returns the join span for the join with the specified key
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public uint GetJoinSpanForKey(string key)
{
return Joins.ContainsKey(key) ? Joins[key].JoinSpan : 0;
}
}
/// <summary>
/// Base class for join maps
/// </summary>
public abstract class JoinMapBaseAdvanced
{
protected uint JoinOffset;
/// <summary>
/// The collection of joins and associated metadata
/// </summary>
public Dictionary<string, JoinDataComplete> Joins { get; private set; }
protected JoinMapBaseAdvanced(uint joinStart)
{
Joins = new Dictionary<string, JoinDataComplete>();
JoinOffset = joinStart - 1;
}
protected JoinMapBaseAdvanced(uint joinStart, Type type):this(joinStart)
{
AddJoins(type);
}
protected void AddJoins(Type type)
{
// Add all the JoinDataComplete properties to the Joins Dictionary and pass in the offset
//Joins = this.GetType()
// .GetCType()
// .GetFields(BindingFlags.Public | BindingFlags.Instance)
// .Where(field => field.IsDefined(typeof(JoinNameAttribute), true))
// .Select(field => (JoinDataComplete)field.GetValue(this))
// .ToDictionary(join => join.GetNameAttribute(), join =>
// {
// join.SetJoinOffset(_joinOffset);
// return join;
// });
//type = this.GetType(); <- this wasn't working because 'this' was always the base class, never the derived class
var fields =
type.GetCType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(f => f.IsDefined(typeof (JoinNameAttribute), true));
foreach (var field in fields)
{
var childClass = Convert.ChangeType(this, type, null);
var value = field.GetValue(childClass) as JoinDataComplete; //this here is JoinMapBaseAdvanced, not the child class. JoinMapBaseAdvanced has no fields.
if (value == null)
{
Debug.Console(0, "Unable to caset base class to {0}", type.Name);
continue;
}
value.SetJoinOffset(JoinOffset);
var joinName = value.GetNameAttribute(field);
if (String.IsNullOrEmpty(joinName)) continue;
Joins.Add(joinName, value);
}
PrintJoinMapInfo();
}
/// <summary>
/// Prints the join information to console
/// </summary>
public void PrintJoinMapInfo()
{
Debug.Console(0, "{0}:\n", GetType().Name);
// Get the joins of each type and print them
Debug.Console(0, "Digitals:");
var digitals = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Digital Joins", digitals.Count);
PrintJoinList(GetSortedJoins(digitals));
Debug.Console(0, "Analogs:");
var analogs = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Analog Joins", analogs.Count);
PrintJoinList(GetSortedJoins(analogs));
Debug.Console(0, "Serials:");
var serials = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Serial Joins", serials.Count);
PrintJoinList(GetSortedJoins(serials));
}
/// <summary>
/// Returns a sorted list by JoinNumber
/// </summary>
/// <param name="joins"></param>
/// <returns></returns>
List<KeyValuePair<string, JoinDataComplete>> GetSortedJoins(Dictionary<string, JoinDataComplete> joins)
{
var sortedJoins = joins.ToList();
sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber));
return sortedJoins;
}
void PrintJoinList(List<KeyValuePair<string, JoinDataComplete>> joins)
{
foreach (var join in joins)
{
Debug.Console(0,
@"Join Number: {0} | JoinSpan: '{1}' | Label: '{2}' | Type: '{3}' | Capabilities: '{4}'",
join.Value.JoinNumber,
join.Value.JoinSpan,
join.Value.Metadata.Label,
join.Value.Metadata.JoinType.ToString(),
join.Value.Metadata.JoinCapabilities.ToString());
}
}
/// <summary>
/// Attempts to find the matching key for the custom join and if found overwrites the default JoinData with the custom
/// </summary>
/// <param name="joinData"></param>
public void SetCustomJoinData(Dictionary<string, JoinData> joinData)
{
foreach (var customJoinData in joinData)
{
var join = Joins[customJoinData.Key];
if (join != null)
{
join.SetCustomJoinData(customJoinData.Value);
}
else
{
Debug.Console(2, "No mathcing key found in join map for: '{0}'", customJoinData.Key);
}
}
PrintJoinMapInfo();
}
///// <summary>
///// Returns the join number for the join with the specified key
///// </summary>
///// <param name="key"></param>
///// <returns></returns>
//public uint GetJoinForKey(string key)
//{
// return Joins.ContainsKey(key) ? Joins[key].JoinNumber : 0;
//}
///// <summary>
///// Returns the join span for the join with the specified key
///// </summary>
///// <param name="key"></param>
///// <returns></returns>
//public uint GetJoinSpanForKey(string key)
//{
// return Joins.ContainsKey(key) ? Joins[key].JoinSpan : 0;
//}
}
/// <summary>
/// Read = Provides feedback to SIMPL
/// Write = Responds to sig values from SIMPL
/// </summary>
[Flags]
public enum eJoinCapabilities
{
None = 0,
ToSIMPL = 1,
FromSIMPL = 2,
ToFromSIMPL = ToSIMPL | FromSIMPL
}
[Flags]
public enum eJoinType
{
None = 0,
Digital = 1,
Analog = 2,
Serial = 4,
DigitalAnalog = Digital | Analog,
DigitalSerial = Digital | Serial,
AnalogSerial = Analog | Serial,
DigitalAnalogSerial = Digital | Analog | Serial
}
/// <summary>
/// Metadata describing the join
/// </summary>
public class JoinMetadata
using Crestron.SimplSharp.Reflection;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core
{
public static class JoinMapHelper
{
private string _description;
/// <summary>
/// Join number (based on join offset value)
/// </summary>
[JsonProperty("joinNumber")]
[Obsolete]
public uint JoinNumber { get; set; }
/// <summary>
/// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range
/// </summary>
[Obsolete]
[JsonProperty("joinSpan")]
public uint JoinSpan { get; set; }
/// <summary>
/// A label for the join to better describe its usage
/// </summary>
[Obsolete("Use Description instead")]
[JsonProperty("label")]
public string Label { get { return _description; } set { _description = value; } }
/// <summary>
/// A description for the join to better describe its usage
/// </summary>
[JsonProperty("description")]
public string Description { get { return _description; } set { _description = value; } }
/// <summary>
/// Signal type(s)
/// </summary>
[JsonProperty("joinType")]
public eJoinType JoinType { get; set; }
/// <summary>
/// Indicates whether the join is read and/or write
/// </summary>
[JsonProperty("joinCapabilities")]
public eJoinCapabilities JoinCapabilities { get; set; }
/// <summary>
/// Indicates a set of valid values (particularly if this translates to an enum
/// </summary>
[JsonProperty("validValues")]
public string[] ValidValues { get; set; }
}
/// <summary>
/// Data describing the join. Can be
/// </summary>
public class JoinData
{
/// <summary>
/// Join number (based on join offset value)
/// </summary>
[JsonProperty("joinNumber")]
public uint JoinNumber { get; set; }
/// <summary>
/// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range
/// </summary>
[JsonProperty("joinSpan")]
public uint JoinSpan { get; set; }
}
/// <summary>
/// A class to aggregate the JoinData and JoinMetadata for a join
/// </summary>
public class JoinDataComplete
{
private uint _joinOffset;
private JoinData _data;
public JoinMetadata Metadata { get; set; }
public JoinDataComplete(JoinData data, JoinMetadata metadata)
{
_data = data;
Metadata = metadata;
}
/// <summary>
/// Sets the join offset value
/// </summary>
/// <param name="joinOffset"></param>
public void SetJoinOffset(uint joinOffset)
{
_joinOffset = joinOffset;
}
/// <summary>
/// The join number (including the offset)
/// </summary>
public uint JoinNumber
{
get { return _data.JoinNumber+ _joinOffset; }
set { _data.JoinNumber = value; }
}
public uint JoinSpan
{
get { return _data.JoinSpan; }
}
public void SetCustomJoinData(JoinData customJoinData)
{
_data = customJoinData;
}
public string GetNameAttribute(MemberInfo memberInfo)
{
var name = string.Empty;
var attribute = (JoinNameAttribute)CAttribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute));
if (attribute == null) return name;
name = attribute.Name;
Debug.Console(2, "JoinName Attribute value: {0}", name);
return name;
/// Attempts to get the serialized join map from config
/// </summary>
/// <param name="joinMapKey"></param>
/// <returns></returns>
public static string GetSerializedJoinMapForDevice(string joinMapKey)
{
if (string.IsNullOrEmpty(joinMapKey))
return null;
var joinMap = ConfigReader.ConfigObject.JoinMaps[joinMapKey];
return joinMap;
}
/// <summary>
/// Attempts to get the serialized join map from config
/// </summary>
/// <param name="joinMapKey"></param>
/// <returns></returns>
public static string GetJoinMapForDevice(string joinMapKey)
{
return GetSerializedJoinMapForDevice(joinMapKey);
}
/// <summary>
/// Attempts to find a custom join map by key and returns it deserialized if found
/// </summary>
/// <param name="joinMapKey"></param>
/// <returns></returns>
public static Dictionary<string, JoinData> TryGetJoinMapAdvancedForDevice(string joinMapKey)
{
if (string.IsNullOrEmpty(joinMapKey))
return null;
var joinMapSerialzed = ConfigReader.ConfigObject.JoinMaps[joinMapKey];
if (joinMapSerialzed == null) return null;
var joinMapData = JsonConvert.DeserializeObject<Dictionary<string, JoinData>>(joinMapSerialzed);
return joinMapData;
}
}
/// <summary>
/// Base class for join maps
/// </summary>
[Obsolete("This is being deprecated in favor of JoinMapBaseAdvanced")]
public abstract class JoinMapBase
{
/// <summary>
/// Modifies all the join numbers by adding the offset. This should never be called twice
/// </summary>
/// <param name="joinStart"></param>
public abstract void OffsetJoinNumbers(uint joinStart);
/// <summary>
/// The collection of joins and associated metadata
/// </summary>
public Dictionary<string, JoinMetadata> Joins = new Dictionary<string, JoinMetadata>();
/// <summary>
/// Prints the join information to console
/// </summary>
public void PrintJoinMapInfo()
{
Debug.Console(0, "{0}:\n", GetType().Name);
// Get the joins of each type and print them
Debug.Console(0, "Digitals:");
var digitals = Joins.Where(j => (j.Value.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Digital Joins", digitals.Count);
PrintJoinList(GetSortedJoins(digitals));
Debug.Console(0, "Analogs:");
var analogs = Joins.Where(j => (j.Value.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Analog Joins", analogs.Count);
PrintJoinList(GetSortedJoins(analogs));
Debug.Console(0, "Serials:");
var serials = Joins.Where(j => (j.Value.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Serial Joins", serials.Count);
PrintJoinList(GetSortedJoins(serials));
}
/// <summary>
/// Returns a sorted list by JoinNumber
/// </summary>
/// <param name="joins"></param>
/// <returns></returns>
List<KeyValuePair<string, JoinMetadata>> GetSortedJoins(Dictionary<string, JoinMetadata> joins)
{
var sortedJoins = joins.ToList();
sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber));
return sortedJoins;
}
void PrintJoinList(List<KeyValuePair<string, JoinMetadata>> joins)
{
foreach (var join in joins)
{
Debug.Console(0,
@"Join Number: {0} | Label: '{1}' | JoinSpan: '{2}' | Type: '{3}' | Capabilities: '{4}'",
join.Value.JoinNumber,
join.Value.Label,
join.Value.JoinSpan,
join.Value.JoinType.ToString(),
join.Value.JoinCapabilities.ToString());
}
}
/// <summary>
/// Returns the join number for the join with the specified key
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public uint GetJoinForKey(string key)
{
return Joins.ContainsKey(key) ? Joins[key].JoinNumber : 0;
}
/// <summary>
/// Returns the join span for the join with the specified key
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public uint GetJoinSpanForKey(string key)
{
return Joins.ContainsKey(key) ? Joins[key].JoinSpan : 0;
}
}
[AttributeUsage(AttributeTargets.All)]
public class JoinNameAttribute : CAttribute
{
private string _Name;
public JoinNameAttribute(string name)
{
Debug.Console(2, "Setting Attribute Name: {0}", name);
_Name = name;
}
public string Name
{
get { return _Name; }
}
/// <summary>
/// Base class for join maps
/// </summary>
public abstract class JoinMapBaseAdvanced
{
protected uint JoinOffset;
/// <summary>
/// The collection of joins and associated metadata
/// </summary>
public Dictionary<string, JoinDataComplete> Joins { get; private set; }
protected JoinMapBaseAdvanced(uint joinStart)
{
Joins = new Dictionary<string, JoinDataComplete>();
JoinOffset = joinStart - 1;
}
protected JoinMapBaseAdvanced(uint joinStart, Type type):this(joinStart)
{
AddJoins(type);
}
protected void AddJoins(Type type)
{
// Add all the JoinDataComplete properties to the Joins Dictionary and pass in the offset
//Joins = this.GetType()
// .GetCType()
// .GetFields(BindingFlags.Public | BindingFlags.Instance)
// .Where(field => field.IsDefined(typeof(JoinNameAttribute), true))
// .Select(field => (JoinDataComplete)field.GetValue(this))
// .ToDictionary(join => join.GetNameAttribute(), join =>
// {
// join.SetJoinOffset(_joinOffset);
// return join;
// });
//type = this.GetType(); <- this wasn't working because 'this' was always the base class, never the derived class
var fields =
type.GetCType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(f => f.IsDefined(typeof (JoinNameAttribute), true));
foreach (var field in fields)
{
var childClass = Convert.ChangeType(this, type, null);
var value = field.GetValue(childClass) as JoinDataComplete; //this here is JoinMapBaseAdvanced, not the child class. JoinMapBaseAdvanced has no fields.
if (value == null)
{
Debug.Console(0, "Unable to caset base class to {0}", type.Name);
continue;
}
value.SetJoinOffset(JoinOffset);
var joinName = value.GetNameAttribute(field);
if (String.IsNullOrEmpty(joinName)) continue;
Joins.Add(joinName, value);
}
PrintJoinMapInfo();
}
/// <summary>
/// Prints the join information to console
/// </summary>
public void PrintJoinMapInfo()
{
Debug.Console(0, "{0}:\n", GetType().Name);
// Get the joins of each type and print them
Debug.Console(0, "Digitals:");
var digitals = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Digital) == eJoinType.Digital).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Digital Joins", digitals.Count);
PrintJoinList(GetSortedJoins(digitals));
Debug.Console(0, "Analogs:");
var analogs = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Analog) == eJoinType.Analog).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Analog Joins", analogs.Count);
PrintJoinList(GetSortedJoins(analogs));
Debug.Console(0, "Serials:");
var serials = Joins.Where(j => (j.Value.Metadata.JoinType & eJoinType.Serial) == eJoinType.Serial).ToDictionary(j => j.Key, j => j.Value);
Debug.Console(2, "Found {0} Serial Joins", serials.Count);
PrintJoinList(GetSortedJoins(serials));
}
/// <summary>
/// Returns a sorted list by JoinNumber
/// </summary>
/// <param name="joins"></param>
/// <returns></returns>
List<KeyValuePair<string, JoinDataComplete>> GetSortedJoins(Dictionary<string, JoinDataComplete> joins)
{
var sortedJoins = joins.ToList();
sortedJoins.Sort((pair1, pair2) => pair1.Value.JoinNumber.CompareTo(pair2.Value.JoinNumber));
return sortedJoins;
}
void PrintJoinList(List<KeyValuePair<string, JoinDataComplete>> joins)
{
foreach (var join in joins)
{
Debug.Console(0,
@"Join Number: {0} | JoinSpan: '{1}' | Label: '{2}' | Type: '{3}' | Capabilities: '{4}'",
join.Value.JoinNumber,
join.Value.JoinSpan,
join.Value.Metadata.Label,
join.Value.Metadata.JoinType.ToString(),
join.Value.Metadata.JoinCapabilities.ToString());
}
}
/// <summary>
/// Attempts to find the matching key for the custom join and if found overwrites the default JoinData with the custom
/// </summary>
/// <param name="joinData"></param>
public void SetCustomJoinData(Dictionary<string, JoinData> joinData)
{
foreach (var customJoinData in joinData)
{
var join = Joins[customJoinData.Key];
if (join != null)
{
join.SetCustomJoinData(customJoinData.Value);
}
else
{
Debug.Console(2, "No mathcing key found in join map for: '{0}'", customJoinData.Key);
}
}
PrintJoinMapInfo();
}
///// <summary>
///// Returns the join number for the join with the specified key
///// </summary>
///// <param name="key"></param>
///// <returns></returns>
//public uint GetJoinForKey(string key)
//{
// return Joins.ContainsKey(key) ? Joins[key].JoinNumber : 0;
//}
///// <summary>
///// Returns the join span for the join with the specified key
///// </summary>
///// <param name="key"></param>
///// <returns></returns>
//public uint GetJoinSpanForKey(string key)
//{
// return Joins.ContainsKey(key) ? Joins[key].JoinSpan : 0;
//}
}
/// <summary>
/// Read = Provides feedback to SIMPL
/// Write = Responds to sig values from SIMPL
/// </summary>
[Flags]
public enum eJoinCapabilities
{
None = 0,
ToSIMPL = 1,
FromSIMPL = 2,
ToFromSIMPL = ToSIMPL | FromSIMPL
}
[Flags]
public enum eJoinType
{
None = 0,
Digital = 1,
Analog = 2,
Serial = 4,
DigitalAnalog = Digital | Analog,
DigitalSerial = Digital | Serial,
AnalogSerial = Analog | Serial,
DigitalAnalogSerial = Digital | Analog | Serial
}
/// <summary>
/// Metadata describing the join
/// </summary>
public class JoinMetadata
{
private string _description;
/// <summary>
/// Join number (based on join offset value)
/// </summary>
[JsonProperty("joinNumber")]
[Obsolete]
public uint JoinNumber { get; set; }
/// <summary>
/// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range
/// </summary>
[Obsolete]
[JsonProperty("joinSpan")]
public uint JoinSpan { get; set; }
/// <summary>
/// A label for the join to better describe its usage
/// </summary>
[Obsolete("Use Description instead")]
[JsonProperty("label")]
public string Label { get { return _description; } set { _description = value; } }
/// <summary>
/// A description for the join to better describe its usage
/// </summary>
[JsonProperty("description")]
public string Description { get { return _description; } set { _description = value; } }
/// <summary>
/// Signal type(s)
/// </summary>
[JsonProperty("joinType")]
public eJoinType JoinType { get; set; }
/// <summary>
/// Indicates whether the join is read and/or write
/// </summary>
[JsonProperty("joinCapabilities")]
public eJoinCapabilities JoinCapabilities { get; set; }
/// <summary>
/// Indicates a set of valid values (particularly if this translates to an enum
/// </summary>
[JsonProperty("validValues")]
public string[] ValidValues { get; set; }
}
/// <summary>
/// Data describing the join. Can be
/// </summary>
public class JoinData
{
/// <summary>
/// Join number (based on join offset value)
/// </summary>
[JsonProperty("joinNumber")]
public uint JoinNumber { get; set; }
/// <summary>
/// Join range span. If join indicates the start of a range of joins, this indicated the maximum number of joins in the range
/// </summary>
[JsonProperty("joinSpan")]
public uint JoinSpan { get; set; }
}
/// <summary>
/// A class to aggregate the JoinData and JoinMetadata for a join
/// </summary>
public class JoinDataComplete
{
private uint _joinOffset;
private JoinData _data;
public JoinMetadata Metadata { get; set; }
public JoinDataComplete(JoinData data, JoinMetadata metadata)
{
_data = data;
Metadata = metadata;
}
/// <summary>
/// Sets the join offset value
/// </summary>
/// <param name="joinOffset"></param>
public void SetJoinOffset(uint joinOffset)
{
_joinOffset = joinOffset;
}
/// <summary>
/// The join number (including the offset)
/// </summary>
public uint JoinNumber
{
get { return _data.JoinNumber+ _joinOffset; }
set { _data.JoinNumber = value; }
}
public uint JoinSpan
{
get { return _data.JoinSpan; }
}
public void SetCustomJoinData(JoinData customJoinData)
{
_data = customJoinData;
}
public string GetNameAttribute(MemberInfo memberInfo)
{
var name = string.Empty;
var attribute = (JoinNameAttribute)CAttribute.GetCustomAttribute(memberInfo, typeof(JoinNameAttribute));
if (attribute == null) return name;
name = attribute.Name;
Debug.Console(2, "JoinName Attribute value: {0}", name);
return name;
}
}
[AttributeUsage(AttributeTargets.All)]
public class JoinNameAttribute : CAttribute
{
private string _Name;
public JoinNameAttribute(string name)
{
Debug.Console(2, "Setting Attribute Name: {0}", name);
_Name = name;
}
public string Name
{
get { return _Name; }
}
}
}

View File

@@ -136,7 +136,8 @@
<Compile Include="Bridges\JoinMaps\DmTxControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\GenericLightingJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\GenericRelayControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\GlsOccupancySensorBaseJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\GlsOccupancySensorJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\GlsPartitionSensorJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\HdMdNxM4kEControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\HdMdxxxCEControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\Hrxxx0WirelessRemoteControllerJoinMap.cs" />