diff --git a/IR Drivers/Apple_AppleTV_4th_Gen_Essentials.ir b/IR Drivers/Apple_AppleTV_4th_Gen_Essentials.ir new file mode 100644 index 00000000..f112ee8b Binary files /dev/null and b/IR Drivers/Apple_AppleTV_4th_Gen_Essentials.ir differ diff --git a/PepperDashEssentials/Example Configuration/EssentialsHuddleSpaceRoom/configurationFile-HuddleSpace-2-Source.json b/PepperDashEssentials/Example Configuration/EssentialsHuddleSpaceRoom/configurationFile-HuddleSpace-2-Source.json index 3e43dac6..d3ce3275 100644 --- a/PepperDashEssentials/Example Configuration/EssentialsHuddleSpaceRoom/configurationFile-HuddleSpace-2-Source.json +++ b/PepperDashEssentials/Example Configuration/EssentialsHuddleSpaceRoom/configurationFile-HuddleSpace-2-Source.json @@ -88,7 +88,7 @@ { "name": "Wireless Video", "key": "wePresent-1", - "type": "wePresent", + "type": "genericSource", "group": "genericSource", "uid": 9, "properties": { diff --git a/PepperDashEssentials/Example Configuration/EssentialsHuddleVtc1Room/configurationFile-mockVideoCodec_din-ap3_-_dm4x1.json b/PepperDashEssentials/Example Configuration/EssentialsHuddleVtc1Room/configurationFile-mockVideoCodec_din-ap3_-_dm4x1.json index 7cc97c47..1e5b66d2 100644 --- a/PepperDashEssentials/Example Configuration/EssentialsHuddleVtc1Room/configurationFile-mockVideoCodec_din-ap3_-_dm4x1.json +++ b/PepperDashEssentials/Example Configuration/EssentialsHuddleVtc1Room/configurationFile-mockVideoCodec_din-ap3_-_dm4x1.json @@ -114,7 +114,7 @@ { "name": "Wireless Video", "key": "wePresent-1", - "type": "wePresent", + "type": "genericSource", "properties": {}, "group": "genericSource", "uid": 3 diff --git a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs index 078f9bd5..5a2bd34f 100644 --- a/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs +++ b/PepperDashEssentials/Room/Config/EssentialsRoomConfig.cs @@ -151,6 +151,24 @@ namespace PepperDash.Essentials.Room.Config [JsonProperty("helpMessage")] public string HelpMessage { get; set; } + /// + /// Read this value to get the help message. It checks for the old and new config format. + /// + public string HelpMessageForDisplay + { + get + { + if(Help != null && !string.IsNullOrEmpty(Help.Message)) + { + return Help.Message; + } + else + { + return HelpMessage; + } + } + } + [JsonProperty("environment")] public EssentialsEnvironmentPropertiesConfig Environment { get; set; } diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs index 3123f20f..5dbe7600 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs @@ -202,11 +202,28 @@ namespace PepperDash.Essentials }; } + SetupEnvironmentalControlDevices(); + SetSourceListKey(); 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() { if (!string.IsNullOrEmpty(PropertiesConfig.SourceListKey)) diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs index a5fda4bd..f429b8c8 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleVtc1Room.cs @@ -214,17 +214,25 @@ namespace PepperDash.Essentials VideoCodec = DeviceManager.GetDeviceForKey(PropertiesConfig.VideoCodecKey) as PepperDash.Essentials.Devices.Common.VideoCodec.VideoCodecBase; - + 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 PepperDash.Essentials.Devices.Common.AudioCodec.AudioCodecBase; if (AudioCodec == null) Debug.Console(0, this, "No Audio Codec Found"); 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(); } @@ -326,6 +334,8 @@ namespace PepperDash.Essentials CallTypeFeedback = new IntFeedback(() => 0); + SetupEnvironmentalControlDevices(); + SetSourceListKey(); 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() { @@ -419,6 +444,14 @@ namespace PepperDash.Essentials /// 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); return true; } diff --git a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs index d33c3707..c2b08f89 100644 --- a/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsTechRoom.cs @@ -375,7 +375,7 @@ Params: {2}" { bridge.AddJoinMap(Key, joinMap); } - uint i; + if (_config.IsPrimary) { Debug.Console(1, this, "Linking Primary system Tuner Preset Mirroring"); diff --git a/PepperDashEssentials/UI/EssentialsTouchpanelController.cs b/PepperDashEssentials/UI/EssentialsTouchpanelController.cs index becba34c..441381bd 100644 --- a/PepperDashEssentials/UI/EssentialsTouchpanelController.cs +++ b/PepperDashEssentials/UI/EssentialsTouchpanelController.cs @@ -408,7 +408,7 @@ namespace PepperDash.Essentials { public EssentialsTouchpanelControllerFactory() { - TypeNames = new List() { "tsw550", "tsw750", "tsw1050", "tsw560", "tsw760", "tsw1060", "tsw570", "tsw770", "ts770", "tsw1070", "ts1070", "xpanel" }; + TypeNames = new List() { "crestronapp", "tsw550", "tsw750", "tsw1050", "tsw560", "tsw760", "tsw1060", "tsw570", "tsw770", "ts770", "tsw1070", "ts1070", "xpanel" }; } public override EssentialsDevice BuildDevice(DeviceConfig dc) diff --git a/README.md b/README.md index efb706c0..0fe4f075 100644 --- a/README.md +++ b/README.md @@ -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). +## Support + +* Check out our [Discord Server](https://discord.gg/rWyeRH3K) + ## How-To (Getting Started) See [Getting Started](https://github.com/PepperDash/Essentials/wiki/Get-started#how-to-get-started) diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs index 4e731f41..63684837 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/CenOdtOccupancySensorBaseJoinMap.cs @@ -46,6 +46,14 @@ namespace PepperDash.Essentials.Core.Bridges public JoinDataComplete RawOccupancyUsFeedback = new JoinDataComplete(new JoinData { JoinNumber = 7, JoinSpan = 1 }, 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")] public JoinDataComplete EnableLedFlash = new JoinDataComplete(new JoinData { JoinNumber = 11, JoinSpan = 1 }, new JoinMetadata { Description = "Enable Led Flash", JoinCapabilities = eJoinCapabilities.ToFromSIMPL, JoinType = eJoinType.Digital }); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs index 3854a4fb..5a583d69 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/GlsPartitionSensorJoinMap.cs @@ -5,6 +5,9 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps { public class GlsPartitionSensorJoinMap : JoinMapBaseAdvanced { + + #region Digital + [JoinName("IsOnline")] public JoinDataComplete IsOnline = new JoinDataComplete( new JoinData @@ -19,20 +22,7 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps JoinType = eJoinType.Digital }); - [JoinName("Name")] - public JoinDataComplete Name = new JoinDataComplete( - new JoinData - { - JoinNumber = 1, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Sensor Name", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Serial - }); - + [JoinName("Enable")] public JoinDataComplete Enable = new JoinDataComplete( new JoinData @@ -101,7 +91,11 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps Description = "Sensor Decrease Sensitivity", JoinCapabilities = eJoinCapabilities.FromSIMPL, JoinType = eJoinType.Digital - }); + }); + + #endregion + + #region Analog [JoinName("Sensitivity")] public JoinDataComplete Sensitivity = new JoinDataComplete( @@ -117,6 +111,28 @@ namespace PepperDash.Essentials.Core.Bridges.JoinMaps 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 + + /// /// Constructor to use when instantiating this Join Map without inheriting from it /// diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs index dcb66a2e..21b88ed3 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Bridges/JoinMaps/VideoCodecControllerJoinMap.cs @@ -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")] public JoinDataComplete MinutesBeforeMeetingStart = new JoinDataComplete( diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Relay/CenIoRy104Controller.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Relay/CenIoRy104Controller.cs new file mode 100644 index 00000000..19ca8438 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Relay/CenIoRy104Controller.cs @@ -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 +{ + /// + /// Wrapper class for CEN-IO-RY-104 relay module + /// + [Description("Wrapper class for the CEN-IO-RY-104 relay module")] + public class CenIoRy104Controller : EssentialsDevice, IRelayPorts + { + private readonly CenIoRy104 _ry104; + + /// + /// Constructor + /// + /// + /// + /// + public CenIoRy104Controller(string key, string name, CenIoRy104 ry104) + : base(key, name) + { + _ry104 = ry104; + } + + /// + /// Relay port collection + /// + public CrestronCollection RelayPorts + { + get { return _ry104.RelayPorts; } + } + + /// + /// Number of relay ports property + /// + public int NumberOfRelayPorts + { + get { return _ry104.NumberOfRelayPorts; } + } + } + + /// + /// CEN-IO-RY Controller factory + /// + public class CenIoRy104ControllerFactory : EssentialsDeviceFactory + { + /// + /// Constructor + /// + public CenIoRy104ControllerFactory() + { + TypeNames = new List() { "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; + } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Relay/GenericRelayDevice.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Relay/GenericRelayDevice.cs index 445ac338..69c588ae 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Relay/GenericRelayDevice.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron IO/Relay/GenericRelayDevice.cs @@ -44,6 +44,12 @@ namespace PepperDash.Essentials.Core.CrestronIO { 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.StateChange += RelayOutput_StateChange; @@ -61,33 +67,36 @@ namespace PepperDash.Essentials.Core.CrestronIO { if (!Global.ControlSystem.SupportsRelay) { - Debug.Console(0, "GetRelayDevice: Processor does not support relays"); + Debug.Console(0, "Processor does not support relays"); return null; } 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; - 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); + Debug.Console(0, "Device {0} was not found in Device Manager. Check configuration or for errors with device.", dc.PortDeviceKey); return null; } - if (dc.PortNumber > relayDevice.NumberOfRelayPorts) - { - Debug.Console(0, "GetRelayDevice: Device {0} does not contain a port {1}", dc.PortDeviceKey, dc.PortNumber); - } + relayDevice = essentialsDevice as IRelayPorts; - 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 @@ -200,58 +209,6 @@ namespace PepperDash.Essentials.Core.CrestronIO var portDevice = new GenericRelayDevice(dc.Key, dc.Name, GetRelay, props); 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 - } - */ - } } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Lighting/LightingBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Lighting/LightingBase.cs index 1bf8aee8..569d2005 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Lighting/LightingBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Lighting/LightingBase.cs @@ -1,83 +1,83 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.DeviceSupport; -using Newtonsoft.Json; -using PepperDash.Core; -using PepperDash.Essentials.Core.Bridges; - -namespace PepperDash.Essentials.Core.Lighting -{ - public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes - { - #region ILightingScenes Members - - public event EventHandler LightingSceneChange; - - public List LightingScenes { get; protected set; } - - public LightingScene CurrentLightingScene { get; protected set; } - - public IntFeedback CurrentLightingSceneFeedback { get; protected set; } - - #endregion - - protected LightingBase(string key, string name) - : base(key, name) - { - LightingScenes = new List(); - - 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(); - } - } - - /// - /// Sets the IsActive property on each scene and fires the LightingSceneChange event - /// - 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) +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DeviceSupport; +using Newtonsoft.Json; +using PepperDash.Core; +using PepperDash.Essentials.Core.Bridges; + +namespace PepperDash.Essentials.Core.Lighting +{ + public abstract class LightingBase : EssentialsBridgeableDevice, ILightingScenes + { + #region ILightingScenes Members + + public event EventHandler LightingSceneChange; + + public List LightingScenes { get; protected set; } + + public LightingScene CurrentLightingScene { get; protected set; } + + public IntFeedback CurrentLightingSceneFeedback { get; protected set; } + + #endregion + + protected LightingBase(string key, string name) + : base(key, name) { - var joinMap = new GenericLightingJoinMap(joinStart); - - var joinMapSerialized = JoinMapHelper.GetSerializedJoinMapForDevice(joinMapKey); - - if (!string.IsNullOrEmpty(joinMapSerialized)) + LightingScenes = new List(); + + 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(); + } + } + + /// + /// Sets the IsActive property on each scene and fires the LightingSceneChange event + /// + 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(joinMapSerialized); if (bridge != null) @@ -87,52 +87,57 @@ namespace PepperDash.Essentials.Core.Lighting else { 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(0, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); - + } + + Debug.Console(1, "Linking to Trilist '{0}'", trilist.ID.ToString("X")); + + Debug.Console(0, "Linking to Lighting Type {0}", lightingDevice.GetType().Name.ToString()); + // GenericLighitng Actions & FeedBack - trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); - - var sceneIndex = 0; - foreach (var scene in lightingDevice.LightingScenes) + trilist.SetUShortSigAction(joinMap.SelectScene.JoinNumber, u => lightingDevice.SelectScene(lightingDevice.LightingScenes[u])); + + var sceneIndex = 0; + 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)]); - trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + sceneIndex)].StringValue = scene.Name; - trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + sceneIndex)].BoolValue = true; - sceneIndex++; - } - - return joinMap; - } - - } - - public class LightingScene - { - public string Name { get; set; } - public string ID { get; set; } - bool _IsActive; - public bool IsActive - { - get - { - return _IsActive; - } - set - { - _IsActive = value; - IsActiveFeedback.FireUpdate(); - } - } - public BoolFeedback IsActiveFeedback { get; set; } - - public LightingScene() - { - IsActiveFeedback = new BoolFeedback(new Func(() => IsActive)); - } - } + trilist.StringInput[(uint)(joinMap.SelectSceneDirect.JoinNumber + sceneIndex)].StringValue = scene.Name; + trilist.BooleanInput[(uint)(joinMap.ButtonVisibility.JoinNumber + sceneIndex)].BoolValue = true; + sceneIndex++; + } + + return joinMap; + } + + } + + public class LightingScene + { + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public string ID { get; set; } + bool _IsActive; + [JsonProperty("isActive", NullValueHandling = NullValueHandling.Ignore)] + public bool IsActive + { + get + { + return _IsActive; + } + set + { + _IsActive = value; + IsActiveFeedback.FireUpdate(); + } + } + + [JsonIgnore] + public BoolFeedback IsActiveFeedback { get; set; } + + public LightingScene() + { + IsActiveFeedback = new BoolFeedback(new Func(() => IsActive)); + } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/CenOdtOccupancySensorBaseController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/CenOdtOccupancySensorBaseController.cs index dcf0b193..eae2f993 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/CenOdtOccupancySensorBaseController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/CenOdtOccupancySensorBaseController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Resources; using System.Text; using Crestron.SimplSharp; using Crestron.SimplSharpPro.DeviceSupport; @@ -61,6 +62,8 @@ namespace PepperDash.Essentials.Core public BoolFeedback RawOccupancyUsFeedback { get; private set; } + public BoolFeedback IdentityModeFeedback { get; private set; } + // Debug properties public bool InTestMode { get; private set; } @@ -117,6 +120,8 @@ namespace PepperDash.Essentials.Core RawOccupancyUsFeedback = new BoolFeedback(() => OccSensor.RawOccupancyDetectedByUltrasonicSensorFeedback.BoolValue); + IdentityModeFeedback = new BoolFeedback(()=>OccSensor.IdentityModeOnFeedback.BoolValue); + UltrasonicSensitivityInVacantStateFeedback = new IntFeedback(() => (int)OccSensor.UltrasonicSensorSensitivityInVacantStateFeedback); UltrasonicSensitivityInOccupiedStateFeedback = new IntFeedback(() => (int)OccSensor.UltrasonicSensorSensitivityInOccupiedStateFeedback); @@ -199,6 +204,27 @@ namespace PepperDash.Essentials.Core { 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); + } } /// @@ -279,7 +305,21 @@ namespace PepperDash.Essentials.Core } } - /// + /// + /// Sets the identity mode on or off + /// + /// + public void SetIdentityMode(bool state) + { + if (state) + OccSensor.IdentityModeOn(); + else + OccSensor.IdentityModeOff(); + + Debug.Console(1, this, "Identity Mode: {0}", OccSensor.IdentityModeOnFeedback.BoolValue ? "On" : "Off"); + } + + /// /// Enables or disables the PIR sensor /// /// @@ -506,6 +546,54 @@ namespace PepperDash.Essentials.Core } } + /// + /// Sets the US sensor sensitivity for occupied state + /// + /// + public void SetUsSensitivityOccupied(ushort sensitivity) + { + var level = (eSensitivityLevel) sensitivity; + if (level == 0) return; + + OccSensor.UltrasonicSensorSensitivityInOccupiedState = level; + } + + /// + /// Sets the US sensor sensitivity for vacant state + /// + /// + public void SetUsSensitivityVacant(ushort sensitivity) + { + var level = (eSensitivityLevel)sensitivity; + if (level == 0) return; + + OccSensor.UltrasonicSensorSensitivityInVacantState = level; + } + + /// + /// Sets the PIR sensor sensitivity for occupied state + /// + /// + public void SetPirSensitivityOccupied(ushort sensitivity) + { + var level = (eSensitivityLevel)sensitivity; + if (level == 0) return; + + OccSensor.PassiveInfraredSensorSensitivityInOccupiedState = level; + } + + /// + /// Sets the PIR sensor sensitivity for vacant state + /// + /// + public void SetPirSensitivityVacant(ushort sensitivity) + { + var level = (eSensitivityLevel)sensitivity; + if (level == 0) return; + + OccSensor.PassiveInfraredSensorSensitivityInVacantState = level; + } + /// /// Method to print current settings to console /// @@ -647,8 +735,11 @@ namespace PepperDash.Essentials.Core //Sensor Raw States 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 diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/GlsOccupancySensorPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/GlsOccupancySensorPropertiesConfig.cs index 1f21b2a8..392c05b0 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/GlsOccupancySensorPropertiesConfig.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Occupancy/GlsOccupancySensorPropertiesConfig.cs @@ -47,5 +47,35 @@ namespace PepperDash.Essentials.Core [JsonProperty("andWhenVacatedState")] public bool? AndWhenVacatedState { get; set; } + + // PoE Sensors: CenOdtCPoe + + /// + /// Sets the sensitivity level for US while sensor is in occupied state + /// 1 = low; 2 = medium; 3 = high; 4 = xlow; 5 = 2xlow; 6 = 3xlow + /// + [JsonProperty("usSensitivityOccupied")] + public ushort? UsSensitivityOccupied { get; set; } + + /// + /// Sets the sensitivity level for US while sensor is in vacant state + /// 1 = low; 2 = medium; 3 = high; 4 = xlow; 5 = 2xlow; 6 = 3xlow + /// + [JsonProperty("usSensitivityVacant")] + public ushort? UsSensitivityVacant { get; set; } + + /// + /// Sets the sensitivity level for PIR while sensor is in occupied state + /// 1 = low; 2 = medium; 3 = high + /// + [JsonProperty("pirSensitivityOccupied")] + public ushort? PirSensitivityOccupied { get; set; } + + /// + /// Sets the sensitivity level for PIR while sensor is in vacant state + /// 1 = low; 2 = medium; 3 = high + /// + [JsonProperty("pirSensitivityVacant")] + public ushort? PirSensitivityVacant { get; set; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs index 5f40bf7e..16b2f265 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorController.cs @@ -1,4 +1,5 @@ -using Crestron.SimplSharpPro; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; using Crestron.SimplSharpPro.DeviceSupport; using Crestron.SimplSharpPro.GeneralIO; using Newtonsoft.Json; @@ -9,15 +10,18 @@ using PepperDash.Essentials.Core.Bridges.JoinMaps; using System; using System.Collections.Generic; using PepperDash.Essentials.Core.Config; +using PepperDash_Essentials_Core.PartitionSensor; namespace PepperDash.Essentials.Core { [Description("Wrapper class for GLS Cresnet Partition Sensor")] 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 PartitionPresentFeedback { get; private set; } public BoolFeedback PartitionNotSensedFeedback { get; private set; } @@ -32,23 +36,71 @@ namespace PepperDash.Essentials.Core public GlsPartitionSensorController(string key, Func preActivationFunc, DeviceConfig config) : base(key, config.Name) { + + var props = config.Properties.ToObject(); + if (props != null) + { + PropertiesConfig = props; + } + else + { + Debug.Console(1, this, "props are null. Unable to deserialize into GlsPartSensorPropertiesConfig"); + } + AddPreActivationAction(() => { _partitionSensor = preActivationFunc(config); - + RegisterCrestronGenericBase(_partitionSensor); - - NameFeedback = new StringFeedback(() => Name); + EnableFeedback = new BoolFeedback(() => InTestMode ? TestEnableFeedback : _partitionSensor.EnableFeedback.BoolValue); PartitionPresentFeedback = new BoolFeedback(() => InTestMode ? TestPartitionSensedFeedback : _partitionSensor.PartitionSensedFeedback.BoolValue); PartitionNotSensedFeedback = new BoolFeedback(() => InTestMode ? !TestPartitionSensedFeedback : _partitionSensor.PartitionNotSensedFeedback.BoolValue); 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); @@ -61,11 +113,13 @@ namespace PepperDash.Essentials.Core } case (GlsPartCn.PartitionSensedFeedbackEventId): { + Debug.Console(1, this, "Partition Sensed State: {0}", _partitionSensor.PartitionSensedFeedback.BoolValue); PartitionPresentFeedback.FireUpdate(); break; } case (GlsPartCn.PartitionNotSensedFeedbackEventId): { + Debug.Console(1, this, "Partition Not Sensed State: {0}", _partitionSensor.PartitionNotSensedFeedback.BoolValue); PartitionNotSensedFeedback.FireUpdate(); break; } @@ -73,7 +127,7 @@ namespace PepperDash.Essentials.Core { SensitivityFeedback.FireUpdate(); break; - } + } default: { 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); } - 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); 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(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); + 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.DecreaseSensitivity.JoinNumber, DecreaseSensitivity); - trilist.SetUShortSigAction(joinMap.Sensitivity.JoinNumber, SetSensitivity); - // link output to simpl - IsOnline.LinkInputSig(trilist.BooleanInput[joinMap.IsOnline.JoinNumber]); - 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]); + SensitivityFeedback.LinkInputSig(trilist.UShortInput[joinMap.Sensitivity.JoinNumber]); + trilist.SetUShortSigAction(joinMap.Sensitivity.JoinNumber, SetSensitivity); FeedbacksFireUpdates(); @@ -218,6 +289,7 @@ namespace PepperDash.Essentials.Core { if (a.DeviceOnLine) { + trilist.StringInput[joinMap.Name.JoinNumber].StringValue = _partitionSensor.Name; FeedbacksFireUpdates(); } }; @@ -225,8 +297,7 @@ namespace PepperDash.Essentials.Core private void FeedbacksFireUpdates() { - IsOnline.FireUpdate(); - NameFeedback.FireUpdate(); + IsOnline.FireUpdate(); EnableFeedback.FireUpdate(); PartitionPresentFeedback.FireUpdate(); PartitionNotSensedFeedback.FireUpdate(); diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorPropertiesConfig.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorPropertiesConfig.cs new file mode 100644 index 00000000..8a303662 --- /dev/null +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PartitionSensor/GlsPartitionSensorPropertiesConfig.cs @@ -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 + { + /// + /// Sets the sensor sensitivity + /// + /// + /// The sensitivity range shall be between 1(lowest) to 10 (highest). + /// + [JsonProperty("sensitivity")] + public ushort? Sensitivity { get; set; } + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj index abd7c498..3c7a6c31 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/PepperDash_Essentials_Core.csproj @@ -182,6 +182,7 @@ + @@ -236,6 +237,7 @@ + diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs index 0d8e9803..352cbfcd 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/EssentialsRoomBase.cs @@ -11,6 +11,8 @@ using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Devices; using PepperDash.Essentials.Core.DeviceTypeInterfaces; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Core { /// @@ -18,6 +20,8 @@ namespace PepperDash.Essentials.Core /// public abstract class EssentialsRoomBase : ReconfigurableDevice, IEssentialsRoom { + + /// /// /// @@ -35,6 +39,16 @@ namespace PepperDash.Essentials.Core public bool OccupancyStatusProviderIsRemote { get; private set; } + public List EnvironmentalControlDevices { get; protected set; } + + public bool HasEnvironmentalControlDevices + { + get + { + return EnvironmentalControlDevices != null && EnvironmentalControlDevices.Count > 0; + } + } + protected abstract Func IsWarmingFeedbackFunc { get; } protected abstract Func IsCoolingFeedbackFunc { get; } @@ -119,6 +133,8 @@ namespace PepperDash.Essentials.Core public EssentialsRoomBase(DeviceConfig config) : base(config) { + EnvironmentalControlDevices = new List(); + // Setup the ShutdownPromptTimer ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer"); ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) => diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/IEssentialsRoom.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/IEssentialsRoom.cs index 5f94a5cd..2273690f 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/IEssentialsRoom.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/IEssentialsRoom.cs @@ -15,7 +15,7 @@ namespace PepperDash.Essentials.Core /// /// Describes the basic functionality of an EssentialsRoom /// - public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute + public interface IEssentialsRoom : IKeyName, IReconfigurableDevice, IRunDefaultPresentRoute, IEnvironmentalControls { BoolFeedback OnFeedback { get; } diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs index 592b0bd9..b5121e9c 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Room/Interfaces.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using PepperDash.Core; + namespace PepperDash.Essentials.Core { @@ -66,6 +68,14 @@ namespace PepperDash.Essentials.Core bool RunDefaultCallRoute(); } + /// + /// Describes environmental controls available on a room such as lighting, shades, temperature, etc. + /// + public interface IEnvironmentalControls + { + List EnvironmentalControlDevices { get; } + bool HasEnvironmentalControlDevices { get; } + } } \ No newline at end of file diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Shades/Shade Interfaces.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Shades/Shade Interfaces.cs index b4d7c88d..35492162 100644 --- a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Shades/Shade Interfaces.cs +++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Shades/Shade Interfaces.cs @@ -31,6 +31,7 @@ namespace PepperDash.Essentials.Core.Shades public interface IShadesOpenCloseStop : IShadesOpenClose { void StopOrPreset(); + string StopOrPresetButtonLabel { get; } } /// diff --git a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmBladeChassisController.cs b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmBladeChassisController.cs index 96cc8097..412dee6b 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmBladeChassisController.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmBladeChassisController.cs @@ -483,7 +483,7 @@ namespace PepperDash.Essentials.DM Debug.Console(2, this, "Adding output port '{0}'", portKey); OutputPorts.Add(new RoutingOutputPort(portKey, sigType, portType, selector, this) { - FeedbackMatchObject = Chassis.Outputs[(uint)selector] + FeedbackMatchObject = selector }); }*/ diff --git a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs index c74aea2b..030536df 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Chassis/DmChassisController.cs @@ -1285,7 +1285,10 @@ namespace PepperDash.Essentials.DM 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, "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) { 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) @@ -1326,17 +1332,66 @@ namespace PepperDash.Essentials.DM { dmMdMnxn.AudioEnter.BoolValue = true; } - output.AudioOut = input; - //Chassis.Outputs[output].AudioOut = inCard; + if (output != null) + { + output.AudioOut = input; + } } - if ((sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput || (sigType & eRoutingSignalType.UsbInput) == eRoutingSignalType.UsbInput) + if ((sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput) + { - Chassis.USBEnter.BoolValue = true; - output.USBRoutedTo = input; + Chassis.USBEnter.BoolValue = true; + 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 #region IRoutingNumeric Members @@ -1349,8 +1404,10 @@ namespace PepperDash.Essentials.DM DMInputOutputBase dmCard; + //Routing Input to Input or Output to Input 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) { uint outputIndex; @@ -1370,13 +1427,14 @@ namespace PepperDash.Essentials.DM dmCard = Chassis.Inputs[inputSelector]; } - ExecuteSwitch(dmCard, Chassis.Outputs[outputSelector], sigType); + ExecuteSwitch(dmCard, Chassis.Inputs[outputSelector], sigType); return; } if ((sigType & eRoutingSignalType.UsbOutput) == eRoutingSignalType.UsbOutput) { 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) { //wanting to route an output to an output. Subtract chassis size and get output, unless it's 8x8 diff --git a/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Receivers/DmRmc4kZScalerCController.cs b/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Receivers/DmRmc4kZScalerCController.cs index 21663e78..73dd59b9 100644 --- a/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Receivers/DmRmc4kZScalerCController.cs +++ b/essentials-framework/Essentials DM/Essentials_DM/Endpoints/Receivers/DmRmc4kZScalerCController.cs @@ -14,7 +14,7 @@ namespace PepperDash.Essentials.DM { [Description("Wrapper Class for DM-RMC-4K-Z-SCALER-C")] public class DmRmc4kZScalerCController : DmRmcControllerBase, IRmcRoutingWithFeedback, - IIROutputPorts, IComPorts, ICec + IIROutputPorts, IComPorts, ICec, IRelayPorts { private readonly DmRmc4kzScalerC _rmc; @@ -168,5 +168,18 @@ namespace PepperDash.Essentials.DM } #endregion + #region Implementation of IRelayPorts + + public CrestronCollection RelayPorts + { + get { return _rmc.RelayPorts; } + } + + public int NumberOfRelayPorts + { + get { return _rmc.NumberOfRelayPorts; } + } + + #endregion } } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs index b2ccb29c..642f03d0 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Codec/iHasDirectory.cs @@ -69,6 +69,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec [JsonProperty("directoryResults")] public List CurrentDirectoryResults { get; private set; } + [JsonProperty("contacts")] public List Contacts { get @@ -77,6 +78,7 @@ namespace PepperDash.Essentials.Devices.Common.Codec } } + [JsonProperty("folders")] public List Folders { get diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj index 1fcffff2..c1873d26 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Essentials Devices Common.csproj @@ -123,6 +123,8 @@ + + diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Streaming/AppleTV.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Streaming/AppleTV.cs index 709afb72..07df3602 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/Streaming/AppleTV.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/Streaming/AppleTV.cs @@ -19,7 +19,7 @@ namespace PepperDash.Essentials.Devices.Common public class AppleTV : EssentialsBridgeableDevice, IDPad, ITransport, IUiDisplayInfo, IRoutingOutputs { 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 AppleTV(string key, string name, IrOutputPortController portCont) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs index 020eec7d..0a13434d 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/CiscoCodec/CiscoSparkCodec.cs @@ -28,9 +28,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco public class CiscoSparkCodec : VideoCodecBase, IHasCallHistory, IHasCallFavorites, IHasDirectory, IHasScheduleAwareness, IOccupancyStatusProvider, IHasCodecLayouts, IHasCodecSelfView, - ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, - IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute, IHasDoNotDisturbMode, - IHasHalfWakeMode + ICommunicationMonitor, IRouting, IHasCodecCameras, IHasCameraAutoMode, IHasCodecRoomPresets, IHasExternalSourceSwitching, IHasBranding, IHasCameraOff, IHasCameraMute { private bool _externalSourceChangeRequested; @@ -318,10 +316,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CameraIsMutedFeedback = CameraIsOffFeedback; 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"); Communication = comm; @@ -419,12 +413,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco CodecStatus.Status.Audio.Volume.ValueChangedAction = VolumeLevelFeedback.FireUpdate; CodecStatus.Status.Audio.VolumeMute.ValueChangedAction = MuteFeedback.FireUpdate; CodecStatus.Status.Audio.Microphones.Mute.ValueChangedAction = PrivacyModeIsOnFeedback.FireUpdate; - CodecStatus.Status.Standby.State.ValueChangedAction = new Action(() => - { - StandbyIsOnFeedback.FireUpdate(); - HalfWakeModeIsOnFeedback.FireUpdate(); - EnteringStandbyModeFeedback.FireUpdate(); - }); + CodecStatus.Status.Standby.State.ValueChangedAction = StandbyIsOnFeedback.FireUpdate; CodecStatus.Status.RoomAnalytics.PeoplePresence.ValueChangedAction = RoomIsOccupiedFeedback.FireUpdate; CodecStatus.Status.RoomAnalytics.PeopleCount.Current.ValueChangedAction = PeopleCountFeedback.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.PIPPosition.ValueChangedAction = ComputeSelfviewPipStatus; CodecStatus.Status.Video.Layout.LayoutFamily.Local.ValueChangedAction = ComputeLocalLayout; - CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = SharingContentIsOnFeedback.FireUpdate; - CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = FarEndIsSharingContentFeedback.FireUpdate; - CodecStatus.Status.Conference.DoNotDisturb.ValueChangedAction = DoNotDisturbModeIsOnFeedback.FireUpdate; + CodecStatus.Status.Conference.Presentation.Mode.ValueChangedAction = () => + { + SharingContentIsOnFeedback.FireUpdate(); + FarEndIsSharingContentFeedback.FireUpdate(); + }; try { @@ -588,7 +579,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco prefix + "/Status/Audio" + Delimiter + prefix + "/Status/Call" + Delimiter + prefix + "/Status/Conference/Presentation" + Delimiter + - prefix + "/Status/Conference/DoNotDisturb" + Delimiter + prefix + "/Status/Cameras/SpeakerTrack" + Delimiter + prefix + "/Status/RoomAnalytics" + Delimiter + prefix + "/Status/RoomPreset" + Delimiter + @@ -597,11 +587,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco prefix + "/Status/Video/Layout" + Delimiter + prefix + "/Status/Video/Input/MainVideoMute" + Delimiter + prefix + "/Bookings" + Delimiter + + prefix + "/Event/CallDisconnect" + Delimiter + prefix + "/Event/Bookings" + Delimiter + prefix + "/Event/CameraPresetListUpdated" + Delimiter + - prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter + - prefix + "/Event/CallDisconnect" + Delimiter; // Keep CallDisconnect last to detect when feedback registration completes correctly - + prefix + "/Event/UserInterface/Presentation/ExternalSource/Selected/SourceIdentifier" + Delimiter; } #endregion @@ -1510,50 +1499,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco 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); - - 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()); - } } /// @@ -2127,47 +2073,6 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Cisco else 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); } } - } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecLayouts.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecLayouts.cs index a8805a21..ef0bf2bd 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecLayouts.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasCodecLayouts.cs @@ -6,6 +6,8 @@ using Crestron.SimplSharp; using PepperDash.Essentials.Core; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Devices.Common.VideoCodec { /// @@ -25,7 +27,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec /// public interface IHasZoomRoomLayouts : IHasCodecLayouts { - event EventHandler AvailableLayoutsChanged; + event EventHandler LayoutInfoChanged; 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 @@ -45,6 +47,17 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec public class LayoutInfoChangedEventArgs : EventArgs { + [JsonProperty("availableLayouts", NullValueHandling = NullValueHandling.Ignore)] 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; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingInfo.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingInfo.cs index 0720b319..0d304028 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingInfo.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingInfo.cs @@ -24,24 +24,27 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces /// public class MeetingInfo { - [JsonProperty("id")] + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] public string Id { get; private set; } - [JsonProperty("name")] + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; private set; } - [JsonProperty("host")] + [JsonProperty("host", NullValueHandling = NullValueHandling.Ignore)] public string Host { get; private set; } - [JsonProperty("password")] + [JsonProperty("password", NullValueHandling = NullValueHandling.Ignore)] public string Password { get; private set; } - [JsonProperty("shareStatus")] + [JsonProperty("shareStatus", NullValueHandling = NullValueHandling.Ignore)] public string ShareStatus { get; private set; } - [JsonProperty("isHost")] + [JsonProperty("isHost", NullValueHandling = NullValueHandling.Ignore)] public Boolean IsHost { get; private set; } - [JsonProperty("isSharingMeeting")] + [JsonProperty("isSharingMeeting", NullValueHandling = NullValueHandling.Ignore)] public Boolean IsSharingMeeting { get; private set; } - [JsonProperty("waitingForHost")] + [JsonProperty("waitingForHost", NullValueHandling = NullValueHandling.Ignore)] 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; Name = name; @@ -51,6 +54,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces IsHost = isHost; IsSharingMeeting = isSharingMeeting; WaitingForHost = waitingForHost; + IsLocked = isLocked; } } diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingLock.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingLock.cs new file mode 100644 index 00000000..97fcb725 --- /dev/null +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingLock.cs @@ -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(); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingRecording.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingRecording.cs new file mode 100644 index 00000000..771a0865 --- /dev/null +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasMeetingRecording.cs @@ -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(); + } +} \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasParticipants.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasParticipants.cs index 409ccd89..11c5f147 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasParticipants.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/IHasParticipants.cs @@ -12,6 +12,18 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces public interface IHasParticipants { CodecParticipants Participants { get; } + + /// + /// Removes the participant from the meeting + /// + /// + void RemoveParticipant(int userId); + + /// + /// Sets the participant as the new host + /// + /// + void SetParticipantAsHost(int userId); } /// @@ -29,6 +41,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.Interfaces /// public interface IHasParticipantAudioMute : IHasParticipantVideoMute { + /// + /// Mute audio of all participants + /// + void MuteAudioForAllParticipants(); + void MuteAudioForParticipant(int userId); void UnmuteAudioForParticipant(int userId); void ToggleAudioForParticipant(int userId); diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/iVideoCodecInfo.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/iVideoCodecInfo.cs index 902dd68f..6eee454f 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/iVideoCodecInfo.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/Interfaces/iVideoCodecInfo.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Crestron.SimplSharp; +using Newtonsoft.Json; + namespace PepperDash.Essentials.Devices.Common.Codec { /// @@ -19,12 +21,19 @@ namespace PepperDash.Essentials.Devices.Common.Codec /// public abstract class VideoCodecInfo { + [JsonProperty("multiSiteOptionIsEnabled", NullValueHandling = NullValueHandling.Ignore)] public abstract bool MultiSiteOptionIsEnabled { get; } + [JsonProperty("ipAddress", NullValueHandling = NullValueHandling.Ignore)] public abstract string IpAddress { get; } + [JsonProperty("sipPhoneNumber", NullValueHandling = NullValueHandling.Ignore)] public abstract string SipPhoneNumber { get; } + [JsonProperty("e164Alias", NullValueHandling = NullValueHandling.Ignore)] public abstract string E164Alias { get; } + [JsonProperty("h323Id", NullValueHandling = NullValueHandling.Ignore)] public abstract string H323Id { get; } + [JsonProperty("sipUri", NullValueHandling = NullValueHandling.Ignore)] public abstract string SipUri { get; } + [JsonProperty("autoAnswerEnabled", NullValueHandling = NullValueHandling.Ignore)] public abstract bool AutoAnswerEnabled { get; } } } \ No newline at end of file diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs index 26ed54bb..cd70119f 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/VideoCodecBase.cs @@ -41,6 +41,9 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec SharingSourceFeedback = new StringFeedback(SharingSourceFeedbackFunc); SharingContentIsOnFeedback = new BoolFeedback(SharingContentIsOnFeedbackFunc); + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + MeetingsToDisplayFeedback = new IntFeedback(() => MeetingsToDisplay); + InputPorts = new RoutingPortCollection(); OutputPorts = new RoutingPortCollection(); @@ -298,6 +301,11 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec } LinkVideoCodecToApi(codec, trilist, joinMap); + + trilist.OnlineStatusChange += (device, args) => + { + if (!args.DeviceOnLine) return; + }; } /// @@ -546,6 +554,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec 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) @@ -777,7 +794,22 @@ ScreenIndexIsPinnedTo: {8} (a{17}) 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) { @@ -785,22 +817,58 @@ ScreenIndexIsPinnedTo: {8} (a{17}) _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); trilist.SetString(joinMap.Schedule.JoinNumber, meetingsData); 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 meetings) { - const int maxMeetings = 3; + // TODO [ ] hotfix/videocodecbase-max-meeting-xsig-set + //const int _meetingsToDisplay = 3; const int maxDigitals = 2; const int maxStrings = 7; const int offset = maxDigitals + maxStrings; - var digitalIndex = maxStrings * maxMeetings; //15 + var digitalIndex = maxStrings * _meetingsToDisplay; //15 var stringIndex = 0; var meetingIndex = 0; - var tokenArray = new XSigToken[maxMeetings * offset]; + var tokenArray = new XSigToken[_meetingsToDisplay * offset]; /* * Digitals * IsJoinable - 1 @@ -823,7 +891,7 @@ ScreenIndexIsPinnedTo: {8} (a{17}) if (meeting.StartTime < currentTime && meeting.EndTime < currentTime) continue; - if (meetingIndex >= maxMeetings * offset) + if (meetingIndex >= _meetingsToDisplay * offset) { Debug.Console(2, this, "Max Meetings reached"); break; @@ -848,10 +916,10 @@ ScreenIndexIsPinnedTo: {8} (a{17}) stringIndex += maxStrings; } - while (meetingIndex < maxMeetings * offset) + while (meetingIndex < _meetingsToDisplay * offset) { Debug.Console(2, this, "Clearing unused data. Meeting Index: {0} MaxMeetings * Offset: {1}", - meetingIndex, maxMeetings * offset); + meetingIndex, _meetingsToDisplay * offset); //digitals tokenArray[digitalIndex] = new XSigDigitalToken(digitalIndex + 1, false); @@ -901,6 +969,16 @@ ScreenIndexIsPinnedTo: {8} (a{17}) 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) @@ -982,6 +1060,15 @@ ScreenIndexIsPinnedTo: {8} (a{17}) 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() @@ -1249,6 +1336,15 @@ ScreenIndexIsPinnedTo: {8} (a{17}) trilist.UShortOutput[joinMap.CameraPresetSelect.JoinNumber].UShortValue, String.Empty); 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 presets) diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs index e6efd063..f6355d63 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ResponseObjects.cs @@ -618,13 +618,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom private bool _can_Switch_Speaker_View; private bool _can_Switch_Wall_View; 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_Last_Page; private string _video_type; 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"); + } + } + } + /// /// [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 emailRequired { 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 diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs index 32a24a28..8fc40f29 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoom.cs @@ -26,7 +26,8 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom IRouting, IHasScheduleAwareness, IHasCodecCameras, IHasParticipants, IHasCameraOff, IHasCameraMute, IHasCameraAutoMode, IHasFarEndContentStatus, IHasSelfviewPosition, IHasPhoneDialing, IHasZoomRoomLayouts, IHasParticipantPinUnpin, - IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo, IHasPresentationOnlyMeeting + IHasParticipantAudioMute, IHasSelfviewSize, IPasswordPrompt, IHasStartMeeting, IHasMeetingInfo, IHasPresentationOnlyMeeting, + IHasMeetingLock, IHasMeetingRecording { private const long MeetingRefreshTimer = 60000; public uint DefaultMeetingDurationMin { get; private set; } @@ -147,6 +148,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom ContentSwappedWithThumbnailFeedback = new BoolFeedback(ContentSwappedWithThumbnailFeedbackFunc); NumberOfScreensFeedback = new IntFeedback(NumberOfScreensFeedbackFunc); + + MeetingIsLockedFeedback = new BoolFeedback(() => Configuration.Call.Lock.Enable ); + + MeetingIsRecordingFeedback = new BoolFeedback(() => Status.Call.CallRecordInfo.meetingIsBeingRecorded ); } public CommunicationGather PortGather { get; private set; } @@ -499,19 +504,19 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { var sharingStatus = GetSharingStatus(); - MeetingInfo = new MeetingInfo("", "", "", "", sharingStatus, GetIsHostMyself(), true, false); + MeetingInfo = new MeetingInfo("", "", "", "", sharingStatus, GetIsHostMyself(), true, false, MeetingIsLockedFeedback.BoolValue); return; } 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; } catch (Exception e) { Debug.Console(1, this, "Error processing state property update. {0}", e.Message); 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": { ContentSwappedWithThumbnailFeedback.FireUpdate(); + OnLayoutInfoChanged(); break; } case "Style": { LocalLayoutFeedback.FireUpdate(); + OnLayoutInfoChanged(); break; } 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 Configuration.Client.Call.Layout.PropertyChanged += (o, a) => { @@ -613,11 +640,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom case "ShareThumb": { ContentSwappedWithThumbnailFeedback.FireUpdate(); + OnLayoutInfoChanged(); break; } case "Style": { LocalLayoutFeedback.FireUpdate(); + OnLayoutInfoChanged(); break; } } @@ -634,13 +663,31 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Status.Call.PropertyChanged += (o, a) => { - if (a.PropertyName == "Info") + switch(a.PropertyName) + { + case "Info": { Debug.Console(1, this, "Updating Call Status"); UpdateCallStatus(); + break; } + + case "Status": + { + UpdateCallStatus(); + break; + } + } }; + Status.Call.CallRecordInfo.PropertyChanged += (o, a) => + { + if (a.PropertyName == "meetingIsBeingRecorded") + { + MeetingIsRecordingFeedback.FireUpdate(); + } + }; + Status.Sharing.PropertyChanged += (o, a) => { switch (a.PropertyName) @@ -663,7 +710,15 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom return; } // 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; break; } @@ -714,13 +769,13 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom LayoutViewIsOnLastPageFeedback.FireUpdate(); break; } - //case "video_type": - // { - // It appears as though the actual value we want to watch is Configuration.Call.Layout.Style - // LocalLayoutFeedback.FireUpdate(); - // break; - // } + case "can_Switch_Floating_Share_Content": + { + CanSwapContentWithThumbnailFeedback.FireUpdate(); + break; + } } + OnLayoutInfoChanged(); }; Status.NumberOfScreens.PropertyChanged += (o, a) => @@ -1244,7 +1299,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Participants.CurrentParticipants = participants; // 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; PrintCurrentCallParticipants(); @@ -1306,11 +1370,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom var codecBookings = JsonConvert.DeserializeObject>( responseObj.ToString()); - if (codecBookings != null && codecBookings.Count > 0) - { - CodecSchedule.Meetings = zCommand.GetGenericMeetingsFromBookingResult( - codecBookings, CodecSchedule.MeetingWarningMinutes); - } + if (codecBookings != null && codecBookings.Count > 0) + { + CodecSchedule.Meetings = zCommand.GetGenericMeetingsFromBookingResult( + codecBookings, CodecSchedule.MeetingWarningMinutes); + } + else + { + //need to clear the list if it's empty + CodecSchedule.Meetings = new List(); + } break; } @@ -1441,21 +1510,21 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom { Status.NeedWaitForHost = JsonConvert.DeserializeObject(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 (MeetingInfo == null) { MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "", - GetSharingStatus(), false, false, true); + GetSharingStatus(), false, false, true, MeetingIsLockedFeedback.BoolValue); UpdateCallStatus(); break; } MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "", - GetSharingStatus(), false, false, true); + GetSharingStatus(), false, false, true, MeetingIsLockedFeedback.BoolValue); UpdateCallStatus(); @@ -1465,12 +1534,12 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom if (MeetingInfo == null) { MeetingInfo = new MeetingInfo("Waiting For Host", "Waiting For Host", "Waiting For Host", "", - GetSharingStatus(), false, false, false); + GetSharingStatus(), false, false, false, MeetingIsLockedFeedback.BoolValue); break; } MeetingInfo = new MeetingInfo(MeetingInfo.Id, MeetingInfo.Name, MeetingInfo.Host, MeetingInfo.Password, - GetSharingStatus(), GetIsHostMyself(), false, false); + GetSharingStatus(), GetIsHostMyself(), false, false, MeetingIsLockedFeedback.BoolValue); break; } @@ -1554,7 +1623,7 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom if (result.Success) { - MeetingInfo = new MeetingInfo("", "", "", "", "", true, true, MeetingInfo.WaitingForHost); + MeetingInfo = new MeetingInfo("", "", "", "", "", true, true, MeetingInfo.WaitingForHost, MeetingIsLockedFeedback.BoolValue); break; } @@ -1899,6 +1968,22 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom GetSharingStatus(), GetIsHostMyself(), !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 ); } @@ -2127,16 +2212,16 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom var layoutsCodec = this as IHasZoomRoomLayouts; if (layoutsCodec != null) { - layoutsCodec.AvailableLayoutsChanged += (o, a) => + layoutsCodec.LayoutInfoChanged += (o, a) => { - trilist.SetBool(joinMap.LayoutGalleryIsAvailable.JoinNumber, zConfiguration.eLayoutStyle.Gallery - == - (a.AvailableLayouts & - zConfiguration.eLayoutStyle.Gallery)); - trilist.SetBool(joinMap.LayoutSpeakerIsAvailable.JoinNumber, zConfiguration.eLayoutStyle.Speaker - == - (a.AvailableLayouts & - zConfiguration.eLayoutStyle.Speaker)); + trilist.SetBool(joinMap.LayoutGalleryIsAvailable.JoinNumber, + zConfiguration.eLayoutStyle.Gallery == (a.AvailableLayouts & zConfiguration.eLayoutStyle.Gallery)); + + trilist.SetBool(joinMap.LayoutSpeakerIsAvailable.JoinNumber, + zConfiguration.eLayoutStyle.Speaker == (a.AvailableLayouts & zConfiguration.eLayoutStyle.Speaker)); + + + trilist.SetBool(joinMap.LayoutStripIsAvailable.JoinNumber, 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); } - // TODO: #714 [ ] LinkZoomRoomToApi >> layoutSizeCoodec var layoutSizeCodec = this as IHasSelfviewSize; if (layoutSizeCodec != null) { @@ -2213,6 +2297,75 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom 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) => { if (!args.DeviceOnLine) return; @@ -2329,6 +2482,56 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom } } + /// + /// Invites contacts to a new meeting for a specified duration + /// + /// + /// + public void InviteContactsToNewMeeting(List 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()); + } + + /// + /// Invites contacts to an existing meeting + /// + /// + public void InviteContactsToExistingMeeting(List 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()); + } + /// /// 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 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 #region IHasParticipantAudioMute Members + public void MuteAudioForAllParticipants() + { + SendText(string.Format("zCommand Call MuteAll Mute: on")); + } + public void MuteAudioForParticipant(int 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 - public event EventHandler AvailableLayoutsChanged; + public event EventHandler LayoutInfoChanged; private Func LayoutViewIsOnFirstPageFeedbackFunc { @@ -2831,15 +3049,26 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Debug.Console(1, this, "availablelayouts: {0}", availableLayouts); - var handler = AvailableLayoutsChanged; - if (handler != null) - { - handler(this, new LayoutInfoChangedEventArgs() {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() { SendText("zStatus Call Layout"); @@ -3029,7 +3258,63 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom } #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 + } /// /// Zoom Room specific info object @@ -3042,8 +3327,10 @@ namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom Configuration = configuration; } + [JsonIgnore] public ZoomRoomStatus Status { get; private set; } - public ZoomRoomConfiguration Configuration { get; private set; } + [JsonIgnore] + public ZoomRoomConfiguration Configuration { get; private set; } public override bool AutoAnswerEnabled { diff --git a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomJoinMap.cs b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomJoinMap.cs index f70c48bf..b977cfe3 100644 --- a/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomJoinMap.cs +++ b/essentials-framework/Essentials Devices Common/Essentials Devices Common/VideoCodec/ZoomRoom/ZoomRoomJoinMap.cs @@ -1,301 +1,496 @@ -using System; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.Bridges.JoinMaps; - -namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom -{ - public class ZoomRoomJoinMap : VideoCodecControllerJoinMap - { - #region Digital - - [JoinName("CanSwapContentWithThumbnail")] - public JoinDataComplete CanSwapContentWithThumbnail = new JoinDataComplete( - new JoinData - { - JoinNumber = 206, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "FB Indicates if content can be swapped with thumbnail", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("SwapContentWithThumbnail")] - public JoinDataComplete SwapContentWithThumbnail = new JoinDataComplete( - new JoinData - { - JoinNumber = 206, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Pulse to swap content with thumbnail. FB reports current state", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("GetAvailableLayouts")] - public JoinDataComplete GetAvailableLayouts = new JoinDataComplete( - new JoinData - { - JoinNumber = 215, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Gets the available layouts. Will update the LayoutXXXXXIsAvailbale signals.", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("LayoutIsOnFirstPage")] - public JoinDataComplete LayoutIsOnFirstPage = new JoinDataComplete( - new JoinData - { - JoinNumber = 216, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Indicates if layout is on first page", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("LayoutIsOnLastPage")] - public JoinDataComplete LayoutIsOnLastPage = new JoinDataComplete( - new JoinData - { - JoinNumber = 217, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Indicates if layout is on first page", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("LayoutTurnToNextPage")] - public JoinDataComplete LayoutTurnToNextPage = new JoinDataComplete( - new JoinData - { - JoinNumber = 216, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Turns layout view to next page", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("LayoutTurnToPreviousPage")] - public JoinDataComplete LayoutTurnToPreviousPage = new JoinDataComplete( - new JoinData - { - JoinNumber = 217, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Turns layout view to previous page", - JoinCapabilities = eJoinCapabilities.FromSIMPL, - JoinType = eJoinType.Digital - }); - - [JoinName("LayoutGalleryIsAvailable")] - public JoinDataComplete LayoutGalleryIsAvailable = new JoinDataComplete( - new JoinData - { - JoinNumber = 221, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "FB Indicates if layout 'Gallery' is available", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.DigitalSerial - }); - - [JoinName("LayoutSpeakerIsAvailable")] - public JoinDataComplete LayoutSpeakerIsAvailable = new JoinDataComplete( - new JoinData - { - JoinNumber = 222, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "FB Indicates if layout 'Speaker' is available", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.DigitalSerial - }); - - [JoinName("LayoutStripIsAvailable")] - public JoinDataComplete LayoutStripIsAvailable = new JoinDataComplete( - new JoinData - { - JoinNumber = 223, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "FB Indicates if layout 'Strip' is available", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.DigitalSerial - }); - - [JoinName("LayoutShareAllIsAvailable")] - public JoinDataComplete LayoutShareAllIsAvailable = new JoinDataComplete( - new JoinData - { - JoinNumber = 224, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "FB Indicates if layout 'ShareAll' is available", - JoinCapabilities = eJoinCapabilities.ToSIMPL, - JoinType = eJoinType.DigitalSerial - }); - - // TODO: #714 [ ] JoinMap >> SelfivewPipSizeToggle - [JoinName("SelfviewPipSizeToggle")] - public JoinDataComplete SelfviewPipSizeToggle = new JoinDataComplete( - new JoinData - { - JoinNumber = 231, - JoinSpan = 1 - }, - new JoinMetadata - { - Description = "Toggles the selfview pip size, (aka layout size)", - JoinCapabilities = eJoinCapabilities.ToFromSIMPL, - 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 - - [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) - { - } - } +using System; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Bridges.JoinMaps; + +namespace PepperDash.Essentials.Devices.Common.VideoCodec.ZoomRoom +{ + public class ZoomRoomJoinMap : VideoCodecControllerJoinMap + { + #region Digital + + // TODO [ ] Issue #868 + [JoinName("ShowPasswordPrompt")] + public JoinDataComplete ShowPasswordPrompt = new JoinDataComplete( + new JoinData + { + JoinNumber = 6, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates to show the password prompt", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + // TODO [ ] Issue #868 + [JoinName("PasswordIncorrect")] + public JoinDataComplete PasswordIncorrect = new JoinDataComplete( + new JoinData + { + JoinNumber = 7, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates the password entered is incorrect", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + // TODO [ ] Issue #868 + [JoinName("PassowrdLoginFailed")] + public JoinDataComplete PasswordLoginFailed = new JoinDataComplete( + new JoinData + { + JoinNumber = 8, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates the password entered is incorrect", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + // TODO [ ] Issue #868 + [JoinName("WaitingForHost")] + public JoinDataComplete WaitingForHost = new JoinDataComplete( + new JoinData + { + JoinNumber = 9, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates system is waiting for host", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + // TODO [ ] Issue #868 + [JoinName("IsHost")] + public JoinDataComplete IsHost = new JoinDataComplete( + new JoinData + { + JoinNumber = 10, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates system is the host", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + // TODO [ ] Issue #868 + [JoinName("StartMeetingNow")] + public JoinDataComplete StartMeetingNow = new JoinDataComplete( + new JoinData + { + JoinNumber = 25, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates the password prompt is active", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + // TODO [ ] Issue #868 + [JoinName("ShareOnlyMeeting")] + public JoinDataComplete ShareOnlyMeeting = new JoinDataComplete( + new JoinData + { + JoinNumber = 26, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Triggers a share only meeting, feedback indicates the current meeting is share only", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + // TODO [ ] Issue #868 + [JoinName("StartNormalMeetingFromSharingOnlyMeeting")] + public JoinDataComplete StartNormalMeetingFromSharingOnlyMeeting = new JoinDataComplete( + new JoinData + { + JoinNumber = 27, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Starts a normal meeting from a share only meeting", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("CanSwapContentWithThumbnail")] + public JoinDataComplete CanSwapContentWithThumbnail = new JoinDataComplete( + new JoinData + { + JoinNumber = 206, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates if content can be swapped with thumbnail", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("SwapContentWithThumbnail")] + public JoinDataComplete SwapContentWithThumbnail = new JoinDataComplete( + new JoinData + { + JoinNumber = 206, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Pulse to swap content with thumbnail. FB reports current state", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("GetAvailableLayouts")] + public JoinDataComplete GetAvailableLayouts = new JoinDataComplete( + new JoinData + { + JoinNumber = 215, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Gets the available layouts. Will update the LayoutXXXXXIsAvailbale signals.", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("LayoutIsOnFirstPage")] + public JoinDataComplete LayoutIsOnFirstPage = new JoinDataComplete( + new JoinData + { + JoinNumber = 216, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Indicates if layout is on first page", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("LayoutIsOnLastPage")] + public JoinDataComplete LayoutIsOnLastPage = new JoinDataComplete( + new JoinData + { + JoinNumber = 217, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Indicates if layout is on first page", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("LayoutTurnToNextPage")] + public JoinDataComplete LayoutTurnToNextPage = new JoinDataComplete( + new JoinData + { + JoinNumber = 216, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Turns layout view to next page", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("LayoutTurnToPreviousPage")] + public JoinDataComplete LayoutTurnToPreviousPage = new JoinDataComplete( + new JoinData + { + JoinNumber = 217, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Turns layout view to previous page", + JoinCapabilities = eJoinCapabilities.FromSIMPL, + JoinType = eJoinType.Digital + }); + + [JoinName("LayoutGalleryIsAvailable")] + public JoinDataComplete LayoutGalleryIsAvailable = new JoinDataComplete( + new JoinData + { + JoinNumber = 221, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates if layout 'Gallery' is available", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.DigitalSerial + }); + + [JoinName("LayoutSpeakerIsAvailable")] + public JoinDataComplete LayoutSpeakerIsAvailable = new JoinDataComplete( + new JoinData + { + JoinNumber = 222, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates if layout 'Speaker' is available", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.DigitalSerial + }); + + [JoinName("LayoutStripIsAvailable")] + public JoinDataComplete LayoutStripIsAvailable = new JoinDataComplete( + new JoinData + { + JoinNumber = 223, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates if layout 'Strip' is available", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.DigitalSerial + }); + + [JoinName("LayoutShareAllIsAvailable")] + public JoinDataComplete LayoutShareAllIsAvailable = new JoinDataComplete( + new JoinData + { + JoinNumber = 224, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "FB Indicates if layout 'ShareAll' is available", + JoinCapabilities = eJoinCapabilities.ToSIMPL, + JoinType = eJoinType.DigitalSerial + }); + + // TODO: #714 [ ] JoinMap >> SelfivewPipSizeToggle + [JoinName("SelfviewPipSizeToggle")] + public JoinDataComplete SelfviewPipSizeToggle = new JoinDataComplete( + new JoinData + { + JoinNumber = 231, + JoinSpan = 1 + }, + new JoinMetadata + { + Description = "Toggles the selfview pip size, (aka layout size)", + JoinCapabilities = eJoinCapabilities.ToFromSIMPL, + 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) + { + } + } } \ No newline at end of file