using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using PepperDash.Core; using PepperDash.Core.Logging; using PepperDash.Essentials.AppServer; using PepperDash.Essentials.AppServer.Messengers; using PepperDash.Essentials.Core; using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.CrestronIO; using PepperDash.Essentials.Core.DeviceTypeInterfaces; using PepperDash.Essentials.Core.Lighting; using PepperDash.Essentials.Core.Shades; using PepperDash.Essentials.Devices.Common.AudioCodec; using PepperDash.Essentials.Devices.Common.Cameras; using PepperDash.Essentials.Devices.Common.Room; using PepperDash.Essentials.Devices.Common.VideoCodec; using PepperDash.Essentials.Room.Config; using PepperDash.Essentials.WebSocketServer; using System; using System.Collections.Generic; using System.Linq; using IShades = PepperDash.Essentials.Core.Shades.IShades; using ShadeBase = PepperDash.Essentials.Devices.Common.Shades.ShadeBase; namespace PepperDash.Essentials.RoomBridges { public class MobileControlEssentialsRoomBridge : MobileControlBridgeBase { private List _touchPanelTokens = new List(); public IEssentialsRoom Room { get; private set; } public string DefaultRoomKey { get; private set; } /// /// /// public override string RoomName { get { return Room.Name; } } public override string RoomKey { get { return Room.Key; } } public MobileControlEssentialsRoomBridge(IEssentialsRoom room) : this($"mobileControlBridge-{room.Key}", room.Key, room) { Room = room; } public MobileControlEssentialsRoomBridge(string key, string roomKey, IEssentialsRoom room) : base(key, $"/room/{room.Key}", room as Device) { DefaultRoomKey = roomKey; AddPreActivationAction(GetRoom); } protected override void RegisterActions() { // we add actions to the messaging system with a path, and a related action. Custom action // content objects can be handled in the controller's LineReceived method - and perhaps other // sub-controller parsing could be attached to these classes, so that the systemController // doesn't need to know about everything. this.LogInformation("Registering Actions with AppServer"); AddAction("/promptForCode", (id, content) => OnUserPromptedForCode()); AddAction("/clientJoined", (id, content) => OnClientJoined()); AddAction("/touchPanels", (id, content) => OnTouchPanelsUpdated(content)); AddAction($"/userApp", (id, content) => OnUserAppUpdated(content)); AddAction("/userCode", (id, content) => { var msg = content.ToObject(); SetUserCode(msg.UserCode, msg.QrChecksum ?? string.Empty); }); // Source Changes and room off AddAction("/status", (id, content) => { SendFullStatusForClientId(id, Room); }); if (Room is IRunRouteAction routeRoom) AddAction("/source", (id, content) => { var msg = content.ToObject(); this.LogVerbose("Received request to route to source: {sourceListKey} on list: {sourceList}", msg.SourceListItemKey, msg.SourceListKey); routeRoom.RunRouteAction(msg.SourceListItemKey, msg.SourceListKey); }); if (Room is IRunDirectRouteAction directRouteRoom) { AddAction("/directRoute", (id, content) => { var msg = content.ToObject(); this.LogVerbose("Running direct route from {sourceKey} to {destinationKey} with signal type {signalType}", msg.SourceKey, msg.DestinationKey, msg.SignalType); directRouteRoom.RunDirectRoute(msg.SourceKey, msg.DestinationKey, msg.SignalType); }); } if (Room is IRunDefaultPresentRoute defaultRoom) AddAction("/defaultsource", (id, content) => defaultRoom.RunDefaultPresentRoute()); if (Room is IHasCurrentSourceInfoChange sscRoom) sscRoom.CurrentSourceChange += Room_CurrentSingleSourceChange; if (Room is IEssentialsHuddleVtc1Room vtcRoom) { if (vtcRoom.ScheduleSource != null) { var key = vtcRoom.Key + "-" + Key; if (!AppServerController.CheckForDeviceMessenger(key)) { var scheduleMessenger = new IHasScheduleAwarenessMessenger(key, vtcRoom.ScheduleSource, $"/room/{vtcRoom.Key}"); AppServerController.AddDeviceMessenger(scheduleMessenger); } } vtcRoom.InCallFeedback.OutputChange += InCallFeedback_OutputChange; } if (Room is IPrivacy privacyRoom) { AddAction("/volumes/master/privacyMuteToggle", (id, content) => privacyRoom.PrivacyModeToggle()); privacyRoom.PrivacyModeIsOnFeedback.OutputChange += PrivacyModeIsOnFeedback_OutputChange; } if (Room is IRunDefaultCallRoute defCallRm) { AddAction("/activityVideo", (id, content) => defCallRm.RunDefaultCallRoute()); } Room.OnFeedback.OutputChange += OnFeedback_OutputChange; Room.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; Room.IsWarmingUpFeedback.OutputChange += IsWarmingUpFeedback_OutputChange; AddTechRoomActions(); if (Room is IHasCurrentVolumeControls volumeRoom) { volumeRoom.CurrentVolumeDeviceChange += Room_CurrentVolumeDeviceChange; if (volumeRoom.CurrentVolumeControls == null) return; AddAction("/volumes/master/level", (id, content) => { var msg = content.ToObject>(); if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) basicVolumeWithFeedback.SetVolume(msg.Value); }); AddAction("/volumes/master/muteToggle", (id, content) => volumeRoom.CurrentVolumeControls.MuteToggle()); AddAction("/volumes/master/muteOn", (id, content) => { if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) basicVolumeWithFeedback.MuteOn(); }); AddAction("/volumes/master/muteOff", (id, content) => { if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) basicVolumeWithFeedback.MuteOff(); }); AddAction("/volumes/master/volumeUp", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => { if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) { basicVolumeWithFeedback.VolumeUp(b); } } )); AddAction("/volumes/master/volumeDown", (id, content) => PressAndHoldHandler.HandlePressAndHold(DeviceKey, content, (b) => { if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback basicVolumeWithFeedback) { basicVolumeWithFeedback.VolumeDown(b); } } )); // Registers for initial volume events, if possible if (volumeRoom.CurrentVolumeControls is IBasicVolumeWithFeedback currentVolumeDevice) { this.LogVerbose("Registering for volume feedback events"); currentVolumeDevice.MuteFeedback.OutputChange += MuteFeedback_OutputChange; currentVolumeDevice.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; } } } private void OnTouchPanelsUpdated(JToken content) { var message = content.ToObject(); _touchPanelTokens = message.TouchPanels; UpdateTouchPanelAppUrls(message.UserAppUrl); } private void UpdateTouchPanelAppUrls(string userAppUrl) { foreach (var tp in _touchPanelTokens) { var dev = DeviceManager.AllDevices.OfType().FirstOrDefault((tpc) => tpc.Key.Equals(tp.TouchpanelKey, StringComparison.InvariantCultureIgnoreCase)); if (dev == null) { continue; } //UpdateAppUrl($"{userAppUrl}?token={tp.Token}"); dev.SetAppUrl($"{userAppUrl}?token={tp.Token}"); } } private void OnUserAppUpdated(JToken content) { var message = content.ToObject(); Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Updating User App URL to {userAppUrl}. Full Message: {@message}", this, message.UserAppUrl, content); UpdateTouchPanelAppUrls(message.UserAppUrl); } private void InCallFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new RoomStateMessage { IsInCall = e.BoolValue }; PostStatusMessage(state); } private void GetRoom() { if (Room != null) { this.LogInformation("Room with key {key} already linked.", DefaultRoomKey); return; } if (!(DeviceManager.GetDeviceForKey(DefaultRoomKey) is IEssentialsRoom tempRoom)) { this.LogInformation("Room with key {key} not found or is not an Essentials Room", DefaultRoomKey); return; } Room = tempRoom; } protected override void UserCodeChange() { Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, "Server user code changed: {userCode}", this, UserCode); var qrUrl = string.Format("{0}/rooms/{1}/{3}/qr?x={2}", Parent?.Host, Parent?.SystemUuid, new Random().Next(), DefaultRoomKey); QrCodeUrl = qrUrl; this.LogDebug("Server user code changed: {userCode} - {qrUrl}", UserCode, qrUrl); OnUserCodeChanged(); } /* /// /// Override of base: calls base to add parent and then registers actions and events. /// /// public override void AddParent(MobileControlSystemController parent) { base.AddParent(parent); }*/ private void AddTechRoomActions() { if (!(Room is IEssentialsTechRoom techRoom)) { return; } AddAction("/roomPowerOn", (id, content) => techRoom.RoomPowerOn()); AddAction("/roomPowerOff", (id, content) => techRoom.RoomPowerOff()); } private void PrivacyModeIsOnFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new RoomStateMessage(); var volumes = new Dictionary { { "master", new Volume("master") { PrivacyMuted = e.BoolValue } } }; state.Volumes = volumes; PostStatusMessage(state); } /// /// /// /// /// private void IsSharingFeedback_OutputChange(object sender, FeedbackEventArgs e) { // sharing source string shareText; bool isSharing; if (Room is IHasCurrentSourceInfoChange srcInfoRoom && Room is IHasVideoCodec vcRoom && vcRoom.VideoCodec.SharingContentIsOnFeedback.BoolValue && srcInfoRoom.CurrentSourceInfo != null) { shareText = srcInfoRoom.CurrentSourceInfo.PreferredName; isSharing = true; } else { shareText = "None"; isSharing = false; } var state = new RoomStateMessage { Share = new ShareState { CurrentShareText = shareText, IsSharing = isSharing } }; PostStatusMessage(state); } /// /// /// /// /// private void IsWarmingUpFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new { isWarmingUp = e.BoolValue }; PostStatusMessage(JToken.FromObject(state)); } /// /// /// /// /// private void IsCoolingDownFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new { isCoolingDown = e.BoolValue }; PostStatusMessage(JToken.FromObject(state)); } /// /// /// /// /// private void OnFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new { isOn = e.BoolValue }; PostStatusMessage(JToken.FromObject(state)); } private void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e) { if (e.OldDev is IBasicVolumeWithFeedback) { var oldDev = e.OldDev as IBasicVolumeWithFeedback; oldDev.MuteFeedback.OutputChange -= MuteFeedback_OutputChange; oldDev.VolumeLevelFeedback.OutputChange -= VolumeLevelFeedback_OutputChange; } if (e.NewDev is IBasicVolumeWithFeedback) { var newDev = e.NewDev as IBasicVolumeWithFeedback; newDev.MuteFeedback.OutputChange += MuteFeedback_OutputChange; newDev.VolumeLevelFeedback.OutputChange += VolumeLevelFeedback_OutputChange; } } /// /// Event handler for mute changes /// private void MuteFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new RoomStateMessage(); var volumes = new Dictionary { { "master", new Volume("master", e.BoolValue) } }; state.Volumes = volumes; PostStatusMessage(state); } /// /// Handles Volume changes on room /// private void VolumeLevelFeedback_OutputChange(object sender, FeedbackEventArgs e) { var state = new { volumes = new Dictionary { { "master", new Volume("master", e.IntValue) } } }; PostStatusMessage(JToken.FromObject(state)); } private void Room_CurrentSingleSourceChange(SourceListItem info, ChangeType type) { /* Example message * {    "type":"/room/status",    "content": {      "selectedSourceKey": "off",    } } */ } /// /// Sends the full status of the room to the server /// /// private void SendFullStatusForClientId(string id, IEssentialsRoom room) { //Parent.SendMessageObject(GetFullStatus(room)); var message = GetFullStatusForClientId(room); if (message == null) { return; } PostStatusMessage(message, id); } /// /// Gets full room status /// /// The room to get status of /// The status response message private RoomStateMessage GetFullStatusForClientId(IEssentialsRoom room) { try { this.LogVerbose("GetFullStatus"); var sourceKey = room is IHasCurrentSourceInfoChange ? (room as IHasCurrentSourceInfoChange).CurrentSourceInfoKey : null; var volumes = new Dictionary(); if (room is IHasCurrentVolumeControls rmVc) { if (rmVc.CurrentVolumeControls is IBasicVolumeWithFeedback vc) { var volume = new Volume("master", vc.VolumeLevelFeedback.UShortValue, vc.MuteFeedback.BoolValue, "Volume", true, ""); if (room is IPrivacy privacyRoom) { volume.HasPrivacyMute = true; volume.PrivacyMuted = privacyRoom.PrivacyModeIsOnFeedback.BoolValue; } volumes.Add("master", volume); } } var state = new RoomStateMessage { Configuration = GetRoomConfiguration(room), ActivityMode = 1, IsOn = room.OnFeedback.BoolValue, SelectedSourceKey = sourceKey, Volumes = volumes, IsWarmingUp = room.IsWarmingUpFeedback.BoolValue, IsCoolingDown = room.IsCoolingDownFeedback.BoolValue }; if (room is IEssentialsHuddleVtc1Room vtcRoom) { state.IsInCall = vtcRoom.InCallFeedback.BoolValue; } return state; } catch (Exception ex) { Debug.LogMessage(ex, "Error getting full status", this); return null; } } /// /// Determines the configuration of the room and the details about the devices associated with the room /// /// private RoomConfiguration GetRoomConfiguration(IEssentialsRoom room) { try { var configuration = new RoomConfiguration { //ShutdownPromptSeconds = room.ShutdownPromptSeconds, TouchpanelKeys = DeviceManager.AllDevices. OfType() .Where((tp) => tp.DefaultRoomKey.Equals(room.Key, StringComparison.InvariantCultureIgnoreCase)) .Select(tp => tp.Key).ToList() }; try { var zrcTp = DeviceManager.AllDevices.OfType().SingleOrDefault((tp) => tp.ZoomRoomController); configuration.ZoomRoomControllerKey = zrcTp?.Key; } catch { configuration.ZoomRoomControllerKey = room.Key; } if (room is IHasCiscoNavigatorTouchpanel ciscoNavRoom) { Debug.LogMessage(Serilog.Events.LogEventLevel.Verbose, $"Setting CiscoNavigatorKey to: {ciscoNavRoom.CiscoNavigatorTouchpanelKey}", this); configuration.CiscoNavigatorKey = ciscoNavRoom.CiscoNavigatorTouchpanelKey; } // find the room combiner for this room by checking if the room is in the list of rooms for the room combiner var roomCombiner = DeviceManager.AllDevices.OfType().FirstOrDefault(); configuration.RoomCombinerKey = roomCombiner?.Key; if (room is IEssentialsRoomPropertiesConfig propertiesConfig) { configuration.HelpMessage = propertiesConfig.PropertiesConfig.HelpMessageForDisplay; } if (room is IEssentialsHuddleSpaceRoom huddleRoom && !string.IsNullOrEmpty(huddleRoom.PropertiesConfig.HelpMessageForDisplay)) { this.LogVerbose("Getting huddle room config"); configuration.HelpMessage = huddleRoom.PropertiesConfig.HelpMessageForDisplay; configuration.UiBehavior = huddleRoom.PropertiesConfig.UiBehavior; configuration.DefaultPresentationSourceKey = huddleRoom.PropertiesConfig.DefaultSourceItem; } if (room is IEssentialsHuddleVtc1Room vtc1Room && !string.IsNullOrEmpty(vtc1Room.PropertiesConfig.HelpMessageForDisplay)) { this.LogVerbose("Getting vtc room config"); configuration.HelpMessage = vtc1Room.PropertiesConfig.HelpMessageForDisplay; configuration.UiBehavior = vtc1Room.PropertiesConfig.UiBehavior; configuration.DefaultPresentationSourceKey = vtc1Room.PropertiesConfig.DefaultSourceItem; } if (room is IEssentialsTechRoom techRoom && !string.IsNullOrEmpty(techRoom.PropertiesConfig.HelpMessage)) { this.LogVerbose("Getting tech room config"); configuration.HelpMessage = techRoom.PropertiesConfig.HelpMessage; } if (room is IHasVideoCodec vcRoom) { if (vcRoom.VideoCodec != null) { this.LogVerbose("Getting codec config"); var type = vcRoom.VideoCodec.GetType(); configuration.HasVideoConferencing = true; configuration.VideoCodecKey = vcRoom.VideoCodec.Key; configuration.VideoCodecIsZoomRoom = type.Name.Equals("ZoomRoom", StringComparison.InvariantCultureIgnoreCase); } } ; if (room is IHasAudioCodec acRoom) { if (acRoom.AudioCodec != null) { this.LogVerbose("Getting audio codec config"); configuration.HasAudioConferencing = true; configuration.AudioCodecKey = acRoom.AudioCodec.Key; } } if (room is IHasMatrixRouting matrixRoutingRoom) { this.LogVerbose("Getting matrix routing config"); configuration.MatrixRoutingKey = matrixRoutingRoom.MatrixRoutingDeviceKey; configuration.EndpointKeys = matrixRoutingRoom.EndpointKeys; } if (room is IEnvironmentalControls envRoom) { this.LogVerbose("Getting environmental controls config. RoomHasEnvironmentalControls: {hasEnvironmentalControls}", envRoom.HasEnvironmentalControlDevices); configuration.HasEnvironmentalControls = envRoom.HasEnvironmentalControlDevices; if (envRoom.HasEnvironmentalControlDevices) { this.LogVerbose("Room Has {count} Environmental Control Devices.", envRoom.EnvironmentalControlDevices.Count); foreach (var dev in envRoom.EnvironmentalControlDevices) { this.LogVerbose("Adding environmental device: {key}", dev.Key); eEnvironmentalDeviceTypes type = eEnvironmentalDeviceTypes.None; if (dev is ILightingScenes) { type = eEnvironmentalDeviceTypes.Lighting; } else if (dev is ShadeBase || dev is IShadesOpenCloseStop || dev is IShadesOpenClosePreset) { type = eEnvironmentalDeviceTypes.Shade; } else if (dev is IShades) { type = eEnvironmentalDeviceTypes.ShadeController; } else if (dev is ISwitchedOutput) { type = eEnvironmentalDeviceTypes.Relay; } this.LogVerbose("Environmental Device Type: {type}", type); var envDevice = new EnvironmentalDeviceConfiguration(dev.Key, type); configuration.EnvironmentalDevices.Add(envDevice); } } else { this.LogVerbose("Room Has No Environmental Control Devices"); } } if (room is IHasDefaultDisplay defDisplayRoom) { this.LogVerbose("Getting default display config"); configuration.DefaultDisplayKey = defDisplayRoom.DefaultDisplay.Key; configuration.Destinations.Add(eSourceListItemDestinationTypes.defaultDisplay, defDisplayRoom.DefaultDisplay.Key); } if (room is IHasMultipleDisplays multiDisplayRoom) { this.LogVerbose("Getting multiple display config"); if (multiDisplayRoom.Displays == null) { this.LogVerbose("Displays collection is null"); } else { this.LogVerbose("Displays collection exists"); configuration.Destinations = multiDisplayRoom.Displays.ToDictionary(kv => kv.Key, kv => kv.Value.Key); } } if (room is IHasAccessoryDevices accRoom) { Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Getting accessory devices config", this); if (accRoom.AccessoryDeviceKeys == null) { Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Accessory devices collection is null", this); } else { Debug.LogMessage(Serilog.Events.LogEventLevel.Information, "Accessory devices collection exists", this); configuration.AccessoryDeviceKeys = accRoom.AccessoryDeviceKeys; } } var sourceList = ConfigReader.ConfigObject.GetSourceListForKey(room.SourceListKey); if (sourceList != null) { this.LogVerbose("Getting source list config"); configuration.SourceList = sourceList; configuration.HasRoutingControls = true; foreach (var source in sourceList) { if (source.Value.SourceDevice is Devices.Common.IRSetTopBoxBase) { configuration.HasSetTopBoxControls = true; continue; } else if (source.Value.SourceDevice is CameraBase) { configuration.HasCameraControls = true; continue; } } } var destinationList = ConfigReader.ConfigObject.GetDestinationListForKey(room.DestinationListKey); if (destinationList != null) { configuration.DestinationList = destinationList; } var audioControlPointList = ConfigReader.ConfigObject.GetAudioControlPointListForKey(room.AudioControlPointListKey); if (audioControlPointList != null) { configuration.AudioControlPointList = audioControlPointList; } var cameraList = ConfigReader.ConfigObject.GetCameraListForKey(room.CameraListKey); if (cameraList != null) { configuration.CameraList = cameraList; } return configuration; } catch (Exception ex) { Debug.LogMessage(ex, "Exception getting room configuration"); return new RoomConfiguration(); } } } public class RoomStateMessage : DeviceStateMessageBase { [JsonProperty("configuration", NullValueHandling = NullValueHandling.Ignore)] public RoomConfiguration Configuration { get; set; } [JsonProperty("activityMode", NullValueHandling = NullValueHandling.Ignore)] public int? ActivityMode { get; set; } [JsonProperty("advancedSharingActive", NullValueHandling = NullValueHandling.Ignore)] public bool? AdvancedSharingActive { get; set; } [JsonProperty("isOn", NullValueHandling = NullValueHandling.Ignore)] public bool? IsOn { get; set; } [JsonProperty("isWarmingUp", NullValueHandling = NullValueHandling.Ignore)] public bool? IsWarmingUp { get; set; } [JsonProperty("isCoolingDown", NullValueHandling = NullValueHandling.Ignore)] public bool? IsCoolingDown { get; set; } [JsonProperty("selectedSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string SelectedSourceKey { get; set; } [JsonProperty("share", NullValueHandling = NullValueHandling.Ignore)] public ShareState Share { get; set; } [JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)] public Dictionary Volumes { get; set; } [JsonProperty("isInCall", NullValueHandling = NullValueHandling.Ignore)] public bool? IsInCall { get; set; } } public class ShareState { [JsonProperty("currentShareText", NullValueHandling = NullValueHandling.Ignore)] public string CurrentShareText { get; set; } [JsonProperty("enabled", NullValueHandling = NullValueHandling.Ignore)] public bool? Enabled { get; set; } [JsonProperty("isSharing", NullValueHandling = NullValueHandling.Ignore)] public bool? IsSharing { get; set; } } /// /// Represents the capabilities of the room and the associated device info /// public class RoomConfiguration { //[JsonProperty("shutdownPromptSeconds", NullValueHandling = NullValueHandling.Ignore)] //public int? ShutdownPromptSeconds { get; set; } [JsonProperty("hasVideoConferencing", NullValueHandling = NullValueHandling.Ignore)] public bool? HasVideoConferencing { get; set; } [JsonProperty("videoCodecIsZoomRoom", NullValueHandling = NullValueHandling.Ignore)] public bool? VideoCodecIsZoomRoom { get; set; } [JsonProperty("hasAudioConferencing", NullValueHandling = NullValueHandling.Ignore)] public bool? HasAudioConferencing { get; set; } [JsonProperty("hasEnvironmentalControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasEnvironmentalControls { get; set; } [JsonProperty("hasCameraControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasCameraControls { get; set; } [JsonProperty("hasSetTopBoxControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasSetTopBoxControls { get; set; } [JsonProperty("hasRoutingControls", NullValueHandling = NullValueHandling.Ignore)] public bool? HasRoutingControls { get; set; } [JsonProperty("touchpanelKeys", NullValueHandling = NullValueHandling.Ignore)] public List TouchpanelKeys { get; set; } [JsonProperty("zoomRoomControllerKey", NullValueHandling = NullValueHandling.Ignore)] public string ZoomRoomControllerKey { get; set; } [JsonProperty("ciscoNavigatorKey", NullValueHandling = NullValueHandling.Ignore)] public string CiscoNavigatorKey { get; set; } [JsonProperty("videoCodecKey", NullValueHandling = NullValueHandling.Ignore)] public string VideoCodecKey { get; set; } [JsonProperty("audioCodecKey", NullValueHandling = NullValueHandling.Ignore)] public string AudioCodecKey { get; set; } [JsonProperty("matrixRoutingKey", NullValueHandling = NullValueHandling.Ignore)] public string MatrixRoutingKey { get; set; } [JsonProperty("endpointKeys", NullValueHandling = NullValueHandling.Ignore)] public List EndpointKeys { get; set; } [JsonProperty("accessoryDeviceKeys", NullValueHandling = NullValueHandling.Ignore)] public List AccessoryDeviceKeys { get; set; } [JsonProperty("defaultDisplayKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultDisplayKey { get; set; } [JsonProperty("destinations", NullValueHandling = NullValueHandling.Ignore)] public Dictionary Destinations { get; set; } [JsonProperty("environmentalDevices", NullValueHandling = NullValueHandling.Ignore)] public List EnvironmentalDevices { get; set; } [JsonProperty("sourceList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary SourceList { get; set; } [JsonProperty("destinationList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary DestinationList { get; set; } [JsonProperty("audioControlPointList", NullValueHandling = NullValueHandling.Ignore)] public AudioControlPointListItem AudioControlPointList { get; set; } [JsonProperty("cameraList", NullValueHandling = NullValueHandling.Ignore)] public Dictionary CameraList { get; set; } [JsonProperty("defaultPresentationSourceKey", NullValueHandling = NullValueHandling.Ignore)] public string DefaultPresentationSourceKey { get; set; } [JsonProperty("helpMessage", NullValueHandling = NullValueHandling.Ignore)] public string HelpMessage { get; set; } [JsonProperty("techPassword", NullValueHandling = NullValueHandling.Ignore)] public string TechPassword { get; set; } [JsonProperty("uiBehavior", NullValueHandling = NullValueHandling.Ignore)] public EssentialsRoomUiBehaviorConfig UiBehavior { get; set; } [JsonProperty("supportsAdvancedSharing", NullValueHandling = NullValueHandling.Ignore)] public bool? SupportsAdvancedSharing { get; set; } [JsonProperty("userCanChangeShareMode", NullValueHandling = NullValueHandling.Ignore)] public bool? UserCanChangeShareMode { get; set; } [JsonProperty("roomCombinerKey", NullValueHandling = NullValueHandling.Ignore)] public string RoomCombinerKey { get; set; } public RoomConfiguration() { Destinations = new Dictionary(); EnvironmentalDevices = new List(); SourceList = new Dictionary(); TouchpanelKeys = new List(); } } public class EnvironmentalDeviceConfiguration { [JsonProperty("deviceKey", NullValueHandling = NullValueHandling.Ignore)] public string DeviceKey { get; private set; } [JsonConverter(typeof(StringEnumConverter))] [JsonProperty("deviceType", NullValueHandling = NullValueHandling.Ignore)] public eEnvironmentalDeviceTypes DeviceType { get; private set; } public EnvironmentalDeviceConfiguration(string key, eEnvironmentalDeviceTypes type) { DeviceKey = key; DeviceType = type; } } public enum eEnvironmentalDeviceTypes { None, Lighting, Shade, ShadeController, Relay, } public class ApiTouchPanelToken { [JsonProperty("touchPanels", NullValueHandling = NullValueHandling.Ignore)] public List TouchPanels { get; set; } = new List(); [JsonProperty("userAppUrl", NullValueHandling = NullValueHandling.Ignore)] public string UserAppUrl { get; set; } = ""; } #if SERIES3 public class SourceSelectMessageContent { public string SourceListItem { get; set; } public string SourceListKey { get; set; } } public class DirectRoute { public string SourceKey { get; set; } public string DestinationKey { get; set; } } /// /// /// /// public delegate void PressAndHoldAction(bool b); #endif }