Merge branch 'development' into hotfix/zoomroom-bridge-updates

This commit is contained in:
jdevito
2022-08-12 16:04:40 -05:00
committed by GitHub
28 changed files with 1135 additions and 354 deletions

View File

@@ -490,21 +490,17 @@ namespace PepperDash.Essentials
} }
} }
AddRoomAndBuildMC(room);
if (room is IEssentialsHuddleSpaceRoom) if (room is IEssentialsHuddleSpaceRoom)
{ {
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId); Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase(room, fusionIpId, fusionJoinMapKey)); DeviceManager.AddDevice(new Core.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase(room, fusionIpId, fusionJoinMapKey));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
CreateMobileControlBridge(room);
} }
else if (room is IEssentialsHuddleVtc1Room) else if (room is IEssentialsHuddleVtc1Room)
{ {
DeviceManager.AddDevice(room);
if (!(room is EssentialsCombinedHuddleVtc1Room)) if (!(room is EssentialsCombinedHuddleVtc1Room))
{ {
@@ -512,28 +508,15 @@ namespace PepperDash.Essentials
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey)); DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((IEssentialsHuddleVtc1Room)room, fusionIpId, fusionJoinMapKey));
} }
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge...");
CreateMobileControlBridge(room);
} }
else if (room is EssentialsTechRoom) else if (room is EssentialsTechRoom)
{ {
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, Debug.Console(0, Debug.ErrorLogLevel.Notice,
"Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId); "Room is EssentialsTechRoom, Attempting to add to DeviceManager with Fusion with IP-ID {0:X2}", fusionIpId);
DeviceManager.AddDevice(new EssentialsTechRoomFusionSystemController((EssentialsTechRoom)room, fusionIpId, fusionJoinMapKey)); DeviceManager.AddDevice(new EssentialsTechRoomFusionSystemController((EssentialsTechRoom)room, fusionIpId, fusionJoinMapKey));
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge");
CreateMobileControlBridge(room);
} }
else
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsRoom, attempting to add to DeviceManager w/o Fusion");
DeviceManager.AddDevice(room);
}
fusionIpId += 1; fusionIpId += 1;
} }
else else
@@ -547,6 +530,15 @@ namespace PepperDash.Essentials
} }
private static void AddRoomAndBuildMC(IEssentialsRoom room)
{
DeviceManager.AddDevice(room);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Mobile Control Bridge");
CreateMobileControlBridge(room);
}
private static void CreateMobileControlBridge(object room) private static void CreateMobileControlBridge(object room)
{ {
var mobileControl = GetMobileControlDevice(); var mobileControl = GetMobileControlDevice();

View File

@@ -19,32 +19,41 @@ namespace PepperDash.Essentials.Room.Config
/// Returns a room object from this config data /// Returns a room object from this config data
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static Device GetRoomObject(DeviceConfig roomConfig) public static IKeyed GetRoomObject(DeviceConfig roomConfig)
{ {
var typeName = roomConfig.Type.ToLower(); var typeName = roomConfig.Type.ToLower();
if (typeName == "huddle") switch (typeName)
{
return new EssentialsHuddleSpaceRoom(roomConfig);
}
if (typeName == "huddlevtc1")
{ {
return new EssentialsHuddleVtc1Room(roomConfig); case "huddle" :
{
return new EssentialsHuddleSpaceRoom(roomConfig);
}
case "huddlevtc1" :
{
return new EssentialsHuddleVtc1Room(roomConfig);
}
case "ddvc01bridge" :
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
case "dualdisplay" :
{
return new EssentialsDualDisplayRoom(roomConfig);
}
case "combinedhuddlevtc1" :
{
return new EssentialsCombinedHuddleVtc1Room(roomConfig);
}
case "techroom" :
{
return new EssentialsTechRoom(roomConfig);
}
default :
{
return Core.DeviceFactory.GetDevice(roomConfig);
}
} }
if (typeName == "ddvc01bridge")
{
return new Device(roomConfig.Key, roomConfig.Name); // placeholder device that does nothing.
}
if (typeName == "dualdisplay")
{
return new EssentialsDualDisplayRoom(roomConfig);
}
if (typeName == "combinedhuddlevtc1")
{
return new EssentialsCombinedHuddleVtc1Room(roomConfig);
}
return typeName != "techroom" ? null : new EssentialsTechRoom(roomConfig);
} }
/// <summary> /// <summary>

View File

@@ -0,0 +1,60 @@
using System;
namespace PepperDash.Essentials.Core.Bridges
{
public class PduJoinMapBase : JoinMapBaseAdvanced
{
[JoinName("Name")]
public JoinDataComplete Name = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "PDU Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });
[JoinName("Online")]
public JoinDataComplete Online = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "PDU Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("OutletCount")]
public JoinDataComplete OutletCount = new JoinDataComplete(new JoinData { JoinNumber = 1, JoinSpan = 1 },
new JoinMetadata { Description = "Number of COntrolled Outlets", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Analog });
[JoinName("OutletName")]
public JoinDataComplete OutletName = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Name", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Serial });
[JoinName("OutletEnabled")]
public JoinDataComplete OutletEnabled = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Enabled", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("OutletPowerCycle")]
public JoinDataComplete OutletPowerCycle = new JoinDataComplete(new JoinData { JoinNumber = 12, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Power Cycle", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("OutletPowerOn")]
public JoinDataComplete OutletPowerOn = new JoinDataComplete(new JoinData { JoinNumber = 13, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Power On", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
[JoinName("OutletPowerOff")]
public JoinDataComplete OutletPowerOff = new JoinDataComplete(new JoinData { JoinNumber = 14, JoinSpan = 1 },
new JoinMetadata { Description = "Outlet Power Off", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });
/// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
public PduJoinMapBase(uint joinStart)
:base(joinStart, typeof(PduJoinMapBase))
{
}
/// <summary>
/// Constructor to use when extending this Join map
/// </summary>
/// <param name="joinStart">Join this join map will start at</param>
/// <param name="type">Type of the child join map</param>
public PduJoinMapBase(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
}

View File

@@ -1,4 +1,4 @@
using System; using System;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Core.Bridges.JoinMaps namespace PepperDash.Essentials.Core.Bridges.JoinMaps
{ {
@@ -1576,6 +1576,36 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
JoinType = eJoinType.Serial JoinType = eJoinType.Serial
}); });
[JoinName("AvailableLayoutsFb")]
public JoinDataComplete AvailableLayoutsFb = new JoinDataComplete(
new JoinData
{
JoinNumber = 142,
JoinSpan = 1
},
new JoinMetadata
{
Description = "xSig of all available layouts",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("SelectLayout")]
public JoinDataComplete SelectLayout = new JoinDataComplete(
new JoinData
{
JoinNumber = 142,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Select Layout by string",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("CurrentParticipants")] [JoinName("CurrentParticipants")]
public JoinDataComplete CurrentParticipants = new JoinDataComplete( public JoinDataComplete CurrentParticipants = new JoinDataComplete(
new JoinData new JoinData
@@ -3014,6 +3044,35 @@ namespace PepperDash_Essentials_Core.Bridges.JoinMaps
JoinType = eJoinType.Serial JoinType = eJoinType.Serial
}); });
[JoinName("AvailableLayoutsFb")]
public JoinDataComplete AvailableLayoutsFb = new JoinDataComplete(
new JoinData
{
JoinNumber = 142,
JoinSpan = 1
},
new JoinMetadata
{
Description = "xSig of all available layouts",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("SelectLayout")]
public JoinDataComplete SelectLayout = new JoinDataComplete(
new JoinData
{
JoinNumber = 142,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Select Layout by string",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("CurrentParticipants")] [JoinName("CurrentParticipants")]
public JoinDataComplete CurrentParticipants = new JoinDataComplete( public JoinDataComplete CurrentParticipants = new JoinDataComplete(
new JoinData new JoinData

View File

@@ -39,7 +39,10 @@ namespace PepperDash.Essentials.Core.Config
Name = dc.Name; Name = dc.Name;
Group = dc.Group; Group = dc.Group;
Type = dc.Type; Type = dc.Type;
Properties = JToken.FromObject(dc.Properties);
Properties = JToken.Parse(dc.Properties.ToString());
//Properties = JToken.FromObject(dc.Properties);
} }
public DeviceConfig() {} public DeviceConfig() {}

View File

@@ -7,25 +7,61 @@ using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core namespace PepperDash.Essentials.Core
{ {
/// <summary> /// <summary>
/// Defines minimal volume control methods /// Defines minimal volume and mute control methods
/// </summary> /// </summary>
public interface IBasicVolumeControls public interface IBasicVolumeControls
{ {
void VolumeUp(bool pressRelease); void VolumeUp(bool pressRelease);
void VolumeDown(bool pressRelease); void VolumeDown(bool pressRelease);
void MuteToggle(); void MuteToggle();
} }
/// <summary>
/// Defines basic volume control methods
/// </summary>
public interface IHasVolumeControl
{
void VolumeUp(bool pressRelease);
void VolumeDown(bool pressRelease);
}
/// <summary>
/// Defines volume control methods and properties with feedback
/// </summary>
public interface IHasVolumeControlWithFeedback : IHasVolumeControl
{
void SetVolume(ushort level);
IntFeedback VolumeLevelFeedback { get; }
}
/// <summary>
/// Defines basic mute control methods
/// </summary>
public interface IHasMuteControl
{
void MuteToggle();
}
/// <summary>
/// Defines mute control methods and properties with feedback
/// </summary>
public interface IHasMuteControlWithFeedback : IHasMuteControl
{
BoolFeedback MuteFeedback { get; }
void MuteOn();
void MuteOff();
}
/// <summary> /// <summary>
/// Adds feedback and direct volume level set to IBasicVolumeControls /// Adds feedback and direct volume level set to IBasicVolumeControls
/// </summary> /// </summary>
public interface IBasicVolumeWithFeedback : IBasicVolumeControls public interface IBasicVolumeWithFeedback : IBasicVolumeControls
{ {
void SetVolume(ushort level);
void MuteOn();
void MuteOff();
IntFeedback VolumeLevelFeedback { get; }
BoolFeedback MuteFeedback { get; } BoolFeedback MuteFeedback { get; }
void MuteOn();
void MuteOff();
void SetVolume(ushort level);
IntFeedback VolumeLevelFeedback { get; }
} }
/// <summary> /// <summary>

View File

@@ -0,0 +1,35 @@
using System.Collections.Generic;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash_Essentials_Core.Devices
{
/// <summary>
/// Interface for any device that is able to control it'spower and has a configurable reboot time
/// </summary>
public interface IHasPowerCycle : IKeyName, IHasPowerControlWithFeedback
{
/// <summary>
/// Delay between power off and power on for reboot
/// </summary>
int PowerCycleTimeMs { get;}
/// <summary>
/// Reboot outlet
/// </summary>
void PowerCycle();
}
/// <summary>
/// Interface for any device that contains a collection of IHasPowerReboot Devices
/// </summary>
public interface IHasControlledPowerOutlets : IKeyName
{
/// <summary>
/// Collection of IPduOutlets
/// </summary>
ReadOnlyDictionary<int, IHasPowerCycle> PduOutlets { get; }
}
}

View File

@@ -59,7 +59,7 @@ namespace PepperDash.Essentials.Core.Devices
/// <summary> /// <summary>
/// Used by the extending class to allow for any custom actions to be taken (tell the ConfigWriter to write config, etc) /// Used by the extending class to allow for any custom actions to be taken (tell the ConfigWriter to write config, etc)
/// </summary> /// </summary>
/// <param name="Config"></param> /// <param name="config"></param>
protected virtual void CustomSetConfig(DeviceConfig config) protected virtual void CustomSetConfig(DeviceConfig config)
{ {
ConfigWriter.UpdateDeviceConfig(config); ConfigWriter.UpdateDeviceConfig(config);

View File

@@ -0,0 +1,278 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using PepperDash.Core;
using Crestron.SimplSharpPro.CrestronThread;
namespace PepperDash.Essentials.Core
{
public static class FileIO
{
static CCriticalSection fileLock = new CCriticalSection();
public delegate void GotFileEventHandler(object sender, FileEventArgs e);
public static event GotFileEventHandler GotFileEvent;
/// <summary>
/// Get the full file info from a path/filename, can include wildcards.
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static FileInfo[] GetFiles(string fileName)
{
DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fileName));
var files = dirInfo.GetFiles(Path.GetFileName(fileName));
Debug.Console(0, "FileIO found: {0}, {1}", files.Count(), fileName);
if (files.Count() > 0)
{
return files;
}
else
{
return null;
}
}
public static FileInfo GetFile(string fileName)
{
DirectoryInfo dirInfo = new DirectoryInfo(Path.GetDirectoryName(fileName));
var files = dirInfo.GetFiles(Path.GetFileName(fileName));
Debug.Console(0, "FileIO found: {0}, {1}", files.Count(), fileName);
if (files.Count() > 0)
{
return files.FirstOrDefault();
}
else
{
return null;
}
}
/// <summary>
/// Get the data from string path/filename
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static string ReadDataFromFile(string fileName)
{
try
{
return ReadDataFromFile(GetFile(fileName));
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
return "";
}
}
/// <summary>
/// Get the data with fileInfo object
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static string ReadDataFromFile(FileInfo file)
{
try
{
if (fileLock.TryEnter())
{
DirectoryInfo dirInfo = new DirectoryInfo(file.Name);
Debug.Console(2, "FileIO Getting Data {0}", file.FullName);
if (File.Exists(file.FullName))
{
using (StreamReader r = new StreamReader(file.FullName))
{
return r.ReadToEnd();
}
}
else
{
Debug.Console(2, "File {0} does not exsist", file.FullName);
return "";
}
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "FileIO Unable to enter FileLock");
return "";
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
return "";
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
}
public static void ReadDataFromFileASync(string fileName)
{
try
{
ReadDataFromFileASync(GetFile(fileName));
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
}
}
public static void ReadDataFromFileASync(FileInfo file)
{
try
{
CrestronInvoke.BeginInvoke(o => _ReadDataFromFileASync(file));
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
}
}
private static void _ReadDataFromFileASync(FileInfo file)
{
string data;
try
{
if (fileLock.TryEnter())
{
DirectoryInfo dirInfo = new DirectoryInfo(file.Name);
Debug.Console(2, "FileIO Getting Data {0}", file.FullName);
if (File.Exists(file.FullName))
{
using (StreamReader r = new StreamReader(file.FullName))
{
data = r.ReadToEnd();
}
}
else
{
Debug.Console(2, "File {0} Does not exsist", file.FullName);
data = "";
}
GotFileEvent.Invoke(null, new FileEventArgs(data));
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "FileIO Unable to enter FileLock");
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO read failed: \r{0}", e);
data = "";
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="filePath"></param>
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="filePath"></param>
public static void WriteDataToFile(string data, string filePath)
{
Thread _WriteFileThread;
_WriteFileThread = new Thread((O) => _WriteFileMethod(data, filePath), null, Thread.eThreadStartOptions.CreateSuspended);
_WriteFileThread.Priority = Thread.eThreadPriority.LowestPriority;
_WriteFileThread.Start();
Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WriteFile Thread");
}
static object _WriteFileMethod(string data, string filePath)
{
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to write file: '{0}'", filePath);
try
{
if (fileLock.TryEnter())
{
using (StreamWriter sw = new StreamWriter(filePath))
{
sw.Write(data);
sw.Flush();
}
}
else
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "FileIO Unable to enter FileLock");
}
}
catch (Exception e)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: FileIO write failed: \r{0}", e);
}
finally
{
if (fileLock != null && !fileLock.Disposed)
fileLock.Leave();
}
return null;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static bool FileIoUnitTest()
{
var testData = "Testing FileIO";
FileIO.WriteDataToFile(testData, "\\user\\FileIOTest.pdt");
var file = FileIO.GetFile("\\user\\*FileIOTest*");
var readData = FileIO.ReadDataFromFile(file);
Debug.Console(0, "Returned {0}", readData);
File.Delete(file.FullName);
if (testData == readData)
{
return true;
}
else
{
return false;
}
}
}
public class FileEventArgs
{
public FileEventArgs(string data) { Data = data; }
public string Data { get; private set; } // readonly
}
}

View File

@@ -92,50 +92,47 @@ namespace PepperDash.Essentials.Core.Lighting
return LinkLightingToApi(lightingDevice, trilist, joinMap); return LinkLightingToApi(lightingDevice, trilist, joinMap);
} }
protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap) protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, GenericLightingJoinMap joinMap)
{ {
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
Debug.Console(0, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString());
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); // GenericLighitng Actions & FeedBack
trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u]));
Debug.Console(0, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); var sceneIndex = 0;
foreach (var scene in lightingDevice.LightingScenes)
{
var index = sceneIndex;
// GenericLighitng Actions & FeedBack trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index]));
trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]);
trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name;
trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true;
var sceneIndex = 0; sceneIndex++;
foreach (var scene in lightingDevice.LightingScenes) }
{
var index = sceneIndex;
trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + index), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[index])); trilist.OnlineStatusChange += (sender, args) =>
scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)]); {
trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name; if (!args.DeviceOnLine) return;
trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true;
sceneIndex++; sceneIndex = 0;
} foreach (var scene in lightingDevice.LightingScenes)
{
var index = sceneIndex;
trilist.OnlineStatusChange += (sender, args) => trilist.StringInput[(uint) (joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name;
{ trilist.BooleanInput[(uint) (joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true;
if (!args.DeviceOnLine) return; scene.IsActiveFeedback.FireUpdate();
sceneIndex = 0; sceneIndex++;
foreach (var scene in lightingDevice.LightingScenes) }
{ };
var index = sceneIndex;
trilist.StringInput[(uint) (joinMap.SelectSceneDirect.JoinNumber + index)].StringValue = scene.Name;
trilist.BooleanInput[(uint) (joinMap.ButtonVisibility.JoinNumber + index)].BoolValue = true;
scene.IsActiveFeedback.FireUpdate();
sceneIndex++;
}
};
return joinMap;
}
return joinMap;
}
} }
public class LightingScene public class LightingScene

View File

@@ -123,6 +123,7 @@
<Compile Include="Bridges\IBridge.cs" /> <Compile Include="Bridges\IBridge.cs" />
<Compile Include="Bridges\JoinMaps\AirMediaControllerJoinMap.cs" /> <Compile Include="Bridges\JoinMaps\AirMediaControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\AppleTvJoinMap.cs" /> <Compile Include="Bridges\JoinMaps\AppleTvJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\PduJoinMapBase.cs" />
<Compile Include="Bridges\JoinMaps\C2nRthsControllerJoinMap.cs" /> <Compile Include="Bridges\JoinMaps\C2nRthsControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\CameraControllerJoinMap.cs" /> <Compile Include="Bridges\JoinMaps\CameraControllerJoinMap.cs" />
<Compile Include="Bridges\JoinMaps\CenOdtOccupancySensorBaseJoinMap.cs" /> <Compile Include="Bridges\JoinMaps\CenOdtOccupancySensorBaseJoinMap.cs" />
@@ -203,6 +204,7 @@
<Compile Include="Devices\IReconfigurableDevice.cs" /> <Compile Include="Devices\IReconfigurableDevice.cs" />
<Compile Include="Devices\PC\InRoomPc.cs" /> <Compile Include="Devices\PC\InRoomPc.cs" />
<Compile Include="Devices\PC\Laptop.cs" /> <Compile Include="Devices\PC\Laptop.cs" />
<Compile Include="Devices\PduInterfaces.cs" />
<Compile Include="Devices\ReconfigurableDevice.cs" /> <Compile Include="Devices\ReconfigurableDevice.cs" />
<Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" /> <Compile Include="Devices\VolumeDeviceChangeEventArgs.cs" />
<Compile Include="DeviceTypeInterfaces\IPasswordPrompt.cs" /> <Compile Include="DeviceTypeInterfaces\IPasswordPrompt.cs" />
@@ -224,6 +226,7 @@
<Compile Include="Feedbacks\IntFeedback.cs" /> <Compile Include="Feedbacks\IntFeedback.cs" />
<Compile Include="Feedbacks\SerialFeedback.cs" /> <Compile Include="Feedbacks\SerialFeedback.cs" />
<Compile Include="Feedbacks\StringFeedback.cs" /> <Compile Include="Feedbacks\StringFeedback.cs" />
<Compile Include="File\FileIO.cs" />
<Compile Include="Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs" /> <Compile Include="Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs" />
<Compile Include="Fusion\FusionCustomPropertiesBridge.cs" /> <Compile Include="Fusion\FusionCustomPropertiesBridge.cs" />
<Compile Include="Fusion\FusionEventHandlers.cs" /> <Compile Include="Fusion\FusionEventHandlers.cs" />
@@ -335,7 +338,9 @@
<Compile Include="Feedbacks\BoolFeedbackPulseExtender.cs" /> <Compile Include="Feedbacks\BoolFeedbackPulseExtender.cs" />
<Compile Include="Routing\RoutingPortNames.cs" /> <Compile Include="Routing\RoutingPortNames.cs" />
<Compile Include="Routing\TieLineConfig.cs" /> <Compile Include="Routing\TieLineConfig.cs" />
<Compile Include="Secrets\CrestronSecretsProvider.cs" /> <Compile Include="Secrets\CrestronGlobalSecretsProvider.cs" />
<Compile Include="Secrets\CrestronLocalSecretsProvider.cs" />
<Compile Include="Secrets\CrestronSecret.cs" />
<Compile Include="Secrets\Interfaces.cs" /> <Compile Include="Secrets\Interfaces.cs" />
<Compile Include="Secrets\SecretsManager.cs" /> <Compile Include="Secrets\SecretsManager.cs" />
<Compile Include="Secrets\SecretsPropertiesConfig.cs" /> <Compile Include="Secrets\SecretsPropertiesConfig.cs" />

View File

@@ -0,0 +1,102 @@
using System;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronDataStore;
using PepperDash.Core;
namespace PepperDash.Essentials.Core
{
public class CrestronGlobalSecretsProvider : ISecretProvider
{
public string Key { get; set; }
//Added for reference
public string Description { get; private set; }
public CrestronGlobalSecretsProvider(string key)
{
Key = key;
Description = String.Format("Default secret provider serving all local applications");
}
static CrestronGlobalSecretsProvider()
{
//Added for future encrypted reference
var secureSupported = CrestronSecureStorage.Supported;
CrestronDataStoreStatic.InitCrestronDataStore();
if (secureSupported)
{
//doThingsFuture
}
}
/// <summary>
/// Set secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <param name="value">Secret Value</param>
public bool SetSecret(string key, object value)
{
var secret = value as string;
CrestronDataStore.CDS_ERROR returnCode;
if (String.IsNullOrEmpty(secret))
{
returnCode = CrestronDataStoreStatic.clearGlobal(key);
if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
Debug.Console(0, this, "Successfully removed secret \"{0}\"", secret);
return true;
}
}
else
{
returnCode = CrestronDataStoreStatic.SetGlobalStringValue(key, secret);
if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
Debug.Console(0, this, "Successfully set secret \"{0}\"", secret);
return true;
}
}
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString());
return false;
}
/// <summary>
/// Retrieve secret for item in the CrestronSecretsProvider
/// </summary>
/// <param name="key">Secret Key</param>
/// <returns>ISecret Object containing key, provider, and value</returns>
public ISecret GetSecret(string key)
{
string mySecret;
var getErrorCode = CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret);
switch (getErrorCode)
{
case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
Debug.Console(2, this, "Secret Successfully retrieved for {0}:{1}", Key, key);
return new CrestronSecret(key, mySecret, this);
default:
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to retrieve secret for {0}:{1} - {2}",
Key, key, getErrorCode.ToString());
return null;
}
}
/// <summary>
/// Determine if a secret is present within the provider without retrieving it
/// </summary>
/// <param name="key">Secret Key</param>
/// <returns>bool if present</returns>
public bool TestSecret(string key)
{
string mySecret;
return CrestronDataStoreStatic.GetGlobalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS;
}
}
}

View File

@@ -2,27 +2,31 @@
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronDataStore; using Crestron.SimplSharp.CrestronDataStore;
using PepperDash.Core; using PepperDash.Core;
using Crestron.SimplSharpPro;
namespace PepperDash.Essentials.Core namespace PepperDash.Essentials.Core
{ {
public class CrestronSecretsProvider : ISecretProvider public class CrestronLocalSecretsProvider : ISecretProvider
{ {
public string Key { get; set; } public string Key { get; set; }
//Added for reference //Added for reference
private static readonly bool SecureSupported; public string Description { get; private set; }
public CrestronSecretsProvider(string key)
public CrestronLocalSecretsProvider(string key)
{ {
Key = key; Key = key;
Description = String.Format("Default secret provider serving Essentials Application {0}", InitialParametersClass.ApplicationNumber);
} }
static CrestronSecretsProvider() static CrestronLocalSecretsProvider()
{ {
//Added for future encrypted reference //Added for future encrypted reference
SecureSupported = CrestronSecureStorage.Supported; var secureSupported = CrestronSecureStorage.Supported;
CrestronDataStoreStatic.InitCrestronDataStore(); CrestronDataStoreStatic.InitCrestronDataStore();
if (SecureSupported) if (secureSupported)
{ {
//doThingsFuture //doThingsFuture
} }
@@ -36,21 +40,30 @@ namespace PepperDash.Essentials.Core
public bool SetSecret(string key, object value) public bool SetSecret(string key, object value)
{ {
var secret = value as string; var secret = value as string;
CrestronDataStore.CDS_ERROR returnCode;
if (String.IsNullOrEmpty(secret)) if (String.IsNullOrEmpty(secret))
{ {
Debug.Console(2, this, "Unable to set secret for {0}:{1} - value is empty.", Key, key); returnCode = CrestronDataStoreStatic.clearLocal(key);
return false; if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
} {
var setErrorCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret); Debug.Console(0, this, "Successfully removed secret \"{0}\"", secret);
switch (setErrorCode)
{
case CrestronDataStore.CDS_ERROR.CDS_SUCCESS:
Debug.Console(1, this,"Secret Successfully Set for {0}:{1}", Key, key);
return true; return true;
default: }
Debug.Console(2, this, Debug.ErrorLogLevel.Notice, "Unable to set secret for {0}:{1} - {2}", Key, key, setErrorCode.ToString());
return false;
} }
else
{
returnCode = CrestronDataStoreStatic.SetLocalStringValue(key, secret);
if (returnCode == CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
{
Debug.Console(0, this, "Successfully set secret \"{0}\"", secret);
return true;
}
}
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Unable to set secret for {0}:{1} - {2}", Key, key, returnCode.ToString());
return false;
} }
/// <summary> /// <summary>
@@ -74,24 +87,17 @@ namespace PepperDash.Essentials.Core
return null; return null;
} }
} }
}
/// <summary> /// <summary>
/// Special container class for CrestronSecret provider /// Determine if a secret is present within the provider without retrieving it
/// </summary> /// </summary>
public class CrestronSecret : ISecret /// <param name="key">Secret Key</param>
{ /// <returns>bool if present</returns>
public ISecretProvider Provider { get; private set; } public bool TestSecret(string key)
public string Key { get; private set; }
public object Value { get; private set; }
public CrestronSecret(string key, string value, ISecretProvider provider)
{ {
Key = key; string mySecret;
Value = value; return CrestronDataStoreStatic.GetLocalStringValue(key, out mySecret) == CrestronDataStore.CDS_ERROR.CDS_SUCCESS;
Provider = provider;
} }
} }
} }

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Special container class for CrestronSecret provider
/// </summary>
public class CrestronSecret : ISecret
{
public ISecretProvider Provider { get; private set; }
public string Key { get; private set; }
public object Value { get; private set; }
public CrestronSecret(string key, string value, ISecretProvider provider)
{
Key = key;
Value = value;
Provider = provider;
}
}
}

View File

@@ -7,9 +7,32 @@ namespace PepperDash.Essentials.Core
/// </summary> /// </summary>
public interface ISecretProvider : IKeyed public interface ISecretProvider : IKeyed
{ {
/// <summary>
/// Set secret value for provider by key
/// </summary>
/// <param name="key">key of secret to set</param>
/// <param name="value">value to set secret to</param>
/// <returns></returns>
bool SetSecret(string key, object value); bool SetSecret(string key, object value);
/// <summary>
/// Return object containing secret from provider
/// </summary>
/// <param name="key">key of secret to retrieve</param>
/// <returns></returns>
ISecret GetSecret(string key); ISecret GetSecret(string key);
/// <summary>
/// Verifies presence of secret
/// </summary>
/// <param name="key">key of secret to chek</param>
/// <returns></returns>
bool TestSecret(string key);
/// <summary>
/// Description of the secrets provider
/// </summary>
string Description { get; }
} }
/// <summary> /// <summary>
@@ -17,8 +40,19 @@ namespace PepperDash.Essentials.Core
/// </summary> /// </summary>
public interface ISecret public interface ISecret
{ {
/// <summary>
/// Instance of ISecretProvider that the secret belongs to
/// </summary>
ISecretProvider Provider { get; } ISecretProvider Provider { get; }
/// <summary>
/// Key of the secret in the provider
/// </summary>
string Key { get; } string Key { get; }
/// <summary>
/// Value of the secret
/// </summary>
object Value { get; } object Value { get; }
} }
} }

View File

@@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using PepperDash.Core; using PepperDash.Core;
namespace PepperDash.Essentials.Core namespace PepperDash.Essentials.Core
{ {
public static class SecretsManager public static class SecretsManager
@@ -16,18 +16,28 @@ namespace PepperDash.Essentials.Core
public static void Initialize() public static void Initialize()
{ {
AddSecretProvider("default", new CrestronSecretsProvider("default")); AddSecretProvider("default", new CrestronLocalSecretsProvider("default"));
AddSecretProvider("CrestronGlobalSecrets", new CrestronGlobalSecretsProvider("CrestronGlobalSecrets"));
CrestronConsole.AddNewConsoleCommand(SetSecretProcess, "setsecret", CrestronConsole.AddNewConsoleCommand(SetSecretProcess, "setsecret",
"Adds secrets to secret provider", "Adds secret to secrets provider",
ConsoleAccessLevelEnum.AccessOperator); ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(UpdateSecretProcess, "updatesecret", CrestronConsole.AddNewConsoleCommand(UpdateSecretProcess, "updatesecret",
"Updates secrets in secret provider", "Updates secret in secrets provider",
ConsoleAccessLevelEnum.AccessAdministrator); ConsoleAccessLevelEnum.AccessAdministrator);
CrestronConsole.AddNewConsoleCommand(DeleteSecretProcess, "deletesecret", CrestronConsole.AddNewConsoleCommand(DeleteSecretProcess, "deletesecret",
"Deletes secrets in secret provider", "Deletes secret from secrest provider",
ConsoleAccessLevelEnum.AccessAdministrator);
CrestronConsole.AddNewConsoleCommand(ListProviders, "secretproviderlist",
"Return list of all valid secrets providers",
ConsoleAccessLevelEnum.AccessAdministrator);
CrestronConsole.AddNewConsoleCommand(GetProviderInfo, "secretproviderinfo",
"Return data about secrets provider",
ConsoleAccessLevelEnum.AccessAdministrator); ConsoleAccessLevelEnum.AccessAdministrator);
} }
@@ -54,6 +64,79 @@ namespace PepperDash.Essentials.Core
return secret; return secret;
} }
public static void GetProviderInfo(string cmd)
{
string response;
var args = cmd.Split(' ');
if (cmd.Length == 0 || (args.Length == 1 && args[0] == "?"))
{
response = "Returns data about secrets provider. Format 'secretproviderinfo <provider>'";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1)
{
var provider = GetSecretProviderByKey(args[0]);
if (provider == null)
{
response = "Invalid secrets provider key";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response = String.Format("{0} : {1}", provider.Key, provider.Description);
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response = "Improper number of arguments";
CrestronConsole.ConsoleCommandResponse(response);
}
/// <summary>
/// Console Command that returns all valid secrets in the essentials program.
/// </summary>
/// <param name="cmd"></param>
public static void ListProviders(string cmd)
{
var response = String.Empty;
var args = cmd.Split(' ');
if (cmd.Length == 0)
{
if (Secrets != null && Secrets.Count > 0)
{
response = Secrets.Aggregate(response,
(current, secretProvider) => current + (secretProvider.Key + "\n\r"));
}
else
{
response = "No Secrets Providers Available";
}
CrestronConsole.ConsoleCommandResponse(response);
return;
}
if (args.Length == 1 && args[0] == "?")
{
response = "Reports all valid and preset Secret providers";
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response = "Improper number of arguments";
CrestronConsole.ConsoleCommandResponse(response);
}
/// <summary> /// <summary>
/// Add secret provider to secrets dictionary /// Add secret provider to secrets dictionary
/// </summary> /// </summary>
@@ -100,14 +183,14 @@ namespace PepperDash.Essentials.Core
if (args.Length == 0) if (args.Length == 0)
{ {
//some Instructional Text //some Instructional Text
response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>"; response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>'";
CrestronConsole.ConsoleCommandResponse(response); CrestronConsole.ConsoleCommandResponse(response);
return; return;
} }
if (args.Length == 1 && args[0] == "?") if (args.Length == 1 && args[0] == "?")
{ {
response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>"; response = "Adds secrets to secret provider. Format 'setsecret <provider> <secretKey> <secret>'";
CrestronConsole.ConsoleCommandResponse(response); CrestronConsole.ConsoleCommandResponse(response);
return; return;
} }
@@ -134,23 +217,7 @@ namespace PepperDash.Essentials.Core
var key = args[1]; var key = args[1];
var secret = args[2]; var secret = args[2];
if (provider.GetSecret(key) == null) CrestronConsole.ConsoleCommandResponse(SetSecret(provider, key, secret));
{
response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
CrestronConsole.ConsoleCommandResponse(response);
return;
}
response =
String.Format(
"Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it");
CrestronConsole.ConsoleCommandResponse(response);
} }
private static void UpdateSecretProcess(string cmd) private static void UpdateSecretProcess(string cmd)
@@ -161,7 +228,7 @@ namespace PepperDash.Essentials.Core
if (args.Length == 0) if (args.Length == 0)
{ {
//some Instructional Text //some Instructional Text
response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>"; response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>'";
CrestronConsole.ConsoleCommandResponse(response); CrestronConsole.ConsoleCommandResponse(response);
return; return;
@@ -169,7 +236,7 @@ namespace PepperDash.Essentials.Core
if (args.Length == 1 && args[0] == "?") if (args.Length == 1 && args[0] == "?")
{ {
response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>"; response = "Updates secrets in secret provider. Format 'updatesecret <provider> <secretKey> <secret>'";
CrestronConsole.ConsoleCommandResponse(response); CrestronConsole.ConsoleCommandResponse(response);
return; return;
} }
@@ -198,23 +265,49 @@ namespace PepperDash.Essentials.Core
var key = args[1]; var key = args[1];
var secret = args[2]; var secret = args[2];
if (provider.GetSecret(key) != null) CrestronConsole.ConsoleCommandResponse(UpdateSecret(provider, key, secret));
{
response = provider.SetSecret(key, secret) }
? String.Format(
"Secret successfully set for {0}:{1}", private static string UpdateSecret(ISecretProvider provider, string key, string secret)
provider.Key, key) {
: String.Format( var secretPresent = provider.TestSecret(key);
"Unable to set secret for {0}:{1}",
provider.Key, key); Debug.Console(2, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key);
CrestronConsole.ConsoleCommandResponse(response);
return; if (!secretPresent)
} return
String.Format(
"Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to modify it");
var response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
return response;
}
private static string SetSecret(ISecretProvider provider, string key, string secret)
{
var secretPresent = provider.TestSecret(key);
Debug.Console(2, provider, "SecretsProvider {0} {1} contain a secret entry for {2}", provider.Key, secretPresent ? "does" : "does not", key);
if (secretPresent)
return
String.Format(
"Unable to set secret for {0}:{1} - Please use the 'UpdateSecret' command to modify it");
var response = provider.SetSecret(key, secret)
? String.Format(
"Secret successfully set for {0}:{1}",
provider.Key, key)
: String.Format(
"Unable to set secret for {0}:{1}",
provider.Key, key);
return response;
response =
String.Format(
"Unable to update secret for {0}:{1} - Please use the 'SetSecret' command to create a new secret");
CrestronConsole.ConsoleCommandResponse(response);
} }
private static void DeleteSecretProcess(string cmd) private static void DeleteSecretProcess(string cmd)
@@ -225,14 +318,14 @@ namespace PepperDash.Essentials.Core
if (args.Length == 0) if (args.Length == 0)
{ {
//some Instructional Text //some Instructional Text
response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>"; response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>'";
CrestronConsole.ConsoleCommandResponse(response); CrestronConsole.ConsoleCommandResponse(response);
return; return;
} }
if (args.Length == 1 && args[0] == "?") if (args.Length == 1 && args[0] == "?")
{ {
response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>"; response = "Deletes secrets in secret provider. Format 'deletesecret <provider> <secretKey>'";
CrestronConsole.ConsoleCommandResponse(response); CrestronConsole.ConsoleCommandResponse(response);
return; return;
} }

View File

@@ -144,7 +144,7 @@ namespace PepperDash.Essentials.Core
public UShortOutputSig GetUShortOutputSig(uint index, uint sigNum) public UShortOutputSig GetUShortOutputSig(uint index, uint sigNum)
{ {
if (sigNum > UShortIncrement) return null; if (sigNum > UShortIncrement) return null;
return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetBoolFeedbackSigName(index, sigNum))); return SRL.UShortOutput.FirstOrDefault(s => s.Name.Equals(GetUShortOutputSigName(index, sigNum)));
} }
/// <summary> /// <summary>
@@ -159,7 +159,7 @@ namespace PepperDash.Essentials.Core
public StringOutputSig GetStringOutputSig(uint index, uint sigNum) public StringOutputSig GetStringOutputSig(uint index, uint sigNum)
{ {
if (sigNum > StringIncrement) return null; if (sigNum > StringIncrement) return null;
return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetBoolFeedbackSigName(index, sigNum))); return SRL.StringOutput.FirstOrDefault(s => s.Name.Equals(GetStringOutputSigName(index, sigNum)));
} }
/// <summary> /// <summary>

View File

@@ -308,7 +308,7 @@ namespace PepperDash.Essentials.Devices.Displays
//Send((string)selector); //Send((string)selector);
} }
void SetVolume(ushort level) public void SetVolume(ushort level)
{ {
var levelString = string.Format("{0}{1:X4}\x03", VolumeLevelPartialCmd, level); var levelString = string.Format("{0}{1:X4}\x03", VolumeLevelPartialCmd, level);
AppendChecksumAndSend(levelString); AppendChecksumAndSend(levelString);
@@ -333,10 +333,13 @@ namespace PepperDash.Essentials.Devices.Displays
Send(MuteOnCmd); Send(MuteOnCmd);
} }
void IBasicVolumeWithFeedback.SetVolume(ushort level)
/*
public void IBasicVolumeWithFeedback.SetVolume(ushort level)
{ {
SetVolume(level); SetVolume(level);
} }
*/
#endregion #endregion

View File

@@ -290,7 +290,7 @@ namespace PepperDash.Essentials.Devices.Displays
//Send((string)selector); //Send((string)selector);
} }
void SetVolume(ushort level) public void SetVolume(ushort level)
{ {
var levelString = string.Format("{0}{1:X3}\x03", VolumeLevelPartialCmd, level); var levelString = string.Format("{0}{1:X3}\x03", VolumeLevelPartialCmd, level);
@@ -315,11 +315,12 @@ namespace PepperDash.Essentials.Devices.Displays
Send(MuteOnCmd); Send(MuteOnCmd);
} }
/*
void IBasicVolumeWithFeedback.SetVolume(ushort level) void IBasicVolumeWithFeedback.SetVolume(ushort level)
{ {
SetVolume(level); SetVolume(level);
} }
*/
#endregion #endregion
#region IBasicVolumeControls Members #region IBasicVolumeControls Members

View File

@@ -108,6 +108,7 @@
<Compile Include="Codec\eCodecCallStatus.cs" /> <Compile Include="Codec\eCodecCallStatus.cs" />
<Compile Include="Codec\eMeetingPrivacy.cs" /> <Compile Include="Codec\eMeetingPrivacy.cs" />
<Compile Include="Codec\iCodecAudio.cs" /> <Compile Include="Codec\iCodecAudio.cs" />
<Compile Include="VideoCodec\IConvertiblePreset.cs" />
<Compile Include="Codec\IHasCallHold.cs" /> <Compile Include="Codec\IHasCallHold.cs" />
<Compile Include="Codec\IHasDoNotDisturb.cs" /> <Compile Include="Codec\IHasDoNotDisturb.cs" />
<Compile Include="Codec\IHasExternalSourceSwitching.cs" /> <Compile Include="Codec\IHasExternalSourceSwitching.cs" />

View File

@@ -1023,20 +1023,25 @@ ConnectorID: {2}"
if (tempPresets.Count > 0) if (tempPresets.Count > 0)
{ {
// Create temporary list to store the existing items from the CiscoCodecStatus.RoomPreset collection // Create temporary list to store the existing items from the CiscoCodecStatus.RoomPreset collection
List<CiscoCodecStatus.RoomPreset> existingRoomPresets = new List<CiscoCodecStatus.RoomPreset>(); var existingRoomPresets = new List<IConvertiblePreset>();
// Add the existing items to the temporary list // Add the existing items to the temporary list
existingRoomPresets.AddRange(CodecStatus.Status.RoomPreset); existingRoomPresets.AddRange(CodecStatus.Status.RoomPreset);
// Populate the CodecStatus object (this will append new values to the RoomPreset collection // Populate the CodecStatus object (this will append new values to the RoomPreset collection
JsonConvert.PopulateObject(response, CodecStatus); JsonConvert.PopulateObject(response, CodecStatus);
JObject jResponse = JObject.Parse(response); var jResponse = JObject.Parse(response);
List<CiscoCodecStatus.RoomPreset> convertedRoomPresets =
existingRoomPresets.Select(a => (CiscoCodecStatus.RoomPreset) a).ToList();
IList<JToken> roomPresets = jResponse["Status"]["RoomPreset"].Children().ToList(); IList<JToken> roomPresets = jResponse["Status"]["RoomPreset"].Children().ToList();
// Iterate the new items in this response agains the temporary list. Overwrite any existing items and add new ones. // Iterate the new items in this response agains the temporary list. Overwrite any existing items and add new ones.
foreach (var preset in tempPresets) foreach (var camPreset in tempPresets)
{ {
var preset = camPreset as CiscoCodecStatus.RoomPreset;
if (preset == null) continue;
// First fine the existing preset that matches the id // First fine the existing preset that matches the id
var existingPreset = existingRoomPresets.FirstOrDefault(p => p.id.Equals(preset.id)); var existingPreset = convertedRoomPresets.FirstOrDefault(p => p.id.Equals(preset.id));
if (existingPreset != null) if (existingPreset != null)
{ {
Debug.Console(1, this, "Existing Room Preset with ID: {0} found. Updating.", existingPreset.id); Debug.Console(1, this, "Existing Room Preset with ID: {0} found. Updating.", existingPreset.id);
@@ -1068,7 +1073,7 @@ ConnectorID: {2}"
CodecStatus.Status.RoomPreset = existingRoomPresets; CodecStatus.Status.RoomPreset = existingRoomPresets;
// Generecise the list // Generecise the list
NearEndPresets = RoomPresets.GetGenericPresets(CodecStatus.Status.RoomPreset); NearEndPresets = existingRoomPresets.GetGenericPresets<CodecRoomPreset>();
var handler = CodecRoomPresetsListHasChanged; var handler = CodecRoomPresetsListHasChanged;
if (handler != null) if (handler != null)
@@ -2465,20 +2470,6 @@ ConnectorID: {2}"
} }
/// <summary>
/// Represents a codec command that might need to have a friendly label applied for UI feedback purposes
/// </summary>
public class CodecCommandWithLabel
{
public string Command { get; set; }
public string Label { get; set; }
public CodecCommandWithLabel(string command, string label)
{
Command = command;
Label = label;
}
}
/// <summary> /// <summary>
/// Tracks the initial sycnronization state of the codec when making a connection /// Tracks the initial sycnronization state of the codec when making a connection

View File

@@ -1,14 +1,9 @@
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 Newtonsoft.Json;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.Core.Presets; using PepperDash.Essentials.Core.Presets;
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco;
namespace PepperDash.Essentials.Devices.Common.VideoCodec namespace PepperDash.Essentials.Devices.Common.VideoCodec
{ {
@@ -33,39 +28,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public static class RoomPresets public static class RoomPresets
{ {
/// <summary> /// <summary>
/// Converts Cisco RoomPresets to generic CameraPresets /// Converts non-generic RoomPresets to generic CameraPresets
/// </summary> /// </summary>
/// <param name="presets"></param> /// <param name="presets"></param>
/// <returns></returns> /// <returns></returns>
public static List<CodecRoomPreset> GetGenericPresets(List<CiscoCodecStatus.RoomPreset> presets) public static List<T> GetGenericPresets<T>(this List<IConvertiblePreset> presets)
{ {
var cameraPresets = new List<CodecRoomPreset>(); return
presets.Select(preset => preset.ConvertCodecPreset())
if (Debug.Level > 0) .Where(newPreset => newPreset != null)
{ .Cast<T>()
Debug.Console(1, "Presets List:"); .ToList();
}
foreach (CiscoCodecStatus.RoomPreset preset in presets)
{
try
{
var cameraPreset = new CodecRoomPreset(UInt16.Parse(preset.id), preset.Description.Value, preset.Defined.BoolValue, true);
cameraPresets.Add(cameraPreset);
if (Debug.Level > 0)
{
Debug.Console(1, "Added Preset ID: {0}, Description: {1}, IsDefined: {2}, isDefinable: {3}", cameraPreset.ID, cameraPreset.Description, cameraPreset.Defined, cameraPreset.IsDefinable);
}
}
catch (Exception e)
{
Debug.Console(2, "Unable to convert preset: {0}. Error: {1}", preset.id, e);
}
}
return cameraPresets;
} }
} }

View File

@@ -9,6 +9,7 @@ using Newtonsoft.Json.Linq;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec.CiscoCodec; using PepperDash.Essentials.Devices.Common.VideoCodec.CiscoCodec;
using PepperDash.Essentials.Core.Presets;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
{ {
@@ -2185,7 +2186,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
} }
} }
public class RoomPreset public class RoomPreset : IConvertiblePreset
{ {
public string id { get; set; } public string id { get; set; }
public Defined Defined { get; set; } public Defined Defined { get; set; }
@@ -2198,7 +2199,24 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
Description = new Description2(); Description = new Description2();
Type = new Type5(); Type = new Type5();
} }
}
public PresetBase ConvertCodecPreset()
{
try
{
var preset = new CodecRoomPreset(UInt16.Parse(id), Description.Value, Defined.BoolValue, true);
Debug.Console(2, "Preset ID {0} Converted from Cisco Codec Preset to Essentials Preset");
return preset;
}
catch (Exception e)
{
Debug.Console(2, "Unable to convert preset: {0}. Error: {1}", id, e);
return null;
}
}
}
@@ -2222,7 +2240,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public Proximity Proximity { get; set; } public Proximity Proximity { get; set; }
public RoomAnalytics RoomAnalytics { get; set; } public RoomAnalytics RoomAnalytics { get; set; }
public List<RoomPreset> RoomPreset { get; set; } public List<IConvertiblePreset> RoomPreset { get; set; }
public SIP SIP { get; set; } public SIP SIP { get; set; }
public Security Security { get; set; } public Security Security { get; set; }
@@ -2239,7 +2257,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
Standby = new Standby(); Standby = new Standby();
Cameras = new Cameras(); Cameras = new Cameras();
RoomAnalytics = new RoomAnalytics(); RoomAnalytics = new RoomAnalytics();
RoomPreset = new List<RoomPreset>(); RoomPreset = new List<IConvertiblePreset>();
Conference = new Conference2(); Conference = new Conference2();
SystemUnit = new SystemUnit(); SystemUnit = new SystemUnit();
Video = new Video(); Video = new Video();

View File

@@ -0,0 +1,9 @@
using PepperDash.Essentials.Core.Presets;
namespace PepperDash.Essentials.Devices.Common.VideoCodec
{
public interface IConvertiblePreset
{
PresetBase ConvertCodecPreset();
}
}

View File

@@ -22,6 +22,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
void MinMaxLayoutToggle(); void MinMaxLayoutToggle();
} }
/// <summary>
/// Defines the required elements for layout control with direct layout selection
/// </summary>
public interface IHasCodecLayoutsAvailable : IHasCodecLayouts
{
event EventHandler<AvailableLayoutChangedEventArgs> AvailableLayoutsChanged;
StringFeedback AvailableLocalLayoutsFeedback { get; }
List<CodecCommandWithLabel> AvailableLocalLayouts { get; }
void LocalLayoutSet(string layout);
void LocalLayoutSet(CodecCommandWithLabel layout);
}
public class AvailableLayoutChangedEventArgs : EventArgs
{
public List<CodecCommandWithLabel> AvailableLayouts { get; set; }
}
/// <summary> /// <summary>
/// Defines the requirements for Zoom Room layout control /// Defines the requirements for Zoom Room layout control
/// </summary> /// </summary>

View File

@@ -1,5 +1,5 @@
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{ {

View File

@@ -1,4 +1,4 @@
using PepperDash.Essentials.Devices.Common.VideoCodec.Cisco; using PepperDash.Essentials.Devices.Common.VideoCodec;
namespace PepperDash.Essentials.Core.DeviceTypeInterfaces namespace PepperDash.Essentials.Core.DeviceTypeInterfaces
{ {

View File

@@ -371,6 +371,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
LinkVideoCodecCameraLayoutsToApi(codec as IHasCodecLayouts, trilist, joinMap); LinkVideoCodecCameraLayoutsToApi(codec as IHasCodecLayouts, trilist, joinMap);
} }
if (codec is IHasCodecLayoutsAvailable)
{
LinkVideoCodecAvailableLayoutsToApi(codec as IHasCodecLayoutsAvailable, trilist, joinMap);
}
if (codec is IHasSelfviewPosition) if (codec is IHasSelfviewPosition)
{ {
LinkVideoCodecSelfviewPositionToApi(codec as IHasSelfviewPosition, trilist, joinMap); LinkVideoCodecSelfviewPositionToApi(codec as IHasSelfviewPosition, trilist, joinMap);
@@ -1484,6 +1489,14 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentLayoutStringFb.JoinNumber]); codec.LocalLayoutFeedback.LinkInputSig(trilist.StringInput[joinMap.CurrentLayoutStringFb.JoinNumber]);
} }
private void LinkVideoCodecAvailableLayoutsToApi(IHasCodecLayoutsAvailable codec, BasicTriList trilist,
VideoCodecControllerJoinMap joinMap)
{
codec.AvailableLocalLayoutsFeedback.LinkInputSig(trilist.StringInput[joinMap.AvailableLayoutsFb.JoinNumber]);
trilist.SetStringSigAction(joinMap.SelectLayout.JoinNumber, codec.LocalLayoutSet);
}
private void LinkVideoCodecCameraModeToApi(IHasCameraAutoMode codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) private void LinkVideoCodecCameraModeToApi(IHasCameraAutoMode codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{ {
trilist.SetSigFalseAction(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeOn); trilist.SetSigFalseAction(joinMap.CameraModeAuto.JoinNumber, codec.CameraAutoModeOn);
@@ -1995,4 +2008,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
} }
} }
} }
/// <summary>
/// Represents a codec command that might need to have a friendly label applied for UI feedback purposes
/// </summary>
public class CodecCommandWithLabel
{
public string Command { get; private set; }
public string Label { get; private set; }
public CodecCommandWithLabel(string command, string label)
{
Command = command;
Label = label;
}
}
} }