Merge branch 'development' into feature/room-combining

This commit is contained in:
Neil Dorin 2022-01-27 15:50:37 -07:00
commit 4dc4565e69
41 changed files with 1802 additions and 723 deletions

Binary file not shown.

View file

@ -88,7 +88,7 @@
{ {
"name": "Wireless Video", "name": "Wireless Video",
"key": "wePresent-1", "key": "wePresent-1",
"type": "wePresent", "type": "genericSource",
"group": "genericSource", "group": "genericSource",
"uid": 9, "uid": 9,
"properties": { "properties": {

View file

@ -114,7 +114,7 @@
{ {
"name": "Wireless Video", "name": "Wireless Video",
"key": "wePresent-1", "key": "wePresent-1",
"type": "wePresent", "type": "genericSource",
"properties": {}, "properties": {},
"group": "genericSource", "group": "genericSource",
"uid": 3 "uid": 3

View file

@ -151,6 +151,24 @@ namespace PepperDash.Essentials.Room.Config
[JsonProperty("helpMessage")] [JsonProperty("helpMessage")]
public string HelpMessage { get; set; } public string HelpMessage { get; set; }
/// <summary>
/// Read this value to get the help message. It checks for the old and new config format.
/// </summary>
public string HelpMessageForDisplay
{
get
{
if(Help != null && !string.IsNullOrEmpty(Help.Message))
{
return Help.Message;
}
else
{
return HelpMessage;
}
}
}
[JsonProperty("environment")] [JsonProperty("environment")]
public EssentialsEnvironmentPropertiesConfig Environment { get; set; } public EssentialsEnvironmentPropertiesConfig Environment { get; set; }

View file

@ -202,11 +202,28 @@ namespace PepperDash.Essentials
}; };
} }
SetupEnvironmentalControlDevices();
SetSourceListKey(); SetSourceListKey();
EnablePowerOnToLastSource = true; EnablePowerOnToLastSource = true;
} }
private void SetupEnvironmentalControlDevices()
{
if (PropertiesConfig.Environment != null)
{
if (PropertiesConfig.Environment.Enabled)
{
foreach (var d in PropertiesConfig.Environment.DeviceKeys)
{
var envDevice = DeviceManager.GetDeviceForKey(d) as EssentialsDevice;
EnvironmentalControlDevices.Add(envDevice);
}
}
}
}
private void SetSourceListKey() private void SetSourceListKey()
{ {
if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey)) if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey))

View file

@ -214,17 +214,25 @@ namespace PepperDash.Essentials
VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as
PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase; PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase;
if (VideoCodec == null) if (VideoCodec == null)
throw new ArgumentNullException("codec cannot be null"); {
Debug.Console(0, Debug.ErrorLogLevel.Error, "No Video Codec set. Please check 'videoCodecKey' property in room config");
throw new ArgumentNullException("VideoCodec cannot be null");
}
AudioCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.AudioCodecKey) as AudioCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.AudioCodecKey) as
PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase; PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase;
if (AudioCodec == null) if (AudioCodec == null)
Debug.Console(0, this, "No Audio Codec Found"); Debug.Console(0, this, "No Audio Codec Found");
DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IBasicVolumeControls; DefaultAudioDevice = DeviceManager.GetDeviceForKey(PropertiesConfig.DefaultAudioKey) as IBasicVolumeControls;
if (DefaultAudioDevice == null)
{
Debug.Console(0, Debug.ErrorLogLevel.Error, "No Default Audio Device set. Please check 'defaultAudioKey' property in room config");
throw new ArgumentNullException("DefaultAudioDevice cannot be null");
}
InitializeRoom(); InitializeRoom();
} }
@ -326,6 +334,8 @@ namespace PepperDash.Essentials
CallTypeFeedback = new IntFeedback(() => 0); CallTypeFeedback = new IntFeedback(() => 0);
SetupEnvironmentalControlDevices();
SetSourceListKey(); SetSourceListKey();
EnablePowerOnToLastSource = true; EnablePowerOnToLastSource = true;
@ -336,6 +346,21 @@ namespace PepperDash.Essentials
} }
} }
private void SetupEnvironmentalControlDevices()
{
if (PropertiesConfig.Environment != null)
{
if (PropertiesConfig.Environment.Enabled)
{
foreach (var d in PropertiesConfig.Environment.DeviceKeys)
{
var envDevice = DeviceManager.GetDeviceForKey(d) as EssentialsDevice;
EnvironmentalControlDevices.Add(envDevice);
}
}
}
}
private void SetSourceListKey() private void SetSourceListKey()
{ {
@ -419,6 +444,14 @@ namespace PepperDash.Essentials
/// <returns></returns> /// <returns></returns>
public bool RunDefaultCallRoute() public bool RunDefaultCallRoute()
{ {
Debug.Console(2, this, "RunDefaultCallRoute() Currently Sharing Content: {0}", VideoCodec.SharingContentIsOnFeedback.BoolValue);
if (VideoCodec.SharingContentIsOnFeedback.BoolValue)
{
Debug.Console(2, this, "Currently sharing content. Ignoring request to run default call route.");
return false;
}
RunRouteAction(DefaultCodecRouteString); RunRouteAction(DefaultCodecRouteString);
return true; return true;
} }

View file

@ -375,7 +375,7 @@ Params: {2}"
{ {
bridge.AddJoinMap(Key, joinMap); bridge.AddJoinMap(Key, joinMap);
} }
uint i;
if (_config.IsPrimary) if (_config.IsPrimary)
{ {
Debug.Console(1, this, "Linking Primary system Tuner Preset Mirroring"); Debug.Console(1, this, "Linking Primary system Tuner Preset Mirroring");

View file

@ -408,7 +408,7 @@ namespace PepperDash.Essentials
{ {
public EssentialsTouchpanelControllerFactory() public EssentialsTouchpanelControllerFactory()
{ {
TypeNames = new List<string>() { "tsw550", "tsw750", "tsw1050", "tsw560", "tsw760", "tsw1060", "tsw570", "tsw770", "ts770", "tsw1070", "ts1070", "xpanel" }; TypeNames = new List<string>() { "crestronapp", "tsw550", "tsw750", "tsw1050", "tsw560", "tsw760", "tsw1060", "tsw570", "tsw770", "ts770", "tsw1070", "ts1070", "xpanel" };
} }
public override EssentialsDevice BuildDevice(DeviceConfig dc) public override EssentialsDevice BuildDevice(DeviceConfig dc)

View file

@ -54,6 +54,10 @@ Utilization of Essentials Framework falls into the following categories:
For detailed documentation, see the [Wiki](https://github.com/PepperDash/EssentialsFramework/wiki). For detailed documentation, see the [Wiki](https://github.com/PepperDash/EssentialsFramework/wiki).
## Support
* Check out our [Discord Server](https://discord.gg/rWyeRH3K)
## How-To (Getting Started) ## How-To (Getting Started)
See [Getting Started](https://github.com/PepperDash/Essentials/wiki/Get-started#how-to-get-started) See [Getting Started](https://github.com/PepperDash/Essentials/wiki/Get-started#how-to-get-started)

View file

@ -46,6 +46,14 @@ namespace PepperDash.Essentials.Core.Bridges
public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 },
new JoinMetadata { Description = "Raw Occupancy Us Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital }); new JoinMetadata { Description = "Raw Occupancy Us Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("IdentityModeOn")]
public JoinDataComplete IdentityMode = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 },
new JoinMetadata { Description = "Enable Identity Mode", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital });
[JoinName("IdentityModeFeedback")]
public JoinDataComplete IdentityModeFeedback = new JoinDataComplete(new JoinData { JoinNumber = 8, JoinSpan = 1 },
new JoinMetadata { Description = "Identity Mode Feedback", JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinType = eJoinType.Digital });
[JoinName("EnableLedFlash")] [JoinName("EnableLedFlash")]
public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 },
new JoinMetadata { Description = "Enable Led Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); new JoinMetadata { Description = "Enable Led Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital });

View file

@ -5,6 +5,9 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
{ {
public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced
{ {
#region Digital
[JoinName("IsOnline")] [JoinName("IsOnline")]
public JoinDataComplete IsOnline = new JoinDataComplete( public JoinDataComplete IsOnline = new JoinDataComplete(
new JoinData new JoinData
@ -19,20 +22,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
JoinType = eJoinType.Digital 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")] [JoinName("Enable")]
public JoinDataComplete Enable = new JoinDataComplete( public JoinDataComplete Enable = new JoinDataComplete(
new JoinData new JoinData
@ -101,7 +91,11 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
Description = "Sensor Decrease Sensitivity", Description = "Sensor Decrease Sensitivity",
JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital JoinType = eJoinType.Digital
}); });
#endregion
#region Analog
[JoinName("Sensitivity")] [JoinName("Sensitivity")]
public JoinDataComplete Sensitivity = new JoinDataComplete( public JoinDataComplete Sensitivity = new JoinDataComplete(
@ -117,6 +111,28 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
JoinType = eJoinType.Analog JoinType = eJoinType.Analog
}); });
#endregion
#region Serial
[JoinName("Name")]
public JoinDataComplete Name = new JoinDataComplete(
new JoinData
{
JoinNumber = 1,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Sensor Name",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
#endregion
/// <summary> /// <summary>
/// Constructor to use when instantiating this Join Map without inheriting from it /// Constructor to use when instantiating this Join Map without inheriting from it
/// </summary> /// </summary>

View file

@ -922,7 +922,22 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps
#region Analog #region Analog
// TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set
[JoinName("MeetingsToDisplay")]
public JoinDataComplete MeetingsToDisplay = new JoinDataComplete(
new JoinData
{
JoinNumber = 40,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Set/FB the number of meetings to display via the bridge xsig; default: 3 meetings.",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("MinutesBeforeMeetingStart")] [JoinName("MinutesBeforeMeetingStart")]
public JoinDataComplete MinutesBeforeMeetingStart = new JoinDataComplete( public JoinDataComplete MinutesBeforeMeetingStart = new JoinDataComplete(

View file

@ -0,0 +1,77 @@
using System.Collections.Generic;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.GeneralIO;
using PepperDash.Core;
using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials.Core
{
/// <summary>
/// Wrapper class for CEN-IO-RY-104 relay module
/// </summary>
[Description("Wrapper class for the CEN-IO-RY-104 relay module")]
public class CenIoRy104Controller : EssentialsDevice, IRelayPorts
{
private readonly CenIoRy104 _ry104;
/// <summary>
/// Constructor
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
/// <param name="ry104"></param>
public CenIoRy104Controller(string key, string name, CenIoRy104 ry104)
: base(key, name)
{
_ry104 = ry104;
}
/// <summary>
/// Relay port collection
/// </summary>
public CrestronCollection<Relay> RelayPorts
{
get { return _ry104.RelayPorts; }
}
/// <summary>
/// Number of relay ports property
/// </summary>
public int NumberOfRelayPorts
{
get { return _ry104.NumberOfRelayPorts; }
}
}
/// <summary>
/// CEN-IO-RY Controller factory
/// </summary>
public class CenIoRy104ControllerFactory : EssentialsDeviceFactory<CenIoRy104Controller>
{
/// <summary>
/// Constructor
/// </summary>
public CenIoRy104ControllerFactory()
{
TypeNames = new List<string>() { "ceniory104" };
}
public override EssentialsDevice BuildDevice(DeviceConfig dc)
{
Debug.Console(1, "Factory Attempting to create a new CEN-IO-RY-104 Device");
var controlPropertiesConfig = CommFactory.GetControlPropertiesConfig(dc);
if (controlPropertiesConfig == null)
{
Debug.Console(1, "Factory failed to create a new CEN-IO-RY-104 Device");
return null;
}
var ipid = controlPropertiesConfig.IpIdInt;
if (ipid != 0) return new CenIoRy104Controller(dc.Key, dc.Name, new CenIoRy104(ipid, Global.ControlSystem));
Debug.Console(1, "Factory failed to create a new CEN-IO-RY-104 Device using IP-ID-{0}", ipid);
return null;
}
}
}

View file

@ -44,6 +44,12 @@ namespace PepperDash.Essentials.Core.CrestronIO
{ {
RelayOutput = postActivationFunc(config); RelayOutput = postActivationFunc(config);
if (RelayOutput == null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Unable to get parent relay device for device key {0} and port {1}", config.PortDeviceKey, config.PortNumber);
return;
}
RelayOutput.Register(); RelayOutput.Register();
RelayOutput.StateChange += RelayOutput_StateChange; RelayOutput.StateChange += RelayOutput_StateChange;
@ -61,33 +67,36 @@ namespace PepperDash.Essentials.Core.CrestronIO
{ {
if (!Global.ControlSystem.SupportsRelay) if (!Global.ControlSystem.SupportsRelay)
{ {
Debug.Console(0, "GetRelayDevice: Processor does not support relays"); Debug.Console(0, "Processor does not support relays");
return null; return null;
} }
relayDevice = Global.ControlSystem; relayDevice = Global.ControlSystem;
return relayDevice.RelayPorts[dc.PortNumber];
} }
else
var essentialsDevice = DeviceManager.GetDeviceForKey(dc.PortDeviceKey);
if (essentialsDevice == null)
{ {
var relayDev = DeviceManager.GetDeviceForKey(dc.PortDeviceKey) as IRelayPorts; Debug.Console(0, "Device {0} was not found in Device Manager. Check configuration or for errors with device.", dc.PortDeviceKey);
if (relayDev == null)
{
Debug.Console(0, "GetRelayDevice: Device {0} is not a valid device", dc.PortDeviceKey);
return null;
}
relayDevice = relayDev;
}
if (relayDevice == null)
{
Debug.Console(0, "GetRelayDevice: Device '0' is not a valid IRelayPorts Device", dc.PortDeviceKey);
return null; return null;
} }
if (dc.PortNumber > relayDevice.NumberOfRelayPorts) relayDevice = essentialsDevice as IRelayPorts;
{
Debug.Console(0, "GetRelayDevice: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber);
}
return relayDevice.RelayPorts[dc.PortNumber]; if (relayDevice == null)
{
Debug.Console(0, "Device {0} is not a valid relay parent. Please check configuration.", dc.PortDeviceKey);
return null;
}
if (dc.PortNumber <= relayDevice.NumberOfRelayPorts)
{
return relayDevice.RelayPorts[dc.PortNumber];
}
Debug.Console(0, "Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber);
return null;
} }
#endregion #endregion
@ -200,58 +209,6 @@ namespace PepperDash.Essentials.Core.CrestronIO
var portDevice = new GenericRelayDevice(dc.Key, dc.Name, GetRelay, props); var portDevice = new GenericRelayDevice(dc.Key, dc.Name, GetRelay, props);
return portDevice; return portDevice;
/*
if (props.PortDeviceKey == "processor")
portDevice = Global.ControlSystem as IRelayPorts;
else
portDevice = DeviceManager.GetDeviceForKey(props.PortDeviceKey) as IRelayPorts;
if (portDevice == null)
Debug.Console(0, "Unable to add relay device with key '{0}'. Port Device does not support relays", key);
else
{
var cs = (portDevice as CrestronControlSystem);
if (cs != null)
{
// The relay is on a control system processor
if (!cs.SupportsRelay || props.PortNumber > cs.NumberOfRelayPorts)
{
Debug.Console(0, "Port Device: {0} does not support relays or does not have enough relays");
return null;
}
}
else
{
// The relay is on another device type
if (props.PortNumber > portDevice.NumberOfRelayPorts)
{
Debug.Console(0, "Port Device: {0} does not have enough relays");
return null;
}
}
Relay relay = portDevice.RelayPorts[props.PortNumber];
if (!relay.Registered)
{
if (relay.Register() == eDeviceRegistrationUnRegistrationResponse.Success)
return new GenericRelayDevice(key, relay);
else
Debug.Console(0, "Attempt to register relay {0} on device with key '{1}' failed.", props.PortNumber, props.PortDeviceKey);
}
else
{
return new GenericRelayDevice(key, relay);
}
// Future: Check if portDevice is 3-series card or other non control system that supports versiports
}
*/
} }
} }

View file

@ -1,83 +1,83 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharpPro; using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.DeviceSupport;
using Newtonsoft.Json; using Newtonsoft.Json;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.Core.Bridges; using PepperDash.Essentials.Core.Bridges;
namespace PepperDash.Essentials.Core.Lighting namespace PepperDash.Essentials.Core.Lighting
{ {
public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes
{ {
#region ILightingScenes Members #region ILightingScenes Members
public event EventHandler<LightingSceneChangeEventArgs> LightingSceneChange; public event EventHandler<LightingSceneChangeEventArgs> LightingSceneChange;
public List<LightingScene> LightingScenes { get; protected set; } public List<LightingScene> LightingScenes { get; protected set; }
public LightingScene CurrentLightingScene { get; protected set; } public LightingScene CurrentLightingScene { get; protected set; }
public IntFeedback CurrentLightingSceneFeedback { get; protected set; } public IntFeedback CurrentLightingSceneFeedback { get; protected set; }
#endregion #endregion
protected LightingBase(string key, string name) protected LightingBase(string key, string name)
: base(key, name) : base(key, name)
{
LightingScenes = new List<LightingScene>();
CurrentLightingScene = new LightingScene();
//CurrentLightingSceneFeedback = new IntFeedback(() => { return int.Parse(this.CurrentLightingScene.ID); });
}
public abstract void SelectScene(LightingScene scene);
public void SimulateSceneSelect(string sceneName)
{
Debug.Console(1, this, "Simulating selection of scene '{0}'", sceneName);
var scene = LightingScenes.FirstOrDefault(s => s.Name.Equals(sceneName));
if (scene != null)
{
CurrentLightingScene = scene;
OnLightingSceneChange();
}
}
/// <summary>
/// Sets the IsActive property on each scene and fires the LightingSceneChange event
/// </summary>
protected void OnLightingSceneChange()
{
foreach (var scene in LightingScenes)
{
if (scene == CurrentLightingScene)
scene.IsActive = true;
else
scene.IsActive = false;
}
var handler = LightingSceneChange;
if (handler != null)
{
handler(this, new LightingSceneChangeEventArgs(CurrentLightingScene));
}
}
protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, uint joinStart,
string joinMapKey, EiscApiAdvanced bridge)
{ {
var joinMap = new GenericLightingJoinMap(joinStart); LightingScenes = new List<LightingScene>();
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); CurrentLightingScene = new LightingScene();
//CurrentLightingSceneFeedback = new IntFeedback(() => { return int.Parse(this.CurrentLightingScene.ID); });
if (!string.IsNullOrEmpty(joinMapSerialized)) }
public abstract void SelectScene(LightingScene scene);
public void SimulateSceneSelect(string sceneName)
{
Debug.Console(1, this, "Simulating selection of scene '{0}'", sceneName);
var scene = LightingScenes.FirstOrDefault(s => s.Name.Equals(sceneName));
if (scene != null)
{
CurrentLightingScene = scene;
OnLightingSceneChange();
}
}
/// <summary>
/// Sets the IsActive property on each scene and fires the LightingSceneChange event
/// </summary>
protected void OnLightingSceneChange()
{
foreach (var scene in LightingScenes)
{
if (scene == CurrentLightingScene)
scene.IsActive = true;
else
scene.IsActive = false;
}
var handler = LightingSceneChange;
if (handler != null)
{
handler(this, new LightingSceneChangeEventArgs(CurrentLightingScene));
}
}
protected GenericLightingJoinMap LinkLightingToApi(LightingBase lightingDevice, BasicTriList trilist, uint joinStart,
string joinMapKey, EiscApiAdvanced bridge)
{
var joinMap = new GenericLightingJoinMap(joinStart);
var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey);
if (!string.IsNullOrEmpty(joinMapSerialized))
joinMap = JsonConvert.DeserializeObject<GenericLightingJoinMap>(joinMapSerialized); joinMap = JsonConvert.DeserializeObject<GenericLightingJoinMap>(joinMapSerialized);
if (bridge != null) if (bridge != null)
@ -87,52 +87,57 @@ namespace PepperDash.Essentials.Core.Lighting
else else
{ {
Debug.Console(0, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device."); Debug.Console(0, this, "Please update config to use 'eiscapiadvanced' to get all join map features for this device.");
} }
Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); 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(0, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString());
// GenericLighitng Actions & FeedBack // GenericLighitng Actions & FeedBack
trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u]));
var sceneIndex = 0; var sceneIndex = 0;
foreach (var scene in lightingDevice.LightingScenes) foreach (var scene in lightingDevice.LightingScenes)
{ {
trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + sceneIndex), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[sceneIndex])); trilist.SetSigTrueAction((uint)(joinMap.SelectSceneDirect.JoinNumber + sceneIndex), () => lightingDevice.SelectScene(lightingDevice.LightingScenes[sceneIndex]));
scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + sceneIndex)]); scene.IsActiveFeedback.LinkInputSig(trilist.BooleanInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + sceneIndex)]);
trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + sceneIndex)].StringValue = scene.Name; trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + sceneIndex)].StringValue = scene.Name;
trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + sceneIndex)].BoolValue = true; trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + sceneIndex)].BoolValue = true;
sceneIndex++; sceneIndex++;
} }
return joinMap; return joinMap;
} }
} }
public class LightingScene public class LightingScene
{ {
public string Name { get; set; } [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string ID { get; set; } public string Name { get; set; }
bool _IsActive; [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public bool IsActive public string ID { get; set; }
{ bool _IsActive;
get [JsonProperty("isActive", NullValueHandling = NullValueHandling.Ignore)]
{ public bool IsActive
return _IsActive; {
} get
set {
{ return _IsActive;
_IsActive = value; }
IsActiveFeedback.FireUpdate(); set
} {
} _IsActive = value;
public BoolFeedback IsActiveFeedback { get; set; } IsActiveFeedback.FireUpdate();
}
public LightingScene() }
{
IsActiveFeedback = new BoolFeedback(new Func<bool>(() => IsActive)); [JsonIgnore]
} public BoolFeedback IsActiveFeedback { get; set; }
}
public LightingScene()
{
IsActiveFeedback = new BoolFeedback(new Func<bool>(() => IsActive));
}
}
} }

View file

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Resources;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.DeviceSupport;
@ -61,6 +62,8 @@ namespace PepperDash.Essentials.Core
public BoolFeedback RawOccupancyUsFeedback { get; private set; } public BoolFeedback RawOccupancyUsFeedback { get; private set; }
public BoolFeedback IdentityModeFeedback { get; private set; }
// Debug properties // Debug properties
public bool InTestMode { get; private set; } public bool InTestMode { get; private set; }
@ -117,6 +120,8 @@ namespace PepperDash.Essentials.Core
RawOccupancyUsFeedback = new BoolFeedback(() => OccSensor.RawOccupancyDetectedByUltrasonicSensorFeedback.BoolValue); RawOccupancyUsFeedback = new BoolFeedback(() => OccSensor.RawOccupancyDetectedByUltrasonicSensorFeedback.BoolValue);
IdentityModeFeedback = new BoolFeedback(()=>OccSensor.IdentityModeOnFeedback.BoolValue);
UltrasonicSensitivityInVacantStateFeedback = new IntFeedback(() => (int)OccSensor.UltrasonicSensorSensitivityInVacantStateFeedback); UltrasonicSensitivityInVacantStateFeedback = new IntFeedback(() => (int)OccSensor.UltrasonicSensorSensitivityInVacantStateFeedback);
UltrasonicSensitivityInOccupiedStateFeedback = new IntFeedback(() => (int)OccSensor.UltrasonicSensorSensitivityInOccupiedStateFeedback); UltrasonicSensitivityInOccupiedStateFeedback = new IntFeedback(() => (int)OccSensor.UltrasonicSensorSensitivityInOccupiedStateFeedback);
@ -199,6 +204,27 @@ namespace PepperDash.Essentials.Core
{ {
SetAndWhenVacatedState((bool)PropertiesConfig.AndWhenVacatedState); SetAndWhenVacatedState((bool)PropertiesConfig.AndWhenVacatedState);
} }
// TODO [ ] feature/cenoodtcpoe-sensor-sensitivity-configuration
if (PropertiesConfig.UsSensitivityOccupied != null)
{
SetUsSensitivityOccupied((ushort)PropertiesConfig.UsSensitivityOccupied);
}
if (PropertiesConfig.UsSensitivityVacant != null)
{
SetUsSensitivityVacant((ushort)PropertiesConfig.UsSensitivityVacant);
}
if (PropertiesConfig.PirSensitivityOccupied != null)
{
SetPirSensitivityOccupied((ushort)PropertiesConfig.PirSensitivityOccupied);
}
if (PropertiesConfig.PirSensitivityVacant != null)
{
SetPirSensitivityVacant((ushort)PropertiesConfig.PirSensitivityVacant);
}
} }
/// <summary> /// <summary>
@ -279,7 +305,21 @@ namespace PepperDash.Essentials.Core
} }
} }
/// <summary> /// <summary>
/// Sets the identity mode on or off
/// </summary>
/// <param name="state"></param>
public void SetIdentityMode(bool state)
{
if (state)
OccSensor.IdentityModeOn();
else
OccSensor.IdentityModeOff();
Debug.Console(1, this, "Identity Mode: {0}", OccSensor.IdentityModeOnFeedback.BoolValue ? "On" : "Off");
}
/// <summary>
/// Enables or disables the PIR sensor /// Enables or disables the PIR sensor
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
@ -506,6 +546,54 @@ namespace PepperDash.Essentials.Core
} }
} }
/// <summary>
/// Sets the US sensor sensitivity for occupied state
/// </summary>
/// <param name="sensitivity"></param>
public void SetUsSensitivityOccupied(ushort sensitivity)
{
var level = (eSensitivityLevel) sensitivity;
if (level == 0) return;
OccSensor.UltrasonicSensorSensitivityInOccupiedState = level;
}
/// <summary>
/// Sets the US sensor sensitivity for vacant state
/// </summary>
/// <param name="sensitivity"></param>
public void SetUsSensitivityVacant(ushort sensitivity)
{
var level = (eSensitivityLevel)sensitivity;
if (level == 0) return;
OccSensor.UltrasonicSensorSensitivityInVacantState = level;
}
/// <summary>
/// Sets the PIR sensor sensitivity for occupied state
/// </summary>
/// <param name="sensitivity"></param>
public void SetPirSensitivityOccupied(ushort sensitivity)
{
var level = (eSensitivityLevel)sensitivity;
if (level == 0) return;
OccSensor.PassiveInfraredSensorSensitivityInOccupiedState = level;
}
/// <summary>
/// Sets the PIR sensor sensitivity for vacant state
/// </summary>
/// <param name="sensitivity"></param>
public void SetPirSensitivityVacant(ushort sensitivity)
{
var level = (eSensitivityLevel)sensitivity;
if (level == 0) return;
OccSensor.PassiveInfraredSensorSensitivityInVacantState = level;
}
/// <summary> /// <summary>
/// Method to print current settings to console /// Method to print current settings to console
/// </summary> /// </summary>
@ -647,8 +735,11 @@ namespace PepperDash.Essentials.Core
//Sensor Raw States //Sensor Raw States
occController.RawOccupancyPirFeedback.LinkInputSig(trilist.BooleanInput[joinMap.RawOccupancyPirFeedback.JoinNumber]); occController.RawOccupancyPirFeedback.LinkInputSig(trilist.BooleanInput[joinMap.RawOccupancyPirFeedback.JoinNumber]);
occController.RawOccupancyUsFeedback.LinkInputSig(trilist.BooleanInput[joinMap.RawOccupancyUsFeedback.JoinNumber]); occController.RawOccupancyUsFeedback.LinkInputSig(trilist.BooleanInput[joinMap.RawOccupancyUsFeedback.JoinNumber]);
// Identity mode
trilist.SetBoolSigAction(joinMap.IdentityMode.JoinNumber, occController.SetIdentityMode);
occController.IdentityModeFeedback.LinkInputSig(trilist.BooleanInput[joinMap.IdentityModeFeedback.JoinNumber]);
} }
public class CenOdtOccupancySensorBaseControllerFactory : EssentialsDeviceFactory<CenOdtOccupancySensorBaseController> public class CenOdtOccupancySensorBaseControllerFactory : EssentialsDeviceFactory<CenOdtOccupancySensorBaseController>

View file

@ -47,5 +47,35 @@ namespace PepperDash.Essentials.Core
[JsonProperty("andWhenVacatedState")] [JsonProperty("andWhenVacatedState")]
public bool? AndWhenVacatedState { get; set; } public bool? AndWhenVacatedState { get; set; }
// PoE Sensors: CenOdtCPoe
/// <summary>
/// Sets the sensitivity level for US while sensor is in occupied state
/// 1 = low; 2 = medium; 3 = high; 4 = xlow; 5 = 2xlow; 6 = 3xlow
/// </summary>
[JsonProperty("usSensitivityOccupied")]
public ushort? UsSensitivityOccupied { get; set; }
/// <summary>
/// Sets the sensitivity level for US while sensor is in vacant state
/// 1 = low; 2 = medium; 3 = high; 4 = xlow; 5 = 2xlow; 6 = 3xlow
/// </summary>
[JsonProperty("usSensitivityVacant")]
public ushort? UsSensitivityVacant { get; set; }
/// <summary>
/// Sets the sensitivity level for PIR while sensor is in occupied state
/// 1 = low; 2 = medium; 3 = high
/// </summary>
[JsonProperty("pirSensitivityOccupied")]
public ushort? PirSensitivityOccupied { get; set; }
/// <summary>
/// Sets the sensitivity level for PIR while sensor is in vacant state
/// 1 = low; 2 = medium; 3 = high
/// </summary>
[JsonProperty("pirSensitivityVacant")]
public ushort? PirSensitivityVacant { get; set; }
} }
} }

View file

@ -1,4 +1,5 @@
using Crestron.SimplSharpPro; using Crestron.SimplSharp;
using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.DeviceSupport;
using Crestron.SimplSharpPro.GeneralIO; using Crestron.SimplSharpPro.GeneralIO;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -9,15 +10,18 @@ using PepperDash.Essentials.Core.Bridges.JoinMaps;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Config;
using PepperDash_Essentials_Core.PartitionSensor;
namespace PepperDash.Essentials.Core namespace PepperDash.Essentials.Core
{ {
[Description("Wrapper class for GLS Cresnet Partition Sensor")] [Description("Wrapper class for GLS Cresnet Partition Sensor")]
public class GlsPartitionSensorController : CrestronGenericBridgeableBaseDevice, IPartitionStateProvider public class GlsPartitionSensorController : CrestronGenericBridgeableBaseDevice, IPartitionStateProvider
{ {
private GlsPartCn _partitionSensor;
public StringFeedback NameFeedback { get; private set; } public GlsPartitionSensorPropertiesConfig PropertiesConfig { get; private set; }
private GlsPartCn _partitionSensor;
public BoolFeedback EnableFeedback { get; private set; } public BoolFeedback EnableFeedback { get; private set; }
public BoolFeedback PartitionPresentFeedback { get; private set; } public BoolFeedback PartitionPresentFeedback { get; private set; }
public BoolFeedback PartitionNotSensedFeedback { get; private set; } public BoolFeedback PartitionNotSensedFeedback { get; private set; }
@ -32,23 +36,71 @@ namespace PepperDash.Essentials.Core
public GlsPartitionSensorController(string key, Func<DeviceConfig, GlsPartCn> preActivationFunc, DeviceConfig config) public GlsPartitionSensorController(string key, Func<DeviceConfig, GlsPartCn> preActivationFunc, DeviceConfig config)
: base(key, config.Name) : base(key, config.Name)
{ {
var props = config.Properties.ToObject<GlsPartitionSensorPropertiesConfig>();
if (props != null)
{
PropertiesConfig = props;
}
else
{
Debug.Console(1, this, "props are null. Unable to deserialize into GlsPartSensorPropertiesConfig");
}
AddPreActivationAction(() => AddPreActivationAction(() =>
{ {
_partitionSensor = preActivationFunc(config); _partitionSensor = preActivationFunc(config);
RegisterCrestronGenericBase(_partitionSensor); RegisterCrestronGenericBase(_partitionSensor);
NameFeedback = new StringFeedback(() => Name);
EnableFeedback = new BoolFeedback(() => InTestMode ? TestEnableFeedback : _partitionSensor.EnableFeedback.BoolValue); EnableFeedback = new BoolFeedback(() => InTestMode ? TestEnableFeedback : _partitionSensor.EnableFeedback.BoolValue);
PartitionPresentFeedback = new BoolFeedback(() => InTestMode ? TestPartitionSensedFeedback : _partitionSensor.PartitionSensedFeedback.BoolValue); PartitionPresentFeedback = new BoolFeedback(() => InTestMode ? TestPartitionSensedFeedback : _partitionSensor.PartitionSensedFeedback.BoolValue);
PartitionNotSensedFeedback = new BoolFeedback(() => InTestMode ? !TestPartitionSensedFeedback : _partitionSensor.PartitionNotSensedFeedback.BoolValue); PartitionNotSensedFeedback = new BoolFeedback(() => InTestMode ? !TestPartitionSensedFeedback : _partitionSensor.PartitionNotSensedFeedback.BoolValue);
SensitivityFeedback = new IntFeedback(() => InTestMode ? TestSensitivityFeedback : _partitionSensor.SensitivityFeedback.UShortValue); SensitivityFeedback = new IntFeedback(() => InTestMode ? TestSensitivityFeedback : _partitionSensor.SensitivityFeedback.UShortValue);
if (_partitionSensor != null) _partitionSensor.BaseEvent += PartitionSensor_BaseEvent; if (_partitionSensor != null)
{
_partitionSensor.BaseEvent += PartitionSensor_BaseEvent;
}
}); });
}
private void PartitionSensor_BaseEvent(GenericBase device, BaseEventArgs args) AddPostActivationAction(() =>
{
_partitionSensor.OnlineStatusChange += (o, a) =>
{
if (a.DeviceOnLine)
{
ApplySettingsToSensorFromConfig();
}
};
if (_partitionSensor.IsOnline)
{
ApplySettingsToSensorFromConfig();
}
});
}
private void ApplySettingsToSensorFromConfig()
{
if (_partitionSensor.IsOnline == false) return;
Debug.Console(1, this, "Attempting to apply settings to sensor from config");
if (PropertiesConfig.Sensitivity != null)
{
Debug.Console(1, this, "Sensitivity found, attempting to set value '{0}' from config",
PropertiesConfig.Sensitivity);
_partitionSensor.Sensitivity.UShortValue = (ushort) PropertiesConfig.Sensitivity;
}
else
{
Debug.Console(1, this, "Sensitivity null, no value specified in config");
}
}
private void PartitionSensor_BaseEvent(GenericBase device, BaseEventArgs args)
{ {
Debug.Console(2, this, "EventId: {0}, Index: {1}", args.EventId, args.Index); Debug.Console(2, this, "EventId: {0}, Index: {1}", args.EventId, args.Index);
@ -61,11 +113,13 @@ namespace PepperDash.Essentials.Core
} }
case (GlsPartCn.PartitionSensedFeedbackEventId): case (GlsPartCn.PartitionSensedFeedbackEventId):
{ {
Debug.Console(1, this, "Partition Sensed State: {0}", _partitionSensor.PartitionSensedFeedback.BoolValue);
PartitionPresentFeedback.FireUpdate(); PartitionPresentFeedback.FireUpdate();
break; break;
} }
case (GlsPartCn.PartitionNotSensedFeedbackEventId): case (GlsPartCn.PartitionNotSensedFeedbackEventId):
{ {
Debug.Console(1, this, "Partition Not Sensed State: {0}", _partitionSensor.PartitionNotSensedFeedback.BoolValue);
PartitionNotSensedFeedback.FireUpdate(); PartitionNotSensedFeedback.FireUpdate();
break; break;
} }
@ -73,7 +127,7 @@ namespace PepperDash.Essentials.Core
{ {
SensitivityFeedback.FireUpdate(); SensitivityFeedback.FireUpdate();
break; break;
} }
default: default:
{ {
Debug.Console(2, this, "Unhandled args.EventId: {0}", args.EventId); Debug.Console(2, this, "Unhandled args.EventId: {0}", args.EventId);
@ -133,7 +187,22 @@ namespace PepperDash.Essentials.Core
Debug.Console(1, this, "InTestMode: {0}, unable to set sensitivity value: {1}", InTestMode.ToString(), value); Debug.Console(1, this, "InTestMode: {0}, unable to set sensitivity value: {1}", InTestMode.ToString(), value);
} }
public void SetEnableState(bool state) public void GetSettings()
{
var dash = new string('*', 50);
CrestronConsole.PrintLine(string.Format("{0}\n", dash));
Debug.Console(0, this, "Enabled State: {0}", _partitionSensor.EnableFeedback.BoolValue);
Debug.Console(0, this, "Partition Sensed State: {0}", _partitionSensor.PartitionSensedFeedback.BoolValue);
Debug.Console(0, this, "Partition Not Sensed State: {0}", _partitionSensor.PartitionNotSensedFeedback.BoolValue);
Debug.Console(0, this, "Sensitivity Value: {0}", _partitionSensor.SensitivityFeedback.UShortValue);
CrestronConsole.PrintLine(string.Format("{0}\n", dash));
}
public void SetEnableState(bool state)
{ {
Debug.Console(2, this, "Sensor is {0}, SetEnableState: {1}", _partitionSensor == null ? "null" : "not null", state); Debug.Console(2, this, "Sensor is {0}, SetEnableState: {1}", _partitionSensor == null ? "null" : "not null", state);
if (_partitionSensor == null) if (_partitionSensor == null)
@ -189,18 +258,20 @@ namespace PepperDash.Essentials.Core
Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); Debug.Console(1, this, "Linking to Trilist '{0}'", trilist.ID.ToString("X"));
Debug.Console(0, this, "Linking to Bridge Type {0}", GetType().Name); Debug.Console(0, this, "Linking to Bridge Type {0}", GetType().Name);
// link input from simpl IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]);
trilist.StringInput[joinMap.Name.JoinNumber].StringValue = _partitionSensor.Name;
trilist.SetBoolSigAction(joinMap.Enable.JoinNumber, SetEnableState); trilist.SetBoolSigAction(joinMap.Enable.JoinNumber, SetEnableState);
EnableFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Enable.JoinNumber]);
PartitionPresentFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionSensed.JoinNumber]);
PartitionNotSensedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionNotSensed.JoinNumber]);
trilist.SetSigTrueAction(joinMap.IncreaseSensitivity.JoinNumber, IncreaseSensitivity); trilist.SetSigTrueAction(joinMap.IncreaseSensitivity.JoinNumber, IncreaseSensitivity);
trilist.SetSigTrueAction(joinMap.DecreaseSensitivity.JoinNumber, DecreaseSensitivity); trilist.SetSigTrueAction(joinMap.DecreaseSensitivity.JoinNumber, DecreaseSensitivity);
trilist.SetUShortSigAction(joinMap.Sensitivity.JoinNumber, SetSensitivity);
// link output to simpl SensitivityFeedback.LinkInputSig(trilist.UShortInput[joinMap.Sensitivity.JoinNumber]);
IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); trilist.SetUShortSigAction(joinMap.Sensitivity.JoinNumber, SetSensitivity);
EnableFeedback.LinkInputSig(trilist.BooleanInput[joinMap.Enable.JoinNumber]);
PartitionPresentFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionSensed.JoinNumber]);
PartitionNotSensedFeedback.LinkInputSig(trilist.BooleanInput[joinMap.PartitionNotSensed.JoinNumber]);
SensitivityFeedback.LinkInputSig(trilist.UShortInput[joinMap.Sensitivity.JoinNumber]);
FeedbacksFireUpdates(); FeedbacksFireUpdates();
@ -218,6 +289,7 @@ namespace PepperDash.Essentials.Core
{ {
if (a.DeviceOnLine) if (a.DeviceOnLine)
{ {
trilist.StringInput[joinMap.Name.JoinNumber].StringValue = _partitionSensor.Name;
FeedbacksFireUpdates(); FeedbacksFireUpdates();
} }
}; };
@ -225,8 +297,7 @@ namespace PepperDash.Essentials.Core
private void FeedbacksFireUpdates() private void FeedbacksFireUpdates()
{ {
IsOnline.FireUpdate(); IsOnline.FireUpdate();
NameFeedback.FireUpdate();
EnableFeedback.FireUpdate(); EnableFeedback.FireUpdate();
PartitionPresentFeedback.FireUpdate(); PartitionPresentFeedback.FireUpdate();
PartitionNotSensedFeedback.FireUpdate(); PartitionNotSensedFeedback.FireUpdate();

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash_Essentials_Core.PartitionSensor
{
public class GlsPartitionSensorPropertiesConfig
{
/// <summary>
/// Sets the sensor sensitivity
/// </summary>
/// <remarks>
/// The sensitivity range shall be between 1(lowest) to 10 (highest).
/// </remarks>
[JsonProperty("sensitivity")]
public ushort? Sensitivity { get; set; }
}
}

View file

@ -182,6 +182,7 @@
<Compile Include="Crestron IO\Inputs\GenericVersiportInputDevice.cs" /> <Compile Include="Crestron IO\Inputs\GenericVersiportInputDevice.cs" />
<Compile Include="Crestron IO\Inputs\IDigitalInput.cs" /> <Compile Include="Crestron IO\Inputs\IDigitalInput.cs" />
<Compile Include="Crestron IO\IOPortConfig.cs" /> <Compile Include="Crestron IO\IOPortConfig.cs" />
<Compile Include="Crestron IO\Relay\CenIoRy104Controller.cs" />
<Compile Include="Crestron IO\Relay\GenericRelayDevice.cs" /> <Compile Include="Crestron IO\Relay\GenericRelayDevice.cs" />
<Compile Include="Crestron IO\Relay\ISwitchedOutput.cs" /> <Compile Include="Crestron IO\Relay\ISwitchedOutput.cs" />
<Compile Include="Crestron IO\StatusSign\StatusSignController.cs" /> <Compile Include="Crestron IO\StatusSign\StatusSignController.cs" />
@ -236,6 +237,7 @@
<Compile Include="Occupancy\GlsOccupancySensorPropertiesConfig.cs" /> <Compile Include="Occupancy\GlsOccupancySensorPropertiesConfig.cs" />
<Compile Include="Occupancy\GlsOirOccupancySensorController.cs" /> <Compile Include="Occupancy\GlsOirOccupancySensorController.cs" />
<Compile Include="PartitionSensor\EssentialsPartitionController.cs" /> <Compile Include="PartitionSensor\EssentialsPartitionController.cs" />
<Compile Include="PartitionSensor\GlsPartitionSensorPropertiesConfig.cs" />
<Compile Include="PartitionSensor\IPartitionStateProvider.cs" /> <Compile Include="PartitionSensor\IPartitionStateProvider.cs" />
<Compile Include="Occupancy\OccupancyAggregatorConfig.cs" /> <Compile Include="Occupancy\OccupancyAggregatorConfig.cs" />
<Compile Include="Queues\ComsMessage.cs" /> <Compile Include="Queues\ComsMessage.cs" />

View file

@ -11,6 +11,8 @@ using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.DeviceTypeInterfaces;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Core namespace PepperDash.Essentials.Core
{ {
/// <summary> /// <summary>
@ -18,6 +20,8 @@ namespace PepperDash.Essentials.Core
/// </summary> /// </summary>
public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -35,6 +39,16 @@ namespace PepperDash.Essentials.Core
public bool OccupancyStatusProviderIsRemote { get; private set; } public bool OccupancyStatusProviderIsRemote { get; private set; }
public List<EssentialsDevice> EnvironmentalControlDevices { get; protected set; }
public bool HasEnvironmentalControlDevices
{
get
{
return EnvironmentalControlDevices != null && EnvironmentalControlDevices.Count > 0;
}
}
protected abstract Func<bool> IsWarmingFeedbackFunc { get; } protected abstract Func<bool> IsWarmingFeedbackFunc { get; }
protected abstract Func<bool> IsCoolingFeedbackFunc { get; } protected abstract Func<bool> IsCoolingFeedbackFunc { get; }
@ -119,6 +133,8 @@ namespace PepperDash.Essentials.Core
public EssentialsRoomBase(DeviceConfig config) public EssentialsRoomBase(DeviceConfig config)
: base(config) : base(config)
{ {
EnvironmentalControlDevices = new List<EssentialsDevice>();
// Setup the ShutdownPromptTimer // Setup the ShutdownPromptTimer
ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer");
ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) =>

View file

@ -15,7 +15,7 @@ namespace PepperDash.Essentials.Core
/// <summary> /// <summary>
/// Describes the basic functionality of an EssentialsRoom /// Describes the basic functionality of an EssentialsRoom
/// </summary> /// </summary>
public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute, IEnvironmentalControls
{ {
BoolFeedback OnFeedback { get; } BoolFeedback OnFeedback { get; }

View file

@ -4,6 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using PepperDash.Core;
namespace PepperDash.Essentials.Core namespace PepperDash.Essentials.Core
{ {
@ -66,6 +68,14 @@ namespace PepperDash.Essentials.Core
bool RunDefaultCallRoute(); bool RunDefaultCallRoute();
} }
/// <summary>
/// Describes environmental controls available on a room such as lighting, shades, temperature, etc.
/// </summary>
public interface IEnvironmentalControls
{
List<EssentialsDevice> EnvironmentalControlDevices { get; }
bool HasEnvironmentalControlDevices { get; }
}
} }

View file

@ -31,6 +31,7 @@ namespace PepperDash.Essentials.Core.Shades
public interface IShadesOpenCloseStop : IShadesOpenClose public interface IShadesOpenCloseStop : IShadesOpenClose
{ {
void StopOrPreset(); void StopOrPreset();
string StopOrPresetButtonLabel { get; }
} }
/// <summary> /// <summary>

View file

@ -483,7 +483,7 @@ namespace PepperDash.Essentials.DM
Debug.Console(2, this, "Adding output port '{0}'", portKey); Debug.Console(2, this, "Adding output port '{0}'", portKey);
OutputPorts.Add(new RoutingOutputPort(portKey, sigType, portType, selector, this) OutputPorts.Add(new RoutingOutputPort(portKey, sigType, portType, selector, this)
{ {
FeedbackMatchObject = Chassis.Outputs[(uint)selector] FeedbackMatchObject = selector
}); });
}*/ }*/

View file

@ -1285,7 +1285,10 @@ namespace PepperDash.Essentials.DM
var output = outputSelector as DMOutput; var output = outputSelector as DMOutput;
if (output == null) var isUsbInput = (sigType & eRoutingSignalType.UsbInput) == eRoutingSignalType.UsbInput;
var isUsbOutput = (sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput;
if (output == null && !(isUsbOutput || isUsbInput))
{ {
Debug.Console(0, this, Debug.ErrorLogLevel.Warning, Debug.Console(0, this, Debug.ErrorLogLevel.Warning,
"Unable to execute switch for inputSelector {0} to outputSelector {1}", inputSelector, "Unable to execute switch for inputSelector {0} to outputSelector {1}", inputSelector,
@ -1316,7 +1319,10 @@ namespace PepperDash.Essentials.DM
if ((sigType & eRoutingSignalType.Video) == eRoutingSignalType.Video) if ((sigType & eRoutingSignalType.Video) == eRoutingSignalType.Video)
{ {
Chassis.VideoEnter.BoolValue = true; Chassis.VideoEnter.BoolValue = true;
output.VideoOut = input; //Chassis.Outputs[output].VideoOut = inCard; if (output != null)
{
output.VideoOut = input; //Chassis.Outputs[output].VideoOut = inCard;
}
} }
if ((sigType & eRoutingSignalType.Audio) == eRoutingSignalType.Audio) if ((sigType & eRoutingSignalType.Audio) == eRoutingSignalType.Audio)
@ -1326,17 +1332,66 @@ namespace PepperDash.Essentials.DM
{ {
dmMdMnxn.AudioEnter.BoolValue = true; dmMdMnxn.AudioEnter.BoolValue = true;
} }
output.AudioOut = input; if (output != null)
//Chassis.Outputs[output].AudioOut = inCard; {
output.AudioOut = input;
}
} }
if ((sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput || (sigType & eRoutingSignalType.UsbInput) == eRoutingSignalType.UsbInput) if ((sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput)
{ {
Chassis.USBEnter.BoolValue = true; Chassis.USBEnter.BoolValue = true;
output.USBRoutedTo = input; if (inputSelector == null && output != null)
{
//clearing the route is intended
output.USBRoutedTo = null;
return;
}
if (inputSelector != null && input == null)
{
//input selector is DMOutput...we're doing a out to out route
var tempInput = inputSelector as DMOutput;
if (tempInput == null || output == null)
{
return;
}
output.USBRoutedTo = tempInput;
return;
}
if (input != null & output != null)
{
output.USBRoutedTo = input;
}
} }
if((sigType & eRoutingSignalType.UsbInput) != eRoutingSignalType.UsbInput)
{
return;
}
Chassis.USBEnter.BoolValue = true;
if (output != null)
{
output.USBRoutedTo = input;
return;
}
var tempOutput = outputSelector as DMInput;
if (tempOutput == null)
{
Debug.Console(0, this, Debug.ErrorLogLevel.Warning,
"Unable to execute switch for inputSelector {0} to outputSelector {1}", inputSelector,
outputSelector);
return;
}
tempOutput.USBRoutedTo = input;
} }
#endregion #endregion
#region IRoutingNumeric Members #region IRoutingNumeric Members
@ -1349,8 +1404,10 @@ namespace PepperDash.Essentials.DM
DMInputOutputBase dmCard; DMInputOutputBase dmCard;
//Routing Input to Input or Output to Input
if ((sigType & eRoutingSignalType.UsbInput) == eRoutingSignalType.UsbInput) if ((sigType & eRoutingSignalType.UsbInput) == eRoutingSignalType.UsbInput)
{ {
Debug.Console(2, this, "Executing USB Input switch.\r\n in:{0} output: {1}", inputSelector, outputSelector);
if (outputSelector > chassisSize) if (outputSelector > chassisSize)
{ {
uint outputIndex; uint outputIndex;
@ -1370,13 +1427,14 @@ namespace PepperDash.Essentials.DM
dmCard = Chassis.Inputs[inputSelector]; dmCard = Chassis.Inputs[inputSelector];
} }
ExecuteSwitch(dmCard, Chassis.Outputs[outputSelector], sigType); ExecuteSwitch(dmCard, Chassis.Inputs[outputSelector], sigType);
return; return;
} }
if ((sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput) if ((sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput)
{ {
Debug.Console(2, this, "Executing USB Output switch.\r\n in:{0} output: {1}", inputSelector, outputSelector); Debug.Console(2, this, "Executing USB Output switch.\r\n in:{0} output: {1}", inputSelector, outputSelector);
//routing Output to Output or Input to Output
if (inputSelector > chassisSize) if (inputSelector > chassisSize)
{ {
//wanting to route an output to an output. Subtract chassis size and get output, unless it's 8x8 //wanting to route an output to an output. Subtract chassis size and get output, unless it's 8x8

View file

@ -14,7 +14,7 @@ namespace PepperDash.Essentials.DM
{ {
[Description("Wrapper Class for DM-RMC-4K-Z-SCALER-C")] [Description("Wrapper Class for DM-RMC-4K-Z-SCALER-C")]
public class DmRmc4kZScalerCController : DmRmcControllerBase, IRmcRoutingWithFeedback, public class DmRmc4kZScalerCController : DmRmcControllerBase, IRmcRoutingWithFeedback,
IIROutputPorts, IComPorts, ICec IIROutputPorts, IComPorts, ICec, IRelayPorts
{ {
private readonly DmRmc4kzScalerC _rmc; private readonly DmRmc4kzScalerC _rmc;
@ -168,5 +168,18 @@ namespace PepperDash.Essentials.DM
} }
#endregion #endregion
#region Implementation of IRelayPorts
public CrestronCollection<Relay> RelayPorts
{
get { return _rmc.RelayPorts; }
}
public int NumberOfRelayPorts
{
get { return _rmc.NumberOfRelayPorts; }
}
#endregion
} }
} }

View file

@ -69,6 +69,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec
[JsonProperty("directoryResults")] [JsonProperty("directoryResults")]
public List<DirectoryItem> CurrentDirectoryResults { get; private set; } public List<DirectoryItem> CurrentDirectoryResults { get; private set; }
[JsonProperty("contacts")]
public List<DirectoryItem> Contacts public List<DirectoryItem> Contacts
{ {
get get
@ -77,6 +78,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec
} }
} }
[JsonProperty("folders")]
public List<DirectoryItem> Folders public List<DirectoryItem> Folders
{ {
get get

View file

@ -123,6 +123,8 @@
<Compile Include="Cameras\CameraControl.cs" /> <Compile Include="Cameras\CameraControl.cs" />
<Compile Include="Display\PanasonicThDisplay.cs" /> <Compile Include="Display\PanasonicThDisplay.cs" />
<Compile Include="VideoCodec\Interfaces\IHasMeetingInfo.cs" /> <Compile Include="VideoCodec\Interfaces\IHasMeetingInfo.cs" />
<Compile Include="VideoCodec\Interfaces\IHasMeetingLock.cs" />
<Compile Include="VideoCodec\Interfaces\IHasMeetingRecording.cs" />
<Compile Include="VideoCodec\Interfaces\IHasParticipants.cs" /> <Compile Include="VideoCodec\Interfaces\IHasParticipants.cs" />
<Compile Include="VideoCodec\Interfaces\IHasPresentationOnlyMeeting.cs" /> <Compile Include="VideoCodec\Interfaces\IHasPresentationOnlyMeeting.cs" />
<Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" /> <Compile Include="VideoCodec\Interfaces\IHasSelfviewPosition.cs" />

View file

@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Devices.Common
public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingOutputs public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingOutputs
{ {
public IrOutputPortController IrPort { get; private set; } public IrOutputPortController IrPort { get; private set; }
public const string StandardDriverName = "Apple AppleTV-v2.ir"; public const string StandardDriverName = "Apple_AppleTV_4th_Gen_Essentials.ir";
public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } } public uint DisplayUiType { get { return DisplayUiConstants.TypeAppleTv; } }
public AppleTV(string key, string name, IrOutputPortController portCont) public AppleTV(string key, string name, IrOutputPortController portCont)

View file

@ -28,9 +28,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public class CiscoSparkCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory, public class CiscoSparkCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory,
IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayouts, IHasCodecSelfView, IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayouts, IHasCodecSelfView,
ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute
IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute, IHasDoNotDisturbMode,
IHasHalfWakeMode
{ {
private bool _externalSourceChangeRequested; private bool _externalSourceChangeRequested;
@ -318,10 +316,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
CameraIsMutedFeedback = CameraIsOffFeedback; CameraIsMutedFeedback = CameraIsOffFeedback;
SupportsCameraOff = true; SupportsCameraOff = true;
DoNotDisturbModeIsOnFeedback = new BoolFeedback(() => CodecStatus.Status.Conference.DoNotDisturb.BoolValue);
HalfWakeModeIsOnFeedback = new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "halfwake");
EnteringStandbyModeFeedback = new BoolFeedback(() => CodecStatus.Status.Standby.State.Value.ToLower() == "enteringstandby");
PresentationViewMaximizedFeedback = new BoolFeedback(() => CurrentPresentationView == "Maximized"); PresentationViewMaximizedFeedback = new BoolFeedback(() => CurrentPresentationView == "Maximized");
Communication = comm; Communication = comm;
@ -419,12 +413,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate; CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate;
CodecStatus.Status.Audio.VolumeMute.ValueChangedAction = MuteFeedback.FireUpdate; CodecStatus.Status.Audio.VolumeMute.ValueChangedAction = MuteFeedback.FireUpdate;
CodecStatus.Status.Audio.Microphones.Mute.ValueChangedAction = PrivacyModeIsOnFeedback.FireUpdate; CodecStatus.Status.Audio.Microphones.Mute.ValueChangedAction = PrivacyModeIsOnFeedback.FireUpdate;
CodecStatus.Status.Standby.State.ValueChangedAction = new Action(() => CodecStatus.Status.Standby.State.ValueChangedAction = StandbyIsOnFeedback.FireUpdate;
{
StandbyIsOnFeedback.FireUpdate();
HalfWakeModeIsOnFeedback.FireUpdate();
EnteringStandbyModeFeedback.FireUpdate();
});
CodecStatus.Status.RoomAnalytics.PeoplePresence.ValueChangedAction = RoomIsOccupiedFeedback.FireUpdate; CodecStatus.Status.RoomAnalytics.PeoplePresence.ValueChangedAction = RoomIsOccupiedFeedback.FireUpdate;
CodecStatus.Status.RoomAnalytics.PeopleCount.Current.ValueChangedAction = PeopleCountFeedback.FireUpdate; CodecStatus.Status.RoomAnalytics.PeopleCount.Current.ValueChangedAction = PeopleCountFeedback.FireUpdate;
CodecStatus.Status.Cameras.SpeakerTrack.Status.ValueChangedAction = CameraAutoModeIsOnFeedback.FireUpdate; CodecStatus.Status.Cameras.SpeakerTrack.Status.ValueChangedAction = CameraAutoModeIsOnFeedback.FireUpdate;
@ -432,9 +421,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
CodecStatus.Status.Video.Selfview.Mode.ValueChangedAction = SelfviewIsOnFeedback.FireUpdate; CodecStatus.Status.Video.Selfview.Mode.ValueChangedAction = SelfviewIsOnFeedback.FireUpdate;
CodecStatus.Status.Video.Selfview.PIPPosition.ValueChangedAction = ComputeSelfviewPipStatus; CodecStatus.Status.Video.Selfview.PIPPosition.ValueChangedAction = ComputeSelfviewPipStatus;
CodecStatus.Status.Video.Layout.LayoutFamily.Local.ValueChangedAction = ComputeLocalLayout; CodecStatus.Status.Video.Layout.LayoutFamily.Local.ValueChangedAction = ComputeLocalLayout;
CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = SharingContentIsOnFeedback.FireUpdate; CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = () =>
CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = FarEndIsSharingContentFeedback.FireUpdate; {
CodecStatus.Status.Conference.DoNotDisturb.ValueChangedAction = DoNotDisturbModeIsOnFeedback.FireUpdate; SharingContentIsOnFeedback.FireUpdate();
FarEndIsSharingContentFeedback.FireUpdate();
};
try try
{ {
@ -588,7 +579,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
prefix + "/Status/Audio" + Delimiter + prefix + "/Status/Audio" + Delimiter +
prefix + "/Status/Call" + Delimiter + prefix + "/Status/Call" + Delimiter +
prefix + "/Status/Conference/Presentation" + Delimiter + prefix + "/Status/Conference/Presentation" + Delimiter +
prefix + "/Status/Conference/DoNotDisturb" + Delimiter +
prefix + "/Status/Cameras/SpeakerTrack" + Delimiter + prefix + "/Status/Cameras/SpeakerTrack" + Delimiter +
prefix + "/Status/RoomAnalytics" + Delimiter + prefix + "/Status/RoomAnalytics" + Delimiter +
prefix + "/Status/RoomPreset" + Delimiter + prefix + "/Status/RoomPreset" + Delimiter +
@ -597,11 +587,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
prefix + "/Status/Video/Layout" + Delimiter + prefix + "/Status/Video/Layout" + Delimiter +
prefix + "/Status/Video/Input/MainVideoMute" + Delimiter + prefix + "/Status/Video/Input/MainVideoMute" + Delimiter +
prefix + "/Bookings" + Delimiter + prefix + "/Bookings" + Delimiter +
prefix + "/Event/CallDisconnect" + Delimiter +
prefix + "/Event/Bookings" + Delimiter + prefix + "/Event/Bookings" + Delimiter +
prefix + "/Event/CameraPresetListUpdated" + Delimiter + prefix + "/Event/CameraPresetListUpdated" + Delimiter +
prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter + prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter;
prefix + "/Event/CallDisconnect" + Delimiter; // Keep CallDisconnect last to detect when feedback registration completes correctly
} }
#endregion #endregion
@ -1510,50 +1499,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge) public override void LinkToApi(BasicTriList trilist, uint joinStart, string joinMapKey, EiscApiAdvanced bridge)
{ {
var joinMap = new CiscoCodecJoinMap(joinStart);
var customJoins = JoinMapHelper.TryGetJoinMapAdvancedForDevice(joinMapKey);
if (customJoins != null)
{
joinMap.SetCustomJoinData(customJoins);
}
if (bridge != null)
{
bridge.AddJoinMap(Key, joinMap);
}
LinkVideoCodecToApi(this, trilist, joinStart, joinMapKey, bridge); LinkVideoCodecToApi(this, trilist, joinStart, joinMapKey, bridge);
LinkCiscoCodecToApi(trilist, joinMap);
}
public void LinkCiscoCodecToApi(BasicTriList trilist, CiscoCodecJoinMap joinMap)
{
var dndCodec = this as IHasDoNotDisturbMode;
if (dndCodec != null)
{
dndCodec.DoNotDisturbModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateDoNotDisturbMode.JoinNumber]);
dndCodec.DoNotDisturbModeIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.DeactivateDoNotDisturbMode.JoinNumber]);
trilist.SetSigFalseAction(joinMap.ActivateDoNotDisturbMode.JoinNumber, () => dndCodec.ActivateDoNotDisturbMode());
trilist.SetSigFalseAction(joinMap.DeactivateDoNotDisturbMode.JoinNumber, () => dndCodec.DeactivateDoNotDisturbMode());
trilist.SetSigFalseAction(joinMap.ToggleDoNotDisturbMode.JoinNumber, () => dndCodec.ToggleDoNotDisturbMode());
}
var halfwakeCodec = this as IHasHalfWakeMode;
if (halfwakeCodec != null)
{
halfwakeCodec.StandbyIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateStandby.JoinNumber]);
halfwakeCodec.StandbyIsOnFeedback.LinkComplementInputSig(trilist.BooleanInput[joinMap.DeactivateStandby.JoinNumber]);
halfwakeCodec.HalfWakeModeIsOnFeedback.LinkInputSig(trilist.BooleanInput[joinMap.ActivateHalfWakeMode.JoinNumber]);
halfwakeCodec.EnteringStandbyModeFeedback.LinkInputSig(trilist.BooleanInput[joinMap.EnteringStandbyMode.JoinNumber]);
trilist.SetSigFalseAction(joinMap.ActivateStandby.JoinNumber, () => halfwakeCodec.StandbyActivate());
trilist.SetSigFalseAction(joinMap.DeactivateStandby.JoinNumber, () => halfwakeCodec.StandbyDeactivate());
trilist.SetSigFalseAction(joinMap.ActivateHalfWakeMode.JoinNumber, () => halfwakeCodec.HalfwakeActivate());
}
} }
/// <summary> /// <summary>
@ -2127,47 +2073,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
else else
CameraMuteOn(); CameraMuteOn();
} }
#region IHasDoNotDisturbMode Members
public BoolFeedback DoNotDisturbModeIsOnFeedback { get; private set; }
public void ActivateDoNotDisturbMode()
{
SendText("xCommand Conference DoNotDisturb Activate");
}
public void DeactivateDoNotDisturbMode()
{
SendText("xCommand Conference DoNotDisturb Deactivate");
}
public void ToggleDoNotDisturbMode()
{
if (DoNotDisturbModeIsOnFeedback.BoolValue)
{
DeactivateDoNotDisturbMode();
}
else
{
ActivateDoNotDisturbMode();
}
}
#endregion
#region IHasHalfWakeMode Members
public BoolFeedback HalfWakeModeIsOnFeedback { get; private set; }
public BoolFeedback EnteringStandbyModeFeedback { get; private set; }
public void HalfwakeActivate()
{
SendText("xCommand Standby Halfwake");
}
#endregion
} }
@ -2290,5 +2195,4 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco
return new VideoCodec.Cisco.CiscoSparkCodec(dc, comm); return new VideoCodec.Cisco.CiscoSparkCodec(dc, comm);
} }
} }
} }

View file

@ -6,6 +6,8 @@ using Crestron.SimplSharp;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.VideoCodec namespace PepperDash.Essentials.Devices.Common.VideoCodec
{ {
/// <summary> /// <summary>
@ -25,7 +27,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
/// </summary> /// </summary>
public interface IHasZoomRoomLayouts : IHasCodecLayouts public interface IHasZoomRoomLayouts : IHasCodecLayouts
{ {
event EventHandler<LayoutInfoChangedEventArgs> AvailableLayoutsChanged; event EventHandler<LayoutInfoChangedEventArgs> LayoutInfoChanged;
BoolFeedback LayoutViewIsOnFirstPageFeedback { get; } // TODO: #697 [*] Consider modifying to report button visibility in func BoolFeedback LayoutViewIsOnFirstPageFeedback { get; } // TODO: #697 [*] Consider modifying to report button visibility in func
BoolFeedback LayoutViewIsOnLastPageFeedback { get; } // TODO: #697 [*] Consider modifying to report button visibility in func BoolFeedback LayoutViewIsOnLastPageFeedback { get; } // TODO: #697 [*] Consider modifying to report button visibility in func
@ -45,6 +47,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
public class LayoutInfoChangedEventArgs : EventArgs public class LayoutInfoChangedEventArgs : EventArgs
{ {
[JsonProperty("availableLayouts", NullValueHandling = NullValueHandling.Ignore)]
public ZoomRoom.zConfiguration.eLayoutStyle AvailableLayouts { get; set; } public ZoomRoom.zConfiguration.eLayoutStyle AvailableLayouts { get; set; }
[JsonProperty("currentSelectedLayout", NullValueHandling = NullValueHandling.Ignore)]
public ZoomRoom.zConfiguration.eLayoutStyle CurrentSelectedLayout { get; set; }
[JsonProperty("canSwapContentWithThumbnail", NullValueHandling = NullValueHandling.Ignore)]
public bool CanSwapContentWithThumbnail { get; set; }
[JsonProperty("contentSwappedWithThumbnail", NullValueHandling = NullValueHandling.Ignore)]
public bool ContentSwappedWithThumbnail { get; set; }
[JsonProperty("layoutViewIsOnFirstPage", NullValueHandling = NullValueHandling.Ignore)]
public bool LayoutViewIsOnFirstPage { get; set; }
[JsonProperty("layoutViewIsOnLastPage", NullValueHandling = NullValueHandling.Ignore)]
public bool LayoutViewIsOnLastPage { get; set; }
} }
} }

View file

@ -24,24 +24,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
/// </summary> /// </summary>
public class MeetingInfo public class MeetingInfo
{ {
[JsonProperty("id")] [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)]
public string Id { get; private set; } public string Id { get; private set; }
[JsonProperty("name")] [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
public string Name { get; private set; } public string Name { get; private set; }
[JsonProperty("host")] [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)]
public string Host { get; private set; } public string Host { get; private set; }
[JsonProperty("password")] [JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)]
public string Password { get; private set; } public string Password { get; private set; }
[JsonProperty("shareStatus")] [JsonProperty("shareStatus", NullValueHandling = NullValueHandling.Ignore)]
public string ShareStatus { get; private set; } public string ShareStatus { get; private set; }
[JsonProperty("isHost")] [JsonProperty("isHost", NullValueHandling = NullValueHandling.Ignore)]
public Boolean IsHost { get; private set; } public Boolean IsHost { get; private set; }
[JsonProperty("isSharingMeeting")] [JsonProperty("isSharingMeeting", NullValueHandling = NullValueHandling.Ignore)]
public Boolean IsSharingMeeting { get; private set; } public Boolean IsSharingMeeting { get; private set; }
[JsonProperty("waitingForHost")] [JsonProperty("waitingForHost", NullValueHandling = NullValueHandling.Ignore)]
public Boolean WaitingForHost { get; private set; } public Boolean WaitingForHost { get; private set; }
[JsonProperty("isLocked", NullValueHandling = NullValueHandling.Ignore)]
public Boolean IsLocked { get; private set; }
public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost, bool isSharingMeeting, bool waitingForHost)
public MeetingInfo(string id, string name, string host, string password, string shareStatus, bool isHost, bool isSharingMeeting, bool waitingForHost, bool isLocked)
{ {
Id = id; Id = id;
Name = name; Name = name;
@ -51,6 +54,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
IsHost = isHost; IsHost = isHost;
IsSharingMeeting = isSharingMeeting; IsSharingMeeting = isSharingMeeting;
WaitingForHost = waitingForHost; WaitingForHost = waitingForHost;
IsLocked = isLocked;
} }
} }

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
public interface IHasMeetingLock
{
BoolFeedback MeetingIsLockedFeedback { get; }
void LockMeeting();
void UnLockMeeting();
void ToggleMeetingLock();
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
{
public interface IHasMeetingRecording
{
BoolFeedback MeetingIsRecordingFeedback { get; }
void StartRecording();
void StopRecording();
void ToggleRecording();
}
}

View file

@ -12,6 +12,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
public interface IHasParticipants public interface IHasParticipants
{ {
CodecParticipants Participants { get; } CodecParticipants Participants { get; }
/// <summary>
/// Removes the participant from the meeting
/// </summary>
/// <param name="participant"></param>
void RemoveParticipant(int userId);
/// <summary>
/// Sets the participant as the new host
/// </summary>
/// <param name="participant"></param>
void SetParticipantAsHost(int userId);
} }
/// <summary> /// <summary>
@ -29,6 +41,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces
/// </summary> /// </summary>
public interface IHasParticipantAudioMute : IHasParticipantVideoMute public interface IHasParticipantAudioMute : IHasParticipantVideoMute
{ {
/// <summary>
/// Mute audio of all participants
/// </summary>
void MuteAudioForAllParticipants();
void MuteAudioForParticipant(int userId); void MuteAudioForParticipant(int userId);
void UnmuteAudioForParticipant(int userId); void UnmuteAudioForParticipant(int userId);
void ToggleAudioForParticipant(int userId); void ToggleAudioForParticipant(int userId);

View file

@ -4,6 +4,8 @@ using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Devices.Common.Codec namespace PepperDash.Essentials.Devices.Common.Codec
{ {
/// <summary> /// <summary>
@ -19,12 +21,19 @@ namespace PepperDash.Essentials.Devices.Common.Codec
/// </summary> /// </summary>
public abstract class VideoCodecInfo public abstract class VideoCodecInfo
{ {
[JsonProperty("multiSiteOptionIsEnabled", NullValueHandling = NullValueHandling.Ignore)]
public abstract bool MultiSiteOptionIsEnabled { get; } public abstract bool MultiSiteOptionIsEnabled { get; }
[JsonProperty("ipAddress", NullValueHandling = NullValueHandling.Ignore)]
public abstract string IpAddress { get; } public abstract string IpAddress { get; }
[JsonProperty("sipPhoneNumber", NullValueHandling = NullValueHandling.Ignore)]
public abstract string SipPhoneNumber { get; } public abstract string SipPhoneNumber { get; }
[JsonProperty("e164Alias", NullValueHandling = NullValueHandling.Ignore)]
public abstract string E164Alias { get; } public abstract string E164Alias { get; }
[JsonProperty("h323Id", NullValueHandling = NullValueHandling.Ignore)]
public abstract string H323Id { get; } public abstract string H323Id { get; }
[JsonProperty("sipUri", NullValueHandling = NullValueHandling.Ignore)]
public abstract string SipUri { get; } public abstract string SipUri { get; }
[JsonProperty("autoAnswerEnabled", NullValueHandling = NullValueHandling.Ignore)]
public abstract bool AutoAnswerEnabled { get; } public abstract bool AutoAnswerEnabled { get; }
} }
} }

View file

@ -41,6 +41,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
SharingSourceFeedback = new StringFeedback(SharingSourceFeedbackFunc); SharingSourceFeedback = new StringFeedback(SharingSourceFeedbackFunc);
SharingContentIsOnFeedback = new BoolFeedback(SharingContentIsOnFeedbackFunc); SharingContentIsOnFeedback = new BoolFeedback(SharingContentIsOnFeedbackFunc);
// TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set
MeetingsToDisplayFeedback = new IntFeedback(() => MeetingsToDisplay);
InputPorts = new RoutingPortCollection<RoutingInputPort>(); InputPorts = new RoutingPortCollection<RoutingInputPort>();
OutputPorts = new RoutingPortCollection<RoutingOutputPort>(); OutputPorts = new RoutingPortCollection<RoutingOutputPort>();
@ -298,6 +301,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
} }
LinkVideoCodecToApi(codec, trilist, joinMap); LinkVideoCodecToApi(codec, trilist, joinMap);
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
};
} }
/// <summary> /// <summary>
@ -546,6 +554,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec
UpdateParticipantsXSig(codec, trilist, joinMap); UpdateParticipantsXSig(codec, trilist, joinMap);
}; };
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
// TODO [ ] Issue #868
trilist.SetString(joinMap.CurrentParticipants.JoinNumber, "\xFC");
UpdateParticipantsXSig(codec, trilist, joinMap);
};
} }
private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) private void UpdateParticipantsXSig(IHasParticipants codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
@ -777,7 +794,22 @@ ScreenIndexIsPinnedTo: {8} (a{17})
UpdateMeetingsList(codec, trilist, joinMap); UpdateMeetingsList(codec, trilist, joinMap);
} }
}; };
}
// TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set
trilist.SetUShortSigAction(joinMap.MeetingsToDisplay.JoinNumber, m => MeetingsToDisplay = m);
MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]);
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
// TODO [ ] Issue #868
trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC");
UpdateMeetingsList(codec, trilist, joinMap);
// TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set
MeetingsToDisplayFeedback.LinkInputSig(trilist.UShortInput[joinMap.MeetingsToDisplay.JoinNumber]);
};
}
private void UpdateMeetingsList(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap) private void UpdateMeetingsList(IHasScheduleAwareness codec, BasicTriList trilist, VideoCodecControllerJoinMap joinMap)
{ {
@ -785,22 +817,58 @@ ScreenIndexIsPinnedTo: {8} (a{17})
_currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList(); _currentMeetings = codec.CodecSchedule.Meetings.Where(m => m.StartTime >= currentTime || m.EndTime >= currentTime).ToList();
if (_currentMeetings.Count == 0)
{
var emptyXSigByteArray = XSigHelpers.ClearOutputs();
var emptyXSigString = Encoding.GetEncoding(XSigEncoding)
.GetString(emptyXSigByteArray, 0, emptyXSigByteArray.Length);
trilist.SetString(joinMap.Schedule.JoinNumber, emptyXSigString);
return;
}
var meetingsData = UpdateMeetingsListXSig(_currentMeetings); var meetingsData = UpdateMeetingsListXSig(_currentMeetings);
trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData); trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData);
trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)_currentMeetings.Count); trilist.SetUshort(joinMap.MeetingCount.JoinNumber, (ushort)_currentMeetings.Count);
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
// TODO [ ] Issue #868
trilist.SetString(joinMap.Schedule.JoinNumber, "\xFC");
UpdateMeetingsListXSig(_currentMeetings);
};
} }
// TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set
private int _meetingsToDisplay = 3;
// TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set
protected int MeetingsToDisplay
{
get { return _meetingsToDisplay; }
set {
_meetingsToDisplay = (ushort) (value == 0 ? 3 : value);
MeetingsToDisplayFeedback.FireUpdate();
}
}
// TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set
public IntFeedback MeetingsToDisplayFeedback { get; set; }
private string UpdateMeetingsListXSig(List<Meeting> meetings) private string UpdateMeetingsListXSig(List<Meeting> meetings)
{ {
const int maxMeetings = 3; // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set
//const int _meetingsToDisplay = 3;
const int maxDigitals = 2; const int maxDigitals = 2;
const int maxStrings = 7; const int maxStrings = 7;
const int offset = maxDigitals + maxStrings; const int offset = maxDigitals + maxStrings;
var digitalIndex = maxStrings * maxMeetings; //15 var digitalIndex = maxStrings * _meetingsToDisplay; //15
var stringIndex = 0; var stringIndex = 0;
var meetingIndex = 0; var meetingIndex = 0;
var tokenArray = new XSigToken[maxMeetings * offset]; var tokenArray = new XSigToken[_meetingsToDisplay * offset];
/* /*
* Digitals * Digitals
* IsJoinable - 1 * IsJoinable - 1
@ -823,7 +891,7 @@ ScreenIndexIsPinnedTo: {8} (a{17})
if (meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue; if (meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue;
if (meetingIndex >= maxMeetings * offset) if (meetingIndex >= _meetingsToDisplay * offset)
{ {
Debug.Console(2, this, "Max Meetings reached"); Debug.Console(2, this, "Max Meetings reached");
break; break;
@ -848,10 +916,10 @@ ScreenIndexIsPinnedTo: {8} (a{17})
stringIndex += maxStrings; stringIndex += maxStrings;
} }
while (meetingIndex < maxMeetings * offset) while (meetingIndex < _meetingsToDisplay * offset)
{ {
Debug.Console(2, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}", Debug.Console(2, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}",
meetingIndex, maxMeetings * offset); meetingIndex, _meetingsToDisplay * offset);
//digitals //digitals
tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false);
@ -901,6 +969,16 @@ ScreenIndexIsPinnedTo: {8} (a{17})
trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig); trilist.SetString(joinMap.DirectoryEntries.JoinNumber, directoryXSig);
}; };
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
// TODO [ ] Issue #868
trilist.SetString(joinMap.DirectoryEntries.JoinNumber, "\xFC");
UpdateDirectoryXSig(codec.CurrentDirectoryResult,
!codec.CurrentDirectoryResultIsNotDirectoryRoot.BoolValue);
};
} }
private void SelectDirectoryEntry(IHasDirectory codec, ushort i) private void SelectDirectoryEntry(IHasDirectory codec, ushort i)
@ -982,6 +1060,15 @@ ScreenIndexIsPinnedTo: {8} (a{17})
trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig()); trilist.SetString(joinMap.CurrentCallData.JoinNumber, UpdateCallStatusXSig());
}; };
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
// TODO [ ] Issue #868
trilist.SetString(joinMap.CurrentCallData.JoinNumber, "\xFC");
UpdateCallStatusXSig();
};
} }
private string UpdateCallStatusXSig() private string UpdateCallStatusXSig()
@ -1249,6 +1336,15 @@ ScreenIndexIsPinnedTo: {8} (a{17})
trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, String.Empty); trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, String.Empty);
trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000); trilist.PulseBool(joinMap.CameraPresetSave.JoinNumber, 3000);
}); });
trilist.OnlineStatusChange += (device, args) =>
{
if (!args.DeviceOnLine) return;
// TODO [ ] Issue #868
trilist.SetString(joinMap.CameraPresetNames.JoinNumber, "\xFC");
SetCameraPresetNames(presetCodec.NearEndPresets);
};
} }
private string SetCameraPresetNames(IEnumerable<CodecRoomPreset> presets) private string SetCameraPresetNames(IEnumerable<CodecRoomPreset> presets)

View file

@ -618,13 +618,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
private bool _can_Switch_Speaker_View; private bool _can_Switch_Speaker_View;
private bool _can_Switch_Wall_View; private bool _can_Switch_Wall_View;
private bool _can_Switch_Share_On_All_Screens; private bool _can_Switch_Share_On_All_Screens;
private bool _can_Switch_Floating_Share_Content;
private bool _is_In_First_Page; private bool _is_In_First_Page;
private bool _is_In_Last_Page; private bool _is_In_Last_Page;
private string _video_type; private string _video_type;
public bool can_Adjust_Floating_Video { get; set; } public bool can_Adjust_Floating_Video { get; set; }
public bool can_Switch_Floating_Share_Content { get; set; }
public bool can_Switch_Floating_Share_Content
{
get
{
return _can_Switch_Floating_Share_Content;
}
set
{
if (value != _can_Switch_Floating_Share_Content)
{
_can_Switch_Floating_Share_Content = value;
NotifyPropertyChanged("can_Switch_Floating_Share_Content");
}
}
}
/// <summary> /// <summary>
/// [on/off] // Set to On if it is possible to invoke zConfiguration Call Layout Style: ShareAll, to switch to the ShareAll mode, where the content sharing is shown full screen on all monitors. /// [on/off] // Set to On if it is possible to invoke zConfiguration Call Layout Style: ShareAll, to switch to the ShareAll mode, where the content sharing is shown full screen on all monitors.
@ -744,12 +762,29 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
} }
public class CallRecordInfo public class CallRecordInfo : NotifiableObject
{ {
private bool _meetingIsBeingRecorded;
public bool canRecord { get; set; } public bool canRecord { get; set; }
public bool emailRequired { get; set; } public bool emailRequired { get; set; }
public bool amIRecording { get; set; } public bool amIRecording { get; set; }
public bool meetingIsBeingRecorded { get; set; }
public bool meetingIsBeingRecorded
{
get
{
return _meetingIsBeingRecorded;
}
set
{
if (value != _meetingIsBeingRecorded)
{
_meetingIsBeingRecorded = value;
NotifyPropertyChanged("meetingIsBeingRecorded");
}
}
}
} }
} }
@ -1123,9 +1158,25 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
} }
public class Lock public class Lock : NotifiableObject
{ {
public bool Enable { get; set; } private bool _enable;
public bool Enable
{
get
{
return _enable;
}
set
{
if (value != _enable)
{
_enable = value;
NotifyPropertyChanged("Enable");
}
}
}
} }
public class ClosedCaption public class ClosedCaption

View file

@ -26,7 +26,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
IRouting, IRouting,
IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode, IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode,
IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin, IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin,
IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo, IHasPresentationOnlyMeeting IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo, IHasPresentationOnlyMeeting,
IHasMeetingLock, IHasMeetingRecording
{ {
private const long MeetingRefreshTimer = 60000; private const long MeetingRefreshTimer = 60000;
public uint DefaultMeetingDurationMin { get; private set; } public uint DefaultMeetingDurationMin { get; private set; }
@ -147,6 +148,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
ContentSwappedWithThumbnailFeedback = new BoolFeedback(ContentSwappedWithThumbnailFeedbackFunc); ContentSwappedWithThumbnailFeedback = new BoolFeedback(ContentSwappedWithThumbnailFeedbackFunc);
NumberOfScreensFeedback = new IntFeedback(NumberOfScreensFeedbackFunc); NumberOfScreensFeedback = new IntFeedback(NumberOfScreensFeedbackFunc);
MeetingIsLockedFeedback = new BoolFeedback(() => Configuration.Call.Lock.Enable );
MeetingIsRecordingFeedback = new BoolFeedback(() => Status.Call.CallRecordInfo.meetingIsBeingRecorded );
} }
public CommunicationGather PortGather { get; private set; } public CommunicationGather PortGather { get; private set; }
@ -499,19 +504,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{ {
var sharingStatus = GetSharingStatus(); var sharingStatus = GetSharingStatus();
MeetingInfo = new MeetingInfo("", "", "", "", sharingStatus, GetIsHostMyself(), true, false); MeetingInfo = new MeetingInfo("", "", "", "", sharingStatus, GetIsHostMyself(), true, false, MeetingIsLockedFeedback.BoolValue);
return; return;
} }
var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, Participants.Host != null ? Participants.Host.Name : "None", var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, Participants.Host != null ? Participants.Host.Name : "None",
MeetingInfo.Password, GetSharingStatus(), GetIsHostMyself(), MeetingInfo.IsSharingMeeting, MeetingInfo.WaitingForHost); MeetingInfo.Password, GetSharingStatus(), GetIsHostMyself(), MeetingInfo.IsSharingMeeting, MeetingInfo.WaitingForHost, MeetingIsLockedFeedback.BoolValue);
MeetingInfo = meetingInfo; MeetingInfo = meetingInfo;
} }
catch (Exception e) catch (Exception e)
{ {
Debug.Console(1, this, "Error processing state property update. {0}", e.Message); Debug.Console(1, this, "Error processing state property update. {0}", e.Message);
Debug.Console(2, this, e.StackTrace); Debug.Console(2, this, e.StackTrace);
MeetingInfo = new MeetingInfo("", "", "", "", "None", false, false, false); MeetingInfo = new MeetingInfo("", "", "", "", "None", false, false, false, MeetingIsLockedFeedback.BoolValue);
} }
} }
@ -578,11 +583,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
case "ShareThumb": case "ShareThumb":
{ {
ContentSwappedWithThumbnailFeedback.FireUpdate(); ContentSwappedWithThumbnailFeedback.FireUpdate();
OnLayoutInfoChanged();
break; break;
} }
case "Style": case "Style":
{ {
LocalLayoutFeedback.FireUpdate(); LocalLayoutFeedback.FireUpdate();
OnLayoutInfoChanged();
break; break;
} }
case "Size": case "Size":
@ -597,6 +604,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
}; };
Configuration.Call.Lock.PropertyChanged += (o, a) =>
{
if (a.PropertyName == "Enable")
{
MeetingIsLockedFeedback.FireUpdate();
MeetingInfo = new MeetingInfo
(
MeetingInfo.Id,
MeetingInfo.Name,
MeetingInfo.Host,
MeetingInfo.Password,
GetSharingStatus(),
MeetingInfo.IsHost,
MeetingInfo.IsSharingMeeting,
MeetingInfo.WaitingForHost,
MeetingIsLockedFeedback.BoolValue
);
}
};
// This is to deal with incorrect object structure coming back from the Zoom Room on v 5.6.3 // This is to deal with incorrect object structure coming back from the Zoom Room on v 5.6.3
Configuration.Client.Call.Layout.PropertyChanged += (o, a) => Configuration.Client.Call.Layout.PropertyChanged += (o, a) =>
{ {
@ -613,11 +640,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
case "ShareThumb": case "ShareThumb":
{ {
ContentSwappedWithThumbnailFeedback.FireUpdate(); ContentSwappedWithThumbnailFeedback.FireUpdate();
OnLayoutInfoChanged();
break; break;
} }
case "Style": case "Style":
{ {
LocalLayoutFeedback.FireUpdate(); LocalLayoutFeedback.FireUpdate();
OnLayoutInfoChanged();
break; break;
} }
} }
@ -634,13 +663,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Status.Call.PropertyChanged += (o, a) => Status.Call.PropertyChanged += (o, a) =>
{ {
if (a.PropertyName == "Info") switch(a.PropertyName)
{
case "Info":
{ {
Debug.Console(1, this, "Updating Call Status"); Debug.Console(1, this, "Updating Call Status");
UpdateCallStatus(); UpdateCallStatus();
break;
} }
case "Status":
{
UpdateCallStatus();
break;
}
}
}; };
Status.Call.CallRecordInfo.PropertyChanged += (o, a) =>
{
if (a.PropertyName == "meetingIsBeingRecorded")
{
MeetingIsRecordingFeedback.FireUpdate();
}
};
Status.Sharing.PropertyChanged += (o, a) => Status.Sharing.PropertyChanged += (o, a) =>
{ {
switch (a.PropertyName) switch (a.PropertyName)
@ -663,7 +710,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
return; return;
} }
// Update the share status of the meeting info // Update the share status of the meeting info
var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, MeetingInfo.Host, MeetingInfo.Password, GetSharingStatus(), GetIsHostMyself(), MeetingInfo.IsSharingMeeting, MeetingInfo.WaitingForHost); var meetingInfo = new MeetingInfo(MeetingInfo.Id,
MeetingInfo.Name,
MeetingInfo.Host,
MeetingInfo.Password,
GetSharingStatus(),
GetIsHostMyself(),
MeetingInfo.IsSharingMeeting,
MeetingInfo.WaitingForHost,
MeetingIsLockedFeedback.BoolValue);
MeetingInfo = meetingInfo; MeetingInfo = meetingInfo;
break; break;
} }
@ -714,13 +769,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
LayoutViewIsOnLastPageFeedback.FireUpdate(); LayoutViewIsOnLastPageFeedback.FireUpdate();
break; break;
} }
//case "video_type": case "can_Switch_Floating_Share_Content":
// { {
// It appears as though the actual value we want to watch is Configuration.Call.Layout.Style CanSwapContentWithThumbnailFeedback.FireUpdate();
// LocalLayoutFeedback.FireUpdate(); break;
// break; }
// }
} }
OnLayoutInfoChanged();
}; };
Status.NumberOfScreens.PropertyChanged += (o, a) => Status.NumberOfScreens.PropertyChanged += (o, a) =>
@ -1244,7 +1299,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Participants.CurrentParticipants = participants; Participants.CurrentParticipants = participants;
// Update the share status of the meeting info // Update the share status of the meeting info
var meetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, Participants.Host.Name, MeetingInfo.Password, MeetingInfo.ShareStatus, GetIsHostMyself(), MeetingInfo.IsSharingMeeting, MeetingInfo.WaitingForHost); var meetingInfo = new MeetingInfo(
MeetingInfo.Id,
MeetingInfo.Name,
Participants.Host.Name,
MeetingInfo.Password,
MeetingInfo.ShareStatus,
GetIsHostMyself(),
MeetingInfo.IsSharingMeeting,
MeetingInfo.WaitingForHost,
MeetingIsLockedFeedback.BoolValue);
MeetingInfo = meetingInfo; MeetingInfo = meetingInfo;
PrintCurrentCallParticipants(); PrintCurrentCallParticipants();
@ -1306,11 +1370,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
var codecBookings = JsonConvert.DeserializeObject<List<zCommand.BookingsListResult>>( var codecBookings = JsonConvert.DeserializeObject<List<zCommand.BookingsListResult>>(
responseObj.ToString()); responseObj.ToString());
if (codecBookings != null && codecBookings.Count > 0) if (codecBookings != null && codecBookings.Count > 0)
{ {
CodecSchedule.Meetings = zCommand.GetGenericMeetingsFromBookingResult( CodecSchedule.Meetings = zCommand.GetGenericMeetingsFromBookingResult(
codecBookings, CodecSchedule.MeetingWarningMinutes); codecBookings, CodecSchedule.MeetingWarningMinutes);
} }
else
{
//need to clear the list if it's empty
CodecSchedule.Meetings = new List<Meeting>();
}
break; break;
} }
@ -1441,21 +1510,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{ {
Status.NeedWaitForHost = JsonConvert.DeserializeObject<zEvent.NeedWaitForHost>(responseObj.ToString()); Status.NeedWaitForHost = JsonConvert.DeserializeObject<zEvent.NeedWaitForHost>(responseObj.ToString());
Debug.Console(1, this, "NeedWaitForHost: {0}", Status.NeedWaitForHost.Wait); Debug.Console(1, this, "WaitingForHost: {0}", Status.NeedWaitForHost.Wait);
if (Status.NeedWaitForHost.Wait) if (Status.NeedWaitForHost.Wait)
{ {
if (MeetingInfo == null) if (MeetingInfo == null)
{ {
MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "", MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "",
GetSharingStatus(), false, false, true); GetSharingStatus(), false, false, true, MeetingIsLockedFeedback.BoolValue);
UpdateCallStatus(); UpdateCallStatus();
break; break;
} }
MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "", MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "",
GetSharingStatus(), false, false, true); GetSharingStatus(), false, false, true, MeetingIsLockedFeedback.BoolValue);
UpdateCallStatus(); UpdateCallStatus();
@ -1465,12 +1534,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
if (MeetingInfo == null) if (MeetingInfo == null)
{ {
MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "", MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "",
GetSharingStatus(), false, false, false); GetSharingStatus(), false, false, false, MeetingIsLockedFeedback.BoolValue);
break; break;
} }
MeetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, MeetingInfo.Host, MeetingInfo.Password, MeetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, MeetingInfo.Host, MeetingInfo.Password,
GetSharingStatus(), GetIsHostMyself(), false, false); GetSharingStatus(), GetIsHostMyself(), false, false, MeetingIsLockedFeedback.BoolValue);
break; break;
} }
@ -1554,7 +1623,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
if (result.Success) if (result.Success)
{ {
MeetingInfo = new MeetingInfo("", "", "", "", "", true, true, MeetingInfo.WaitingForHost); MeetingInfo = new MeetingInfo("", "", "", "", "", true, true, MeetingInfo.WaitingForHost, MeetingIsLockedFeedback.BoolValue);
break; break;
} }
@ -1899,6 +1968,22 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
GetSharingStatus(), GetSharingStatus(),
GetIsHostMyself(), GetIsHostMyself(),
!String.Equals(Status.Call.Info.meeting_type,"NORMAL"), !String.Equals(Status.Call.Info.meeting_type,"NORMAL"),
false,
MeetingIsLockedFeedback.BoolValue
);
}
// TODO [ ] Issue #868
else if (item.Status == eCodecCallStatus.Disconnected)
{
MeetingInfo = new MeetingInfo(
string.Empty,
string.Empty,
string.Empty,
string.Empty,
string.Empty,
false,
false,
false,
false false
); );
} }
@ -2127,16 +2212,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
var layoutsCodec = this as IHasZoomRoomLayouts; var layoutsCodec = this as IHasZoomRoomLayouts;
if (layoutsCodec != null) if (layoutsCodec != null)
{ {
layoutsCodec.AvailableLayoutsChanged += (o, a) => layoutsCodec.LayoutInfoChanged += (o, a) =>
{ {
trilist.SetBool(joinMap.LayoutGalleryIsAvailable.JoinNumber, zConfiguration.eLayoutStyle.Gallery trilist.SetBool(joinMap.LayoutGalleryIsAvailable.JoinNumber,
== zConfiguration.eLayoutStyle.Gallery == (a.AvailableLayouts & zConfiguration.eLayoutStyle.Gallery));
(a.AvailableLayouts &
zConfiguration.eLayoutStyle.Gallery)); trilist.SetBool(joinMap.LayoutSpeakerIsAvailable.JoinNumber,
trilist.SetBool(joinMap.LayoutSpeakerIsAvailable.JoinNumber, zConfiguration.eLayoutStyle.Speaker zConfiguration.eLayoutStyle.Speaker == (a.AvailableLayouts & zConfiguration.eLayoutStyle.Speaker));
==
(a.AvailableLayouts &
zConfiguration.eLayoutStyle.Speaker));
trilist.SetBool(joinMap.LayoutStripIsAvailable.JoinNumber, zConfiguration.eLayoutStyle.Strip trilist.SetBool(joinMap.LayoutStripIsAvailable.JoinNumber, zConfiguration.eLayoutStyle.Strip
== ==
(a.AvailableLayouts & zConfiguration.eLayoutStyle.Strip)); (a.AvailableLayouts & zConfiguration.eLayoutStyle.Strip));
@ -2191,7 +2276,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
trilist.SetUShortSigAction(joinMap.ScreenIndexToPinUserTo.JoinNumber, (u) => ScreenIndexToPinUserTo = u); trilist.SetUShortSigAction(joinMap.ScreenIndexToPinUserTo.JoinNumber, (u) => ScreenIndexToPinUserTo = u);
} }
// TODO: #714 [ ] LinkZoomRoomToApi >> layoutSizeCoodec
var layoutSizeCodec = this as IHasSelfviewSize; var layoutSizeCodec = this as IHasSelfviewSize;
if (layoutSizeCodec != null) if (layoutSizeCodec != null)
{ {
@ -2213,6 +2297,75 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
layoutSizeCodec.SelfviewPipSizeFeedback.LinkInputSig(trilist.StringInput[joinMap.GetSetSelfviewPipSize.JoinNumber]); layoutSizeCodec.SelfviewPipSizeFeedback.LinkInputSig(trilist.StringInput[joinMap.GetSetSelfviewPipSize.JoinNumber]);
} }
PasswordRequired += (device, args) =>
{
if (args.LoginAttemptCancelled)
{
trilist.SetBool(joinMap.ShowPasswordPrompt.JoinNumber, false);
return;
}
if (!string.IsNullOrEmpty(args.Message))
{
trilist.SetString(joinMap.PasswordPromptMessage.JoinNumber, args.Message);
}
if (args.LoginAttemptFailed)
{
trilist.SetBool(joinMap.PasswordLoginFailed.JoinNumber, true);
return;
}
trilist.SetBool(joinMap.ShowPasswordPrompt.JoinNumber, true);
};
MeetingInfoChanged += (device, args) =>
{
trilist.SetString(joinMap.MeetingInfoId.JoinNumber, args.Info.Id);
trilist.SetString(joinMap.MeetingInfoHost.JoinNumber, args.Info.Host);
trilist.SetString(joinMap.MeetingInfoPassword.JoinNumber, args.Info.Password);
trilist.SetBool(joinMap.IsHost.JoinNumber, args.Info.IsHost);
trilist.SetBool(joinMap.ShareOnlyMeeting.JoinNumber, args.Info.IsSharingMeeting);
trilist.SetBool(joinMap.WaitingForHost.JoinNumber, args.Info.WaitingForHost);
//trilist.SetString(joinMap.CurrentSource.JoinNumber, args.Info.ShareStatus);
};
trilist.SetSigTrueAction(joinMap.StartMeetingNow.JoinNumber, () => StartMeeting(0));
trilist.SetSigTrueAction(joinMap.ShareOnlyMeeting.JoinNumber, StartSharingOnlyMeeting);
trilist.SetSigTrueAction(joinMap.StartNormalMeetingFromSharingOnlyMeeting.JoinNumber, StartNormalMeetingFromSharingOnlyMeeting);
// not sure if this would be needed here, should be handled by VideoCodecBase.cs LinkToApi methods
//DirectoryResultReturned += (device, args) =>
//{
// // add logic here if necessary when event fires
//};
trilist.SetStringSigAction(joinMap.SubmitPassword.JoinNumber, SubmitPassword);
PasswordRequired += (devices, args) =>
{
if (args.LoginAttemptCancelled)
{
trilist.SetBool(joinMap.ShowPasswordPrompt.JoinNumber, false);
return;
}
if (!string.IsNullOrEmpty(args.Message))
{
trilist.SetString(joinMap.PasswordPromptMessage.JoinNumber, args.Message);
}
if (args.LoginAttemptFailed)
{
// login attempt failed
return;
}
trilist.SetBool(joinMap.PasswordIncorrect.JoinNumber, args.LastAttemptWasIncorrect);
trilist.SetBool(joinMap.ShowPasswordPrompt.JoinNumber, true);
};
trilist.OnlineStatusChange += (device, args) => trilist.OnlineStatusChange += (device, args) =>
{ {
if (!args.DeviceOnLine) return; if (!args.DeviceOnLine) return;
@ -2329,6 +2482,56 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
} }
/// <summary>
/// Invites contacts to a new meeting for a specified duration
/// </summary>
/// <param name="contacts"></param>
/// <param name="duration"></param>
public void InviteContactsToNewMeeting(List<InvitableDirectoryContact> contacts, uint duration)
{
if(duration == 0)
{
duration = DefaultMeetingDurationMin;
}
StringBuilder message = new StringBuilder();
// Add the prefix
message.Append(string.Format("zCommand Invite Duration: {0}", duration));
// Add each invitee
foreach (var contact in contacts)
{
var invitee = string.Format(" user: {0}", contact.ContactId);
message.Append(invitee);
}
SendText(message.ToString());
}
/// <summary>
/// Invites contacts to an existing meeting
/// </summary>
/// <param name="contacts"></param>
public void InviteContactsToExistingMeeting(List<InvitableDirectoryContact> contacts)
{
StringBuilder message = new StringBuilder();
// Add the prefix
message.Append(string.Format("zCommand Call Invite"));
// Add each invitee
foreach (var contact in contacts)
{
var invitee = string.Format(" user: {0}", contact.ContactId);
message.Append(invitee);
}
SendText(message.ToString());
}
/// <summary> /// <summary>
/// Starts a PMI Meeting for the specified duration (or default meeting duration if 0 is specified) /// Starts a PMI Meeting for the specified duration (or default meeting duration if 0 is specified)
@ -2464,10 +2667,25 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
public CodecParticipants Participants { get; private set; } public CodecParticipants Participants { get; private set; }
public void RemoveParticipant(int userId)
{
SendText(string.Format("zCommand Call Expel Id: {0}", userId));
}
public void SetParticipantAsHost(int userId)
{
SendText(string.Format("zCommand Call HostChange Id: {0}", userId));
}
#endregion #endregion
#region IHasParticipantAudioMute Members #region IHasParticipantAudioMute Members
public void MuteAudioForAllParticipants()
{
SendText(string.Format("zCommand Call MuteAll Mute: on"));
}
public void MuteAudioForParticipant(int userId) public void MuteAudioForParticipant(int userId)
{ {
SendText(string.Format("zCommand Call MuteParticipant Mute: on Id: {0}", userId)); SendText(string.Format("zCommand Call MuteParticipant Mute: on Id: {0}", userId));
@ -2765,7 +2983,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
#region IHasZoomRoomLayouts Members #region IHasZoomRoomLayouts Members
public event EventHandler<LayoutInfoChangedEventArgs> AvailableLayoutsChanged; public event EventHandler<LayoutInfoChangedEventArgs> LayoutInfoChanged;
private Func<bool> LayoutViewIsOnFirstPageFeedbackFunc private Func<bool> LayoutViewIsOnFirstPageFeedbackFunc
{ {
@ -2831,15 +3049,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Debug.Console(1, this, "availablelayouts: {0}", availableLayouts); Debug.Console(1, this, "availablelayouts: {0}", availableLayouts);
var handler = AvailableLayoutsChanged;
if (handler != null)
{
handler(this, new LayoutInfoChangedEventArgs() {AvailableLayouts = availableLayouts});
}
AvailableLayouts = availableLayouts; AvailableLayouts = availableLayouts;
} }
private void OnLayoutInfoChanged()
{
var handler = LayoutInfoChanged;
if (handler != null)
{
handler(this, new LayoutInfoChangedEventArgs()
{
AvailableLayouts = AvailableLayouts,
CurrentSelectedLayout = (zConfiguration.eLayoutStyle)Enum.Parse(typeof(zConfiguration.eLayoutStyle),LocalLayoutFeedback.StringValue, true),
LayoutViewIsOnFirstPage = LayoutViewIsOnFirstPageFeedback.BoolValue,
LayoutViewIsOnLastPage = LayoutViewIsOnLastPageFeedback.BoolValue,
CanSwapContentWithThumbnail = CanSwapContentWithThumbnailFeedback.BoolValue,
ContentSwappedWithThumbnail = ContentSwappedWithThumbnailFeedback.BoolValue,
});
}
}
public void GetAvailableLayouts() public void GetAvailableLayouts()
{ {
SendText("zStatus Call Layout"); SendText("zStatus Call Layout");
@ -3029,7 +3258,63 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
} }
#endregion #endregion
}
#region IHasMeetingLock Members
public BoolFeedback MeetingIsLockedFeedback { get; private set; }
public void LockMeeting()
{
SendText(string.Format("zConfiguration Call Lock Enable: on"));
}
public void UnLockMeeting()
{
SendText(string.Format("zConfiguration Call Lock Enable: off"));
}
public void ToggleMeetingLock()
{
if (MeetingIsLockedFeedback.BoolValue)
{
UnLockMeeting();
}
else
{
LockMeeting();
}
}
#endregion
#region IHasMeetingRecording Members
public BoolFeedback MeetingIsRecordingFeedback { get; private set; }
public void StartRecording()
{
SendText(string.Format("Command Call Record Enable: on"));
}
public void StopRecording()
{
SendText(string.Format("Command Call Record Enable: off"));
}
public void ToggleRecording()
{
if (MeetingIsRecordingFeedback.BoolValue)
{
StopRecording();
}
else
{
StartRecording();
}
}
#endregion
}
/// <summary> /// <summary>
/// Zoom Room specific info object /// Zoom Room specific info object
@ -3042,8 +3327,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
Configuration = configuration; Configuration = configuration;
} }
[JsonIgnore]
public ZoomRoomStatus Status { get; private set; } public ZoomRoomStatus Status { get; private set; }
public ZoomRoomConfiguration Configuration { get; private set; } [JsonIgnore]
public ZoomRoomConfiguration Configuration { get; private set; }
public override bool AutoAnswerEnabled public override bool AutoAnswerEnabled
{ {

View file

@ -1,301 +1,496 @@
using System; using System;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Bridges.JoinMaps; using PepperDash.Essentials.Core.Bridges.JoinMaps;
namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom
{ {
public class ZoomRoomJoinMap : VideoCodecControllerJoinMap public class ZoomRoomJoinMap : VideoCodecControllerJoinMap
{ {
#region Digital #region Digital
[JoinName("CanSwapContentWithThumbnail")] // TODO [ ] Issue #868
public JoinDataComplete CanSwapContentWithThumbnail = new JoinDataComplete( [JoinName("ShowPasswordPrompt")]
new JoinData public JoinDataComplete ShowPasswordPrompt = new JoinDataComplete(
{ new JoinData
JoinNumber = 206, {
JoinSpan = 1 JoinNumber = 6,
}, JoinSpan = 1
new JoinMetadata },
{ new JoinMetadata
Description = "FB Indicates if content can be swapped with thumbnail", {
JoinCapabilities = eJoinCapabilities.ToSIMPL, Description = "FB Indicates to show the password prompt",
JoinType = eJoinType.Digital JoinCapabilities = eJoinCapabilities.ToSIMPL,
}); JoinType = eJoinType.Digital
});
[JoinName("SwapContentWithThumbnail")]
public JoinDataComplete SwapContentWithThumbnail = new JoinDataComplete( // TODO [ ] Issue #868
new JoinData [JoinName("PasswordIncorrect")]
{ public JoinDataComplete PasswordIncorrect = new JoinDataComplete(
JoinNumber = 206, new JoinData
JoinSpan = 1 {
}, JoinNumber = 7,
new JoinMetadata JoinSpan = 1
{ },
Description = "Pulse to swap content with thumbnail. FB reports current state", new JoinMetadata
JoinCapabilities = eJoinCapabilities.ToFromSIMPL, {
JoinType = eJoinType.Digital Description = "FB Indicates the password entered is incorrect",
}); JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Digital
[JoinName("GetAvailableLayouts")] });
public JoinDataComplete GetAvailableLayouts = new JoinDataComplete(
new JoinData // TODO [ ] Issue #868
{ [JoinName("PassowrdLoginFailed")]
JoinNumber = 215, public JoinDataComplete PasswordLoginFailed = new JoinDataComplete(
JoinSpan = 1 new JoinData
}, {
new JoinMetadata JoinNumber = 8,
{ JoinSpan = 1
Description = "Gets the available layouts. Will update the LayoutXXXXXIsAvailbale signals.", },
JoinCapabilities = eJoinCapabilities.FromSIMPL, new JoinMetadata
JoinType = eJoinType.Digital {
}); Description = "FB Indicates the password entered is incorrect",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
[JoinName("LayoutIsOnFirstPage")] JoinType = eJoinType.Digital
public JoinDataComplete LayoutIsOnFirstPage = new JoinDataComplete( });
new JoinData
{ // TODO [ ] Issue #868
JoinNumber = 216, [JoinName("WaitingForHost")]
JoinSpan = 1 public JoinDataComplete WaitingForHost = new JoinDataComplete(
}, new JoinData
new JoinMetadata {
{ JoinNumber = 9,
Description = "Indicates if layout is on first page", JoinSpan = 1
JoinCapabilities = eJoinCapabilities.ToSIMPL, },
JoinType = eJoinType.Digital new JoinMetadata
}); {
Description = "FB Indicates system is waiting for host",
[JoinName("LayoutIsOnLastPage")] JoinCapabilities = eJoinCapabilities.ToSIMPL,
public JoinDataComplete LayoutIsOnLastPage = new JoinDataComplete( JoinType = eJoinType.Digital
new JoinData });
{
JoinNumber = 217, // TODO [ ] Issue #868
JoinSpan = 1 [JoinName("IsHost")]
}, public JoinDataComplete IsHost = new JoinDataComplete(
new JoinMetadata new JoinData
{ {
Description = "Indicates if layout is on first page", JoinNumber = 10,
JoinCapabilities = eJoinCapabilities.ToSIMPL, JoinSpan = 1
JoinType = eJoinType.Digital },
}); new JoinMetadata
{
[JoinName("LayoutTurnToNextPage")] Description = "FB Indicates system is the host",
public JoinDataComplete LayoutTurnToNextPage = new JoinDataComplete( JoinCapabilities = eJoinCapabilities.ToSIMPL,
new JoinData JoinType = eJoinType.Digital
{ });
JoinNumber = 216,
JoinSpan = 1 // TODO [ ] Issue #868
}, [JoinName("StartMeetingNow")]
new JoinMetadata public JoinDataComplete StartMeetingNow = new JoinDataComplete(
{ new JoinData
Description = "Turns layout view to next page", {
JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinNumber = 25,
JoinType = eJoinType.Digital JoinSpan = 1
}); },
new JoinMetadata
[JoinName("LayoutTurnToPreviousPage")] {
public JoinDataComplete LayoutTurnToPreviousPage = new JoinDataComplete( Description = "FB Indicates the password prompt is active",
new JoinData JoinCapabilities = eJoinCapabilities.FromSIMPL,
{ JoinType = eJoinType.Digital
JoinNumber = 217, });
JoinSpan = 1
}, // TODO [ ] Issue #868
new JoinMetadata [JoinName("ShareOnlyMeeting")]
{ public JoinDataComplete ShareOnlyMeeting = new JoinDataComplete(
Description = "Turns layout view to previous page", new JoinData
JoinCapabilities = eJoinCapabilities.FromSIMPL, {
JoinType = eJoinType.Digital JoinNumber = 26,
}); JoinSpan = 1
},
[JoinName("LayoutGalleryIsAvailable")] new JoinMetadata
public JoinDataComplete LayoutGalleryIsAvailable = new JoinDataComplete( {
new JoinData Description = "Triggers a share only meeting, feedback indicates the current meeting is share only",
{ JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinNumber = 221, JoinType = eJoinType.Digital
JoinSpan = 1 });
},
new JoinMetadata // TODO [ ] Issue #868
{ [JoinName("StartNormalMeetingFromSharingOnlyMeeting")]
Description = "FB Indicates if layout 'Gallery' is available", public JoinDataComplete StartNormalMeetingFromSharingOnlyMeeting = new JoinDataComplete(
JoinCapabilities = eJoinCapabilities.ToSIMPL, new JoinData
JoinType = eJoinType.DigitalSerial {
}); JoinNumber = 27,
JoinSpan = 1
[JoinName("LayoutSpeakerIsAvailable")] },
public JoinDataComplete LayoutSpeakerIsAvailable = new JoinDataComplete( new JoinMetadata
new JoinData {
{ Description = "Starts a normal meeting from a share only meeting",
JoinNumber = 222, JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinSpan = 1 JoinType = eJoinType.Digital
}, });
new JoinMetadata
{ [JoinName("CanSwapContentWithThumbnail")]
Description = "FB Indicates if layout 'Speaker' is available", public JoinDataComplete CanSwapContentWithThumbnail = new JoinDataComplete(
JoinCapabilities = eJoinCapabilities.ToSIMPL, new JoinData
JoinType = eJoinType.DigitalSerial {
}); JoinNumber = 206,
JoinSpan = 1
[JoinName("LayoutStripIsAvailable")] },
public JoinDataComplete LayoutStripIsAvailable = new JoinDataComplete( new JoinMetadata
new JoinData {
{ Description = "FB Indicates if content can be swapped with thumbnail",
JoinNumber = 223, JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinSpan = 1 JoinType = eJoinType.Digital
}, });
new JoinMetadata
{ [JoinName("SwapContentWithThumbnail")]
Description = "FB Indicates if layout 'Strip' is available", public JoinDataComplete SwapContentWithThumbnail = new JoinDataComplete(
JoinCapabilities = eJoinCapabilities.ToSIMPL, new JoinData
JoinType = eJoinType.DigitalSerial {
}); JoinNumber = 206,
JoinSpan = 1
[JoinName("LayoutShareAllIsAvailable")] },
public JoinDataComplete LayoutShareAllIsAvailable = new JoinDataComplete( new JoinMetadata
new JoinData {
{ Description = "Pulse to swap content with thumbnail. FB reports current state",
JoinNumber = 224, JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinSpan = 1 JoinType = eJoinType.Digital
}, });
new JoinMetadata
{ [JoinName("GetAvailableLayouts")]
Description = "FB Indicates if layout 'ShareAll' is available", public JoinDataComplete GetAvailableLayouts = new JoinDataComplete(
JoinCapabilities = eJoinCapabilities.ToSIMPL, new JoinData
JoinType = eJoinType.DigitalSerial {
}); JoinNumber = 215,
JoinSpan = 1
// TODO: #714 [ ] JoinMap >> SelfivewPipSizeToggle },
[JoinName("SelfviewPipSizeToggle")] new JoinMetadata
public JoinDataComplete SelfviewPipSizeToggle = new JoinDataComplete( {
new JoinData Description = "Gets the available layouts. Will update the LayoutXXXXXIsAvailbale signals.",
{ JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinNumber = 231, JoinType = eJoinType.Digital
JoinSpan = 1 });
},
new JoinMetadata [JoinName("LayoutIsOnFirstPage")]
{ public JoinDataComplete LayoutIsOnFirstPage = new JoinDataComplete(
Description = "Toggles the selfview pip size, (aka layout size)", new JoinData
JoinCapabilities = eJoinCapabilities.ToFromSIMPL, {
JoinType = eJoinType.Digital JoinNumber = 216,
}); JoinSpan = 1
},
//[JoinName("ParticipantAudioMuteToggleStart")] new JoinMetadata
//public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete( {
// new JoinData Description = "Indicates if layout is on first page",
// { JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinNumber = 500, JoinType = eJoinType.Digital
// JoinSpan = 100 });
// },
// new JoinMetadata [JoinName("LayoutIsOnLastPage")]
// { public JoinDataComplete LayoutIsOnLastPage = new JoinDataComplete(
// Description = "Toggles the participant's audio mute status", new JoinData
// JoinCapabilities = eJoinCapabilities.ToSIMPL, {
// JoinType = eJoinType.Digital JoinNumber = 217,
// }); JoinSpan = 1
},
//[JoinName("ParticipantVideoMuteToggleStart")] new JoinMetadata
//public JoinDataComplete ParticipantVideoMuteToggleStart = new JoinDataComplete( {
// new JoinData Description = "Indicates if layout is on first page",
// { JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinNumber = 800, JoinType = eJoinType.Digital
// JoinSpan = 100 });
// },
// new JoinMetadata [JoinName("LayoutTurnToNextPage")]
// { public JoinDataComplete LayoutTurnToNextPage = new JoinDataComplete(
// Description = "Toggles the participant's video mute status", new JoinData
// JoinCapabilities = eJoinCapabilities.ToSIMPL, {
// JoinType = eJoinType.Digital JoinNumber = 216,
// }); JoinSpan = 1
},
//[JoinName("ParticipantPinToggleStart")] new JoinMetadata
//public JoinDataComplete ParticipantPinToggleStart = new JoinDataComplete( {
// new JoinData Description = "Turns layout view to next page",
// { JoinCapabilities = eJoinCapabilities.FromSIMPL,
// JoinNumber = 1100, JoinType = eJoinType.Digital
// JoinSpan = 100 });
// },
// new JoinMetadata [JoinName("LayoutTurnToPreviousPage")]
// { public JoinDataComplete LayoutTurnToPreviousPage = new JoinDataComplete(
// Description = "Toggles the participant's pin status", new JoinData
// JoinCapabilities = eJoinCapabilities.ToSIMPL, {
// JoinType = eJoinType.Digital JoinNumber = 217,
// }); JoinSpan = 1
},
#endregion new JoinMetadata
{
Description = "Turns layout view to previous page",
#region Analog JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Digital
[JoinName("NumberOfScreens")] });
public JoinDataComplete NumberOfScreens = new JoinDataComplete(
new JoinData [JoinName("LayoutGalleryIsAvailable")]
{ public JoinDataComplete LayoutGalleryIsAvailable = new JoinDataComplete(
JoinNumber = 11, new JoinData
JoinSpan = 1 {
}, JoinNumber = 221,
new JoinMetadata JoinSpan = 1
{ },
Description = "Reports the number of screens connected", new JoinMetadata
JoinCapabilities = eJoinCapabilities.ToSIMPL, {
JoinType = eJoinType.Analog Description = "FB Indicates if layout 'Gallery' is available",
}); JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
[JoinName("ScreenIndexToPinUserTo")] });
public JoinDataComplete ScreenIndexToPinUserTo = new JoinDataComplete(
new JoinData [JoinName("LayoutSpeakerIsAvailable")]
{ public JoinDataComplete LayoutSpeakerIsAvailable = new JoinDataComplete(
JoinNumber = 11, new JoinData
JoinSpan = 1 {
}, JoinNumber = 222,
new JoinMetadata JoinSpan = 1
{ },
Description = "Specifies the screen index a participant should be pinned to", new JoinMetadata
JoinCapabilities = eJoinCapabilities.FromSIMPL, {
JoinType = eJoinType.Analog Description = "FB Indicates if layout 'Speaker' is available",
}); JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.DigitalSerial
#endregion });
[JoinName("LayoutStripIsAvailable")]
#region Serials public JoinDataComplete LayoutStripIsAvailable = new JoinDataComplete(
new JoinData
[JoinName("GetSetCurrentLayout")] {
public JoinDataComplete GetSetCurrentLayout = new JoinDataComplete( JoinNumber = 223,
new JoinData JoinSpan = 1
{ },
JoinNumber = 215, new JoinMetadata
JoinSpan = 1 {
}, Description = "FB Indicates if layout 'Strip' is available",
new JoinMetadata JoinCapabilities = eJoinCapabilities.ToSIMPL,
{ JoinType = eJoinType.DigitalSerial
Description = "Sets and reports the current layout. Use the LayoutXXXXIsAvailable signals to determine valid layouts", });
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Serial [JoinName("LayoutShareAllIsAvailable")]
}); public JoinDataComplete LayoutShareAllIsAvailable = new JoinDataComplete(
new JoinData
// TODO: #714 [ ] JoinMap >> GetSetSelfviewPipSize {
[JoinName("GetSetSelfviewPipSize")] JoinNumber = 224,
public JoinDataComplete GetSetSelfviewPipSize = new JoinDataComplete( JoinSpan = 1
new JoinData },
{ new JoinMetadata
JoinNumber = 230, {
JoinSpan = 1 Description = "FB Indicates if layout 'ShareAll' is available",
}, JoinCapabilities = eJoinCapabilities.ToSIMPL,
new JoinMetadata JoinType = eJoinType.DigitalSerial
{ });
Description = "Sets and reports the selfview pip size, (aka layout size).",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL, // TODO: #714 [ ] JoinMap >> SelfivewPipSizeToggle
JoinType = eJoinType.DigitalSerial [JoinName("SelfviewPipSizeToggle")]
}); public JoinDataComplete SelfviewPipSizeToggle = new JoinDataComplete(
new JoinData
#endregion {
JoinNumber = 231,
public ZoomRoomJoinMap(uint joinStart) JoinSpan = 1
: base(joinStart, typeof(ZoomRoomJoinMap)) },
{ new JoinMetadata
} {
Description = "Toggles the selfview pip size, (aka layout size)",
public ZoomRoomJoinMap(uint joinStart, Type type) JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
: base(joinStart, type) JoinType = eJoinType.Digital
{ });
}
} //[JoinName("ParticipantAudioMuteToggleStart")]
//public JoinDataComplete ParticipantAudioMuteToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 500,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's audio mute status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
//[JoinName("ParticipantVideoMuteToggleStart")]
//public JoinDataComplete ParticipantVideoMuteToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 800,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's video mute status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
//[JoinName("ParticipantPinToggleStart")]
//public JoinDataComplete ParticipantPinToggleStart = new JoinDataComplete(
// new JoinData
// {
// JoinNumber = 1100,
// JoinSpan = 100
// },
// new JoinMetadata
// {
// Description = "Toggles the participant's pin status",
// JoinCapabilities = eJoinCapabilities.ToSIMPL,
// JoinType = eJoinType.Digital
// });
#endregion
#region Analog
[JoinName("NumberOfScreens")]
public JoinDataComplete NumberOfScreens = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Reports the number of screens connected",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Analog
});
[JoinName("ScreenIndexToPinUserTo")]
public JoinDataComplete ScreenIndexToPinUserTo = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Specifies the screen index a participant should be pinned to",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Analog
});
#endregion
#region Serials
// TODO [ ] Issue #868
[JoinName("SubmitPassword")]
public JoinDataComplete SubmitPassword = new JoinDataComplete(
new JoinData
{
JoinNumber = 6,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Submit password text",
JoinCapabilities = eJoinCapabilities.FromSIMPL,
JoinType = eJoinType.Serial
});
// TODO [ ] Issue #868
[JoinName("PasswordPromptMessage")]
public JoinDataComplete PasswordPromptMessage = new JoinDataComplete(
new JoinData
{
JoinNumber = 6,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Password prompt message",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
// TODO [ ] Issue #868
[JoinName("MeetingInfoId")]
public JoinDataComplete MeetingInfoId = new JoinDataComplete(
new JoinData
{
JoinNumber = 11,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Meeting info ID text feedback",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
// TODO [ ] Issue #868
[JoinName("MeetingInfoHostt")]
public JoinDataComplete MeetingInfoHost = new JoinDataComplete(
new JoinData
{
JoinNumber = 12,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Meeting info Host text feedback",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
// TODO [ ] Issue #868
[JoinName("MeetingInfoPassword")]
public JoinDataComplete MeetingInfoPassword = new JoinDataComplete(
new JoinData
{
JoinNumber = 13,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Meeting info Password text feedback",
JoinCapabilities = eJoinCapabilities.ToSIMPL,
JoinType = eJoinType.Serial
});
[JoinName("GetSetCurrentLayout")]
public JoinDataComplete GetSetCurrentLayout = new JoinDataComplete(
new JoinData
{
JoinNumber = 215,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Sets and reports the current layout. Use the LayoutXXXXIsAvailable signals to determine valid layouts",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.Serial
});
// TODO: #714 [ ] JoinMap >> GetSetSelfviewPipSize
[JoinName("GetSetSelfviewPipSize")]
public JoinDataComplete GetSetSelfviewPipSize = new JoinDataComplete(
new JoinData
{
JoinNumber = 230,
JoinSpan = 1
},
new JoinMetadata
{
Description = "Sets and reports the selfview pip size, (aka layout size).",
JoinCapabilities = eJoinCapabilities.ToFromSIMPL,
JoinType = eJoinType.DigitalSerial
});
#endregion
public ZoomRoomJoinMap(uint joinStart)
: base(joinStart, typeof(ZoomRoomJoinMap))
{
}
public ZoomRoomJoinMap(uint joinStart, Type type)
: base(joinStart, type)
{
}
}
} }