Mega refactor in progress

This commit is contained in:
Neil Dorin
2019-10-23 22:29:04 -06:00
parent 407a354cfe
commit 13132c29fc
38 changed files with 1068 additions and 1369 deletions

View File

@@ -19,42 +19,3 @@ namespace PepperDash.Essentials.Room.Cotija
}
}
namespace PepperDash.Essentials
{
/// <summary>
/// For rooms with a single presentation source, change event
/// </summary>
public interface IHasCurrentSourceInfoChange
{
string CurrentSourceInfoKey { get; }
SourceListItem CurrentSourceInfo { get; }
event SourceInfoChangeHandler CurrentSingleSourceChange;
}
/// <summary>
/// For rooms with routing
/// </summary>
public interface IRunRouteAction
{
void RunRouteAction(string routeKey);
void RunRouteAction(string routeKey, Action successCallback);
}
/// <summary>
/// For rooms that default presentation only routing
/// </summary>
public interface IRunDefaultPresentRoute
{
bool RunDefaultPresentRoute();
}
/// <summary>
/// For rooms that have default presentation and calling routes
/// </summary>
public interface IRunDefaultCallRoute : IRunDefaultPresentRoute
{
bool RunDefaultCallRoute();
}
}

View File

@@ -93,7 +93,7 @@ namespace PepperDash.Essentials
var sscRoom = Room as IHasCurrentSourceInfoChange;
if(sscRoom != null)
sscRoom.CurrentSingleSourceChange += new SourceInfoChangeHandler(Room_CurrentSingleSourceChange);
sscRoom.CurrentSingleDisplaySourceChange += new SourceInfoChangeHandler(Room_CurrentSingleSourceChange);
var vcRoom = Room as IHasVideoCodec;
if (vcRoom != null && vcRoom.VideoCodec != null)

View File

@@ -1,119 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Room.Behaviours;
namespace PepperDash.Essentials.Fusion
{
/// <summary>
/// Handles mapping Fusion Custom Property values to system properties
/// </summary>
public class FusionCustomPropertiesBridge
{
/// <summary>
/// Evaluates the room info and custom properties from Fusion and updates the system properties aa needed
/// </summary>
/// <param name="roomInfo"></param>
public void EvaluateRoomInfo(string roomKey, RoomInformation roomInfo)
{
try
{
var reconfigurableDevices = DeviceManager.AllDevices.Where(d => d is ReconfigurableDevice);
foreach (var device in reconfigurableDevices)
{
// Get the current device config so new values can be overwritten over existing
var deviceConfig = (device as ReconfigurableDevice).Config;
if (device is RoomOnToDefaultSourceWhenOccupied)
{
Debug.Console(1, "Mapping Room on via Occupancy values from Fusion");
var devProps = JsonConvert.DeserializeObject<RoomOnToDefaultSourceWhenOccupiedConfig>(deviceConfig.Properties.ToString());
var enableFeature = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupied"));
if (enableFeature != null)
devProps.EnableRoomOnWhenOccupied = bool.Parse(enableFeature.CustomFieldValue);
var enableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedStartTime"));
if (enableTime != null)
devProps.OccupancyStartTime = enableTime.CustomFieldValue;
var disableTime = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomOnWhenOccupiedEndTime"));
if (disableTime != null)
devProps.OccupancyEndTime = disableTime.CustomFieldValue;
var enableSunday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSun"));
if (enableSunday != null)
devProps.EnableSunday = bool.Parse(enableSunday.CustomFieldValue);
var enableMonday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedMon"));
if (enableMonday != null)
devProps.EnableMonday = bool.Parse(enableMonday.CustomFieldValue);
var enableTuesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedTue"));
if (enableTuesday != null)
devProps.EnableTuesday = bool.Parse(enableTuesday.CustomFieldValue);
var enableWednesday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedWed"));
if (enableWednesday != null)
devProps.EnableWednesday = bool.Parse(enableWednesday.CustomFieldValue);
var enableThursday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedThu"));
if (enableThursday != null)
devProps.EnableThursday = bool.Parse(enableThursday.CustomFieldValue);
var enableFriday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedFri"));
if (enableFriday != null)
devProps.EnableFriday = bool.Parse(enableFriday.CustomFieldValue);
var enableSaturday = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("EnRoomOnWhenOccupiedSat"));
if (enableSaturday != null)
devProps.EnableSaturday = bool.Parse(enableSaturday.CustomFieldValue);
deviceConfig.Properties = JToken.FromObject(devProps);
}
else if (device is EssentialsRoomBase)
{
// Set the room name
if (!string.IsNullOrEmpty(roomInfo.Name))
{
Debug.Console(1, "Current Room Name: {0}. New Room Name: {1}", deviceConfig.Name, roomInfo.Name);
// Set the name in config
deviceConfig.Name = roomInfo.Name;
Debug.Console(1, "Room Name Successfully Changed.");
}
// Set the help message
var helpMessage = roomInfo.FusionCustomProperties.FirstOrDefault(p => p.ID.Equals("RoomHelpMessage"));
if (helpMessage != null)
{
//Debug.Console(1, "Current Help Message: {0}. New Help Message: {1}", deviceConfig.Properties["help"]["message"].Value<string>(ToString()), helpMessage.CustomFieldValue);
deviceConfig.Properties["helpMessage"] = (string)helpMessage.CustomFieldValue;
}
}
// Set the config on the device
(device as ReconfigurableDevice).SetConfig(deviceConfig);
}
}
catch (Exception e)
{
Debug.Console(1, "FusionCustomPropetiesBridge: Error mapping properties: {0}", e);
}
}
}
}

View File

@@ -1,18 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Essentials.Fusion
{
public class ScheduleChangeEventArgs : EventArgs
{
public RoomSchedule Schedule { get; set; }
}
public class MeetingChangeEventArgs : EventArgs
{
public Event Meeting { get; set; }
}
}

View File

@@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using PepperDash.Core;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials.Fusion
{
/// <summary>
/// When created, runs progcomments on every slot and stores the program names in a list
/// </summary>
public class ProcessorProgReg
{
//public static Dictionary<int, ProcessorProgramItem> Programs { get; private set; }
public static Dictionary<int, ProcessorProgramItem> GetProcessorProgReg()
{
var programs = new Dictionary<int, ProcessorProgramItem>();
for (int i = 1; i <= Global.ControlSystem.NumProgramsSupported; i++)
{
string response = null;
var success = CrestronConsole.SendControlSystemCommand("progcomments:" + i, ref response);
var item = new ProcessorProgramItem();
if (!success)
item.Name = "Error: PROGCOMMENTS failed";
else
{
if (response.ToLower().Contains("bad or incomplete"))
item.Name = "";
else
{
var startPos = response.IndexOf("Program File");
var colonPos = response.IndexOf(":", startPos) + 1;
var endPos = response.IndexOf(CrestronEnvironment.NewLine, colonPos);
item.Name = response.Substring(colonPos, endPos - colonPos).Trim();
item.Exists = true;
if (item.Name.Contains(".dll"))
{
startPos = response.IndexOf("Compiler Revision");
colonPos = response.IndexOf(":", startPos) + 1;
endPos = response.IndexOf(CrestronEnvironment.NewLine, colonPos);
item.Name = item.Name + "_v" + response.Substring(colonPos, endPos - colonPos).Trim();
}
}
}
programs[i] = item;
Debug.Console(1, "Program {0}: {1}", i, item.Name);
}
return programs;
}
}
/// <summary>
/// Used in ProcessorProgReg
/// </summary>
public class ProcessorProgramItem
{
public bool Exists { get; set; }
public string Name { get; set; }
}
}

View File

@@ -1,499 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharpPro.Fusion;
using PepperDash.Core;
namespace PepperDash.Essentials.Fusion
{
// Helper Classes for GUIDs
/// <summary>
/// Stores GUIDs to be written to a file in NVRAM
/// </summary>
public class FusionRoomGuids
{
public string RoomName { get; set; }
public uint IpId { get; set; }
public string RoomGuid { get; set; }
public FusionOccupancySensorAsset OccupancyAsset { get; set; }
public Dictionary<int, FusionAsset> StaticAssets { get; set; }
public FusionRoomGuids()
{
StaticAssets = new Dictionary<int, FusionAsset>();
OccupancyAsset = new FusionOccupancySensorAsset();
}
public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary<int, FusionAsset> staticAssets)
{
RoomName = roomName;
IpId = ipId;
RoomGuid = roomGuid;
StaticAssets = staticAssets;
OccupancyAsset = new FusionOccupancySensorAsset();
}
public FusionRoomGuids(string roomName, uint ipId, string roomGuid, Dictionary<int, FusionAsset> staticAssets, FusionOccupancySensorAsset occAsset)
{
RoomName = roomName;
IpId = ipId;
RoomGuid = roomGuid;
StaticAssets = staticAssets;
OccupancyAsset = occAsset;
}
/// <summary>
/// Generates a new room GUID prefixed by the program slot number and NIC MAC address
/// </summary>
/// <param name="progSlot"></param>
/// <param name="mac"></param>
public string GenerateNewRoomGuid(uint progSlot, string mac)
{
Guid roomGuid = Guid.NewGuid();
return string.Format("{0}-{1}-{2}", progSlot, mac, roomGuid.ToString());
}
/// <summary>
/// Adds an asset to the StaticAssets collection and returns the new asset
/// </summary>
/// <param name="room"></param>
/// <param name="uid"></param>
/// <param name="assetName"></param>
/// <param name="type"></param>
/// <param name="instanceId"></param>
/// <returns></returns>
public FusionAsset AddStaticAsset(FusionRoom room, int uid, string assetName, string type, string instanceId)
{
var slotNum = GetNextAvailableAssetNumber(room);
Debug.Console(2, "Adding Fusion Asset: {0} of Type: {1} at Slot Number: {2} with GUID: {3}", assetName, type, slotNum, instanceId);
var tempAsset = new FusionAsset(slotNum, assetName, type, instanceId);
StaticAssets.Add(uid, tempAsset);
return tempAsset;
}
/// <summary>
/// Returns the next available slot number in the Fusion UserConfigurableAssetDetails collection
/// </summary>
/// <param name="room"></param>
/// <returns></returns>
public static uint GetNextAvailableAssetNumber(FusionRoom room)
{
uint slotNum = 0;
foreach (var item in room.UserConfigurableAssetDetails)
{
if(item.Number > slotNum)
slotNum = item.Number;
}
if (slotNum < 5)
{
slotNum = 5;
}
else
slotNum = slotNum + 1;
Debug.Console(2, "#Next available fusion asset number is: {0}", slotNum);
return slotNum;
}
}
public class FusionOccupancySensorAsset
{
// SlotNumber fixed at 4
public uint SlotNumber { get { return 4; } }
public string Name { get { return "Occupancy Sensor"; } }
public eAssetType Type { get; set; }
public string InstanceId { get; set; }
public FusionOccupancySensorAsset()
{
}
public FusionOccupancySensorAsset(eAssetType type)
{
Type = type;
InstanceId = Guid.NewGuid().ToString();
}
}
public class FusionAsset
{
public uint SlotNumber { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string InstanceId { get;set; }
public FusionAsset()
{
}
public FusionAsset(uint slotNum, string assetName, string type, string instanceId)
{
SlotNumber = slotNum;
Name = assetName;
Type = type;
if (string.IsNullOrEmpty(instanceId))
{
InstanceId = Guid.NewGuid().ToString();
}
else
{
InstanceId = instanceId;
}
}
}
//***************************************************************************************************
public class RoomSchedule
{
public List<Event> Meetings { get; set; }
public RoomSchedule()
{
Meetings = new List<Event>();
}
}
//****************************************************************************************************
// Helper Classes for XML API
/// <summary>
/// Data needed to request the local time from the Fusion server
/// </summary>
public class LocalTimeRequest
{
public string RequestID { get; set; }
}
/// <summary>
/// All the data needed for a full schedule request in a room
/// </summary>
/// //[XmlRoot(ElementName = "RequestSchedule")]
public class RequestSchedule
{
//[XmlElement(ElementName = "RequestID")]
public string RequestID { get; set; }
//[XmlElement(ElementName = "RoomID")]
public string RoomID { get; set; }
//[XmlElement(ElementName = "Start")]
public DateTime Start { get; set; }
//[XmlElement(ElementName = "HourSpan")]
public double HourSpan { get; set; }
public RequestSchedule(string requestID, string roomID)
{
RequestID = requestID;
RoomID = roomID;
Start = DateTime.Now;
HourSpan = 24;
}
}
//[XmlRoot(ElementName = "RequestAction")]
public class RequestAction
{
//[XmlElement(ElementName = "RequestID")]
public string RequestID { get; set; }
//[XmlElement(ElementName = "RoomID")]
public string RoomID { get; set; }
//[XmlElement(ElementName = "ActionID")]
public string ActionID { get; set; }
//[XmlElement(ElementName = "Parameters")]
public List<Parameter> Parameters { get; set; }
public RequestAction(string roomID, string actionID, List<Parameter> parameters)
{
RoomID = roomID;
ActionID = actionID;
Parameters = parameters;
}
}
//[XmlRoot(ElementName = "ActionResponse")]
public class ActionResponse
{
//[XmlElement(ElementName = "RequestID")]
public string RequestID { get; set; }
//[XmlElement(ElementName = "ActionID")]
public string ActionID { get; set; }
//[XmlElement(ElementName = "Parameters")]
public List<Parameter> Parameters { get; set; }
}
//[XmlRoot(ElementName = "Parameter")]
public class Parameter
{
//[XmlAttribute(AttributeName = "ID")]
public string ID { get; set; }
//[XmlAttribute(AttributeName = "Value")]
public string Value { get; set; }
}
////[XmlRoot(ElementName = "Parameters")]
//public class Parameters
//{
// //[XmlElement(ElementName = "Parameter")]
// public List<Parameter> Parameter { get; set; }
//}
/// <summary>
/// Data structure for a ScheduleResponse from Fusion
/// </summary>
/// //[XmlRoot(ElementName = "ScheduleResponse")]
public class ScheduleResponse
{
//[XmlElement(ElementName = "RequestID")]
public string RequestID { get; set; }
//[XmlElement(ElementName = "RoomID")]
public string RoomID { get; set; }
//[XmlElement(ElementName = "RoomName")]
public string RoomName { get; set; }
//[XmlElement("Event")]
public List<Event> Events { get; set; }
public ScheduleResponse()
{
Events = new List<Event>();
}
}
//[XmlRoot(ElementName = "Event")]
public class Event
{
//[XmlElement(ElementName = "MeetingID")]
public string MeetingID { get; set; }
//[XmlElement(ElementName = "RVMeetingID")]
public string RVMeetingID { get; set; }
//[XmlElement(ElementName = "Recurring")]
public string Recurring { get; set; }
//[XmlElement(ElementName = "InstanceID")]
public string InstanceID { get; set; }
//[XmlElement(ElementName = "dtStart")]
public DateTime dtStart { get; set; }
//[XmlElement(ElementName = "dtEnd")]
public DateTime dtEnd { get; set; }
//[XmlElement(ElementName = "Organizer")]
public string Organizer { get; set; }
//[XmlElement(ElementName = "Attendees")]
public Attendees Attendees { get; set; }
//[XmlElement(ElementName = "Resources")]
public Resources Resources { get; set; }
//[XmlElement(ElementName = "IsEvent")]
public string IsEvent { get; set; }
//[XmlElement(ElementName = "IsRoomViewMeeting")]
public string IsRoomViewMeeting { get; set; }
//[XmlElement(ElementName = "IsPrivate")]
public string IsPrivate { get; set; }
//[XmlElement(ElementName = "IsExchangePrivate")]
public string IsExchangePrivate { get; set; }
//[XmlElement(ElementName = "MeetingTypes")]
public MeetingTypes MeetingTypes { get; set; }
//[XmlElement(ElementName = "ParticipantCode")]
public string ParticipantCode { get; set; }
//[XmlElement(ElementName = "PhoneNo")]
public string PhoneNo { get; set; }
//[XmlElement(ElementName = "WelcomeMsg")]
public string WelcomeMsg { get; set; }
//[XmlElement(ElementName = "Subject")]
public string Subject { get; set; }
//[XmlElement(ElementName = "LiveMeeting")]
public LiveMeeting LiveMeeting { get; set; }
//[XmlElement(ElementName = "ShareDocPath")]
public string ShareDocPath { get; set; }
//[XmlElement(ElementName = "HaveAttendees")]
public string HaveAttendees { get; set; }
//[XmlElement(ElementName = "HaveResources")]
public string HaveResources { get; set; }
/// <summary>
/// Gets the duration of the meeting
/// </summary>
public string DurationInMinutes
{
get
{
string duration;
var timeSpan = dtEnd.Subtract(dtStart);
int hours = timeSpan.Hours;
double minutes = timeSpan.Minutes;
double roundedMinutes = Math.Round(minutes);
if (hours > 0)
{
duration = string.Format("{0} hours {1} minutes", hours, roundedMinutes);
}
else
{
duration = string.Format("{0} minutes", roundedMinutes);
}
return duration;
}
}
/// <summary>
/// Gets the remaining time in the meeting. Returns null if the meeting is not currently in progress.
/// </summary>
public string RemainingTime
{
get
{
var now = DateTime.Now;
string remainingTime;
if (GetInProgress())
{
var timeSpan = dtEnd.Subtract(now);
int hours = timeSpan.Hours;
double minutes = timeSpan.Minutes;
double roundedMinutes = Math.Round(minutes);
if (hours > 0)
{
remainingTime = string.Format("{0} hours {1} minutes", hours, roundedMinutes);
}
else
{
remainingTime = string.Format("{0} minutes", roundedMinutes);
}
return remainingTime;
}
else
return null;
}
}
/// <summary>
/// Indicates that the meeting is in progress
/// </summary>
public bool isInProgress
{
get
{
return GetInProgress();
}
}
/// <summary>
/// Determines if the meeting is in progress
/// </summary>
/// <returns>Returns true if in progress</returns>
bool GetInProgress()
{
var now = DateTime.Now;
if (now > dtStart && now < dtEnd)
{
return true;
}
else
return false;
}
}
//[XmlRoot(ElementName = "Resources")]
public class Resources
{
//[XmlElement(ElementName = "Rooms")]
public Rooms Rooms { get; set; }
}
//[XmlRoot(ElementName = "Rooms")]
public class Rooms
{
//[XmlElement(ElementName = "Room")]
public List<Room> Room { get; set; }
}
//[XmlRoot(ElementName = "Room")]
public class Room
{
//[XmlElement(ElementName = "Name")]
public string Name { get; set; }
//[XmlElement(ElementName = "ID")]
public string ID { get; set; }
//[XmlElement(ElementName = "MPType")]
public string MPType { get; set; }
}
//[XmlRoot(ElementName = "Attendees")]
public class Attendees
{
//[XmlElement(ElementName = "Required")]
public Required Required { get; set; }
//[XmlElement(ElementName = "Optional")]
public Optional Optional { get; set; }
}
//[XmlRoot(ElementName = "Required")]
public class Required
{
//[XmlElement(ElementName = "Attendee")]
public List<string> Attendee { get; set; }
}
//[XmlRoot(ElementName = "Optional")]
public class Optional
{
//[XmlElement(ElementName = "Attendee")]
public List<string> Attendee { get; set; }
}
//[XmlRoot(ElementName = "MeetingType")]
public class MeetingType
{
//[XmlAttribute(AttributeName = "ID")]
public string ID { get; set; }
//[XmlAttribute(AttributeName = "Value")]
public string Value { get; set; }
}
//[XmlRoot(ElementName = "MeetingTypes")]
public class MeetingTypes
{
//[XmlElement(ElementName = "MeetingType")]
public List<MeetingType> MeetingType { get; set; }
}
//[XmlRoot(ElementName = "LiveMeeting")]
public class LiveMeeting
{
//[XmlElement(ElementName = "URL")]
public string URL { get; set; }
//[XmlElement(ElementName = "ID")]
public string ID { get; set; }
//[XmlElement(ElementName = "Key")]
public string Key { get; set; }
//[XmlElement(ElementName = "Subject")]
public string Subject { get; set; }
}
//[XmlRoot(ElementName = "LiveMeetingURL")]
public class LiveMeetingURL
{
//[XmlElement(ElementName = "LiveMeeting")]
public LiveMeeting LiveMeeting { get; set; }
}
}

View File

@@ -14,6 +14,7 @@ using PepperDash.Core;
using PepperDash.Essentials;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Core.Fusion;
using PepperDash.Essentials.Devices.Common;
using PepperDash.Essentials.Devices.Common.Occupancy;
@@ -181,7 +182,7 @@ namespace PepperDash.Essentials.Fusion
// Moved to
CurrentRoomSourceNameSig = FusionRoom.CreateOffsetStringSig(84, "Display 1 - Current Source", eSigIoMask.InputSigOnly);
// Don't think we need to get current status of this as nothing should be alive yet.
(Room as EssentialsHuddleVtc1Room).CurrentSingleSourceChange += Room_CurrentSourceInfoChange;
(Room as EssentialsHuddleVtc1Room).CurrentSourceChange += Room_CurrentSourceInfoChange;
FusionRoom.SystemPowerOn.OutputSig.SetSigFalseAction((Room as EssentialsHuddleVtc1Room).PowerOnToDefaultOrLastSource);
@@ -220,7 +221,7 @@ namespace PepperDash.Essentials.Fusion
break;
}
var laptops = dict.Where(d => d.Value.SourceDevice is Laptop);
var laptops = dict.Where(d => d.Value.SourceDevice is Core.Devices.Laptop);
i = 1;
foreach (var kvp in laptops)
{

View File

@@ -173,16 +173,11 @@
<Compile Include="Devices\NUMERIC AppleTV.cs" />
<Compile Include="ControlSystem.cs" />
<Compile Include="Factory\UiDeviceFactory.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\EssentialsHuddleVtc1FusionController.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\FusionCustomPropertiesBridge.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\FusionEventHandlers.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\FusionProcessorQueries.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\FusionRviDataClasses.cs" />
<Compile Include="Fusion\EssentialsHuddleVtc1FusionController.cs" />
<Compile Include="REMOVE EssentialsApp.cs" />
<Compile Include="FOR REFERENCE UI\OTHER\Fusion\EssentialsHuddleSpaceFusionSystemControllerBase.cs" />
<Compile Include="HttpApiHandler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Room\Behaviours\RoomOnToDefaultSourceWhenOccupied.cs" />
<Compile Include="Room\Config\EssentialsDualDisplayRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsNDisplayRoomPropertiesConfig.cs" />
<Compile Include="Room\Config\DDVC01RoomPropertiesConfig.cs" />
<Compile Include="Room\Config\EssentialsPresentationPropertiesConfig.cs" />
@@ -206,10 +201,10 @@
<Compile Include="AppServer\RoomBridges\SourceDeviceMapDictionary.cs" />
<Compile Include="AppServer\Volumes.cs" />
<Compile Include="Room\Emergency\EsentialsRoomEmergencyContactClosure.cs" />
<Compile Include="Room\Types\EssentialsDualDisplayRoom.cs" />
<Compile Include="Room\Types\EssentialsHuddleVtc1Room.cs" />
<Compile Include="Room\Types\EssentialsNDisplayRoomBase.cs" />
<Compile Include="Room\Types\EssentialsPresentationRoom.cs" />
<Compile Include="Room\Types\EssentialsRoomBase.cs" />
<Compile Include="Room\Config\EssentialsRoomConfig.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\DevicePageControllerBase.cs" />
<Compile Include="FOR REFERENCE UI\PageControllers\PageControllerLaptop.cs" />
@@ -273,6 +268,9 @@
<Name>Essentials Devices Common</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="FOR REFERENCE UI\OTHER\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>

View File

@@ -1,526 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Scheduler;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common.Occupancy;
namespace PepperDash.Essentials.Room.Behaviours
{
/// <summary>
/// A device that when linked to a room can power the room on when enabled during scheduled hours.
/// </summary>
public class RoomOnToDefaultSourceWhenOccupied : ReconfigurableDevice
{
RoomOnToDefaultSourceWhenOccupiedConfig PropertiesConfig;
public bool FeatureEnabled { get; private set; }
public DateTime FeatureEnabledTime { get; private set; }
ScheduledEvent FeatureEnableEvent;
const string FeatureEnableEventName = "EnableRoomOnToDefaultSourceWhenOccupied";
public DateTime FeatureDisabledTime { get; private set; }
ScheduledEvent FeatureDisableEvent;
const string FeatureDisableEventName = "DisableRoomOnToDefaultSourceWhenOccupied";
ScheduledEventGroup FeatureEventGroup;
public EssentialsRoomBase Room { get; private set; }
private Fusion.EssentialsHuddleSpaceFusionSystemControllerBase FusionRoom;
public RoomOnToDefaultSourceWhenOccupied(DeviceConfig config) :
base (config)
{
PropertiesConfig = JsonConvert.DeserializeObject<RoomOnToDefaultSourceWhenOccupiedConfig>(config.Properties.ToString());
FeatureEventGroup = new ScheduledEventGroup(this.Key);
FeatureEventGroup.RetrieveAllEvents();
// Add to the global class for tracking
Scheduler.AddEventGroup(FeatureEventGroup);
AddPostActivationAction(() =>
{
// Subscribe to room event to know when RoomOccupancy is set and ready to be subscribed to
if (Room != null)
Room.RoomOccupancyIsSet += new EventHandler<EventArgs>(RoomOccupancyIsSet);
else
Debug.Console(1, this, "Room has no RoomOccupancy object set");
var fusionRoomKey = PropertiesConfig.RoomKey + "-fusion";
FusionRoom = DeviceManager.GetDeviceForKey(fusionRoomKey) as Fusion.EssentialsHuddleSpaceFusionSystemControllerBase;
if (FusionRoom == null)
Debug.Console(1, this, "Unable to get Fusion Room from Device Manager with key: {0}", fusionRoomKey);
});
}
public override bool CustomActivate()
{
SetUpDevice();
return base.CustomActivate();
}
/// <summary>
/// Sets up device based on config values
/// </summary>
void SetUpDevice()
{
Room = DeviceManager.GetDeviceForKey(PropertiesConfig.RoomKey) as EssentialsRoomBase;
if (Room != null)
{
try
{
FeatureEnabledTime = DateTime.Parse(PropertiesConfig.OccupancyStartTime);
if (FeatureEnabledTime != null)
{
Debug.Console(1, this, "Enabled Time: {0}", FeatureEnabledTime.ToString());
}
else
Debug.Console(1, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyStartTime);
}
catch (Exception e)
{
Debug.Console(1, this, "Unable to parse OccupancyStartTime property: {0} \n Error: {1}", PropertiesConfig.OccupancyStartTime, e);
}
try
{
FeatureDisabledTime = DateTime.Parse(PropertiesConfig.OccupancyEndTime);
if (FeatureDisabledTime != null)
{
Debug.Console(1, this, "Disabled Time: {0}", FeatureDisabledTime.ToString());
}
else
Debug.Console(1, this, "Unable to parse {0} to DateTime", PropertiesConfig.OccupancyEndTime);
}
catch (Exception e)
{
Debug.Console(1, this, "Unable to parse a DateTime config value \n Error: {1}", e);
}
if (!PropertiesConfig.EnableRoomOnWhenOccupied)
FeatureEventGroup.ClearAllEvents();
else
{
AddEnableEventToGroup();
AddDisableEventToGroup();
FeatureEventGroup.UserGroupCallBack += new ScheduledEventGroup.UserEventGroupCallBack(FeatureEventGroup_UserGroupCallBack);
FeatureEventGroup.EnableAllEvents();
}
FeatureEnabled = CheckIfFeatureShouldBeEnabled();
}
else
Debug.Console(1, this, "Unable to get room from Device Manager with key: {0}", PropertiesConfig.RoomKey);
}
protected override void CustomSetConfig(DeviceConfig config)
{
var newPropertiesConfig = JsonConvert.DeserializeObject<RoomOnToDefaultSourceWhenOccupiedConfig>(config.Properties.ToString());
if(newPropertiesConfig != null)
PropertiesConfig = newPropertiesConfig;
ConfigWriter.UpdateDeviceConfig(config);
SetUpDevice();
}
/// <summary>
/// Subscribe to feedback from RoomIsOccupiedFeedback on Room
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void RoomOccupancyIsSet(object sender, EventArgs e)
{
if (Room.RoomOccupancy != null)
{
Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange;
Room.RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += new EventHandler<FeedbackEventArgs>(RoomIsOccupiedFeedback_OutputChange);
Debug.Console(1, this, "Subscribed to RoomOccupancy status from: '{0}'", Room.Key);
}
}
void FeatureEventGroup_UserGroupCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type)
{
if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration)
{
if (SchEvent.Name == FeatureEnableEventName)
{
if (PropertiesConfig.EnableRoomOnWhenOccupied)
FeatureEnabled = true;
Debug.Console(1, this, "*****Feature Enabled by event.*****");
}
else if (SchEvent.Name == FeatureDisableEventName)
{
FeatureEnabled = false;
Debug.Console(1, this, "*****Feature Disabled by event.*****");
}
}
}
/// <summary>
/// Checks if the feature should be currently enabled. Used on startup if processor starts after start time but before end time
/// </summary>
/// <returns></returns>
bool CheckIfFeatureShouldBeEnabled()
{
bool enabled = false;
if(PropertiesConfig.EnableRoomOnWhenOccupied)
{
Debug.Console(1, this, "Current Time: {0} \n FeatureEnabledTime: {1} \n FeatureDisabledTime: {2}", DateTime.Now, FeatureEnabledTime, FeatureDisabledTime);
if (DateTime.Now.TimeOfDay.CompareTo(FeatureEnabledTime.TimeOfDay) >= 0 && FeatureDisabledTime.TimeOfDay.CompareTo(DateTime.Now.TimeOfDay) > 0)
{
if (SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(DateTime.Now, CalculateDaysOfWeekRecurrence()))
{
enabled = true;
}
}
}
if(enabled)
Debug.Console(1, this, "*****Feature Enabled*****");
else
Debug.Console(1, this, "*****Feature Disabled*****");
return enabled;
}
/// <summary>
/// Respond to Occupancy status event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void RoomIsOccupiedFeedback_OutputChange(object sender, FeedbackEventArgs e)
{
Debug.Console(1, this, "RoomIsOccupiedFeeback.OutputChange event fired. e.BoolValue: {0}", e.BoolValue);
if(e.BoolValue)
{
// Occupancy detected
if (FeatureEnabled)
{
// Check room power state first
if (!Room.OnFeedback.BoolValue)
{
Debug.Console(1, this, "Powering Room on to default source");
Room.RunDefaultPresentRoute();
}
}
}
}
void CreateEvent(ScheduledEvent schEvent, string name)
{
Debug.Console(1, this, "Adding Event: '{0}'", name);
// Create the event
if (schEvent == null)
schEvent = new ScheduledEvent(name, FeatureEventGroup);
// Set up its initial properties
if(!schEvent.Acknowledgeable)
schEvent.Acknowledgeable = true;
if(!schEvent.Persistent)
schEvent.Persistent = true;
schEvent.DateAndTime.SetFirstDayOfWeek(ScheduledEventCommon.eFirstDayOfWeek.Sunday);
// Set config driven properties
if (schEvent.Name == FeatureEnableEventName)
{
schEvent.Description = "Enables the RoomOnToDefaultSourceWhenOccupiedFeature";
var eventRecurrennce = CalculateDaysOfWeekRecurrence();
var eventTime = new DateTime();
// Check to make sure the date for this event is in the future
if (DateTime.Now.CompareTo(FeatureEnabledTime) > 0)
eventTime = FeatureEnabledTime.AddDays(1);
else
eventTime = FeatureEnabledTime;
Debug.Console(1, this, "eventTime (before recurrence check): {0}", eventTime);
// Check day of week against recurrence days and move date ahead as necessary to avoid throwing an exception by trying to set the event
// start date on a day of the week that doesn't match teh recurrence values
while(!SchedulerUtilities.CheckIfDayOfWeekMatchesRecurrenceDays(eventTime, eventRecurrennce))
{
eventTime = eventTime.AddDays(1);
Debug.Console(1, this, "eventTime does not fall on a recurrence weekday. eventTime: {0}", eventTime);
}
schEvent.DateAndTime.SetAbsoluteEventTime(eventTime);
Debug.Console(1, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString());
CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureEnabledTime, FeatureDisabledTime);
schEvent.Recurrence.Weekly(eventRecurrennce);
}
else if (schEvent.Name == FeatureDisableEventName)
{
schEvent.Description = "Disables the RoomOnToDefaultSourceWhenOccupiedFeature";
// Check to make sure the date for this event is in the future
if (DateTime.Now.CompareTo(FeatureDisabledTime) > 0)
schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime.AddDays(1));
else
schEvent.DateAndTime.SetAbsoluteEventTime(FeatureDisabledTime);
Debug.Console(1, this, "Event '{0}' Absolute time set to {1}", schEvent.Name, schEvent.DateAndTime.ToString());
CalculateAndSetAcknowledgeExpirationTimeout(schEvent, FeatureDisabledTime, FeatureEnabledTime);
schEvent.Recurrence.Daily();
}
}
void CalculateAndSetAcknowledgeExpirationTimeout(ScheduledEvent schEvent, DateTime time1, DateTime time2)
{
Debug.Console(1, this, "time1.Hour = {0}", time1.Hour);
Debug.Console(1, this, "time2.Hour = {0}", time2.Hour);
Debug.Console(1, this, "time1.Minute = {0}", time1.Minute);
Debug.Console(1, this, "time2.Minute = {0}", time2.Minute);
// Calculate the Acknowledge Expiration timer to be the time between the enable and dispable events, less one minute
var ackHours = time2.Hour - time1.Hour;
if(ackHours < 0)
ackHours = ackHours + 24;
var ackMinutes = time2.Minute - time1.Minute;
Debug.Console(1, this, "ackHours = {0}, ackMinutes = {1}", ackHours, ackMinutes);
var ackTotalMinutes = ((ackHours * 60) + ackMinutes) - 1;
var ackExpHour = ackTotalMinutes / 60;
var ackExpMinutes = ackTotalMinutes % 60;
Debug.Console(1, this, "Acknowledge Expiration Timeout: {0} hours, {1} minutes", ackExpHour, ackExpMinutes);
schEvent.AcknowledgeExpirationTimeout.Hour = (ushort)(ackHours);
schEvent.AcknowledgeExpirationTimeout.Minute = (ushort)(ackExpMinutes);
}
/// <summary>
/// Checks existing event to see if it matches the execution time
/// </summary>
/// <param name="existingEvent"></param>
/// <returns></returns>
bool CheckExistingEventTimeForMatch(ScheduledEvent existingEvent, DateTime newTime)
{
bool isMatch = true;
// Check to see if hour and minute match
if (existingEvent.DateAndTime.Hour != newTime.Hour || existingEvent.DateAndTime.Minute != newTime.Minute)
return false;
return isMatch;
}
/// <summary>
/// Checks existing event to see if it matches the recurrence days
/// </summary>
/// <param name="existingEvent"></param>
/// <param name="eWeekdays"></param>
/// <returns></returns>
bool CheckExistingEventRecurrenceForMatch(ScheduledEvent existingEvent, ScheduledEventCommon.eWeekDays eWeekdays)
{
bool isMatch = true;
// Check to see if recurrence matches
if (eWeekdays != existingEvent.Recurrence.RecurrenceDays)
return false;
return isMatch;
}
/// <summary>
/// Adds the Enable event to the local event group and sets its properties based on config
/// </summary>
void AddEnableEventToGroup()
{
if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureEnableEventName))
{
CreateEvent(FeatureEnableEvent, FeatureEnableEventName);
}
else
{
// Check if existing event has same time and recurrence as config values
FeatureEnableEvent = FeatureEventGroup.ScheduledEvents[FeatureEnableEventName];
Debug.Console(1, this, "Enable event already found in group");
// Check config times and days against DateAndTime of existing event. If different, delete existing event and create new event
if(!CheckExistingEventTimeForMatch(FeatureEnableEvent, FeatureEnabledTime) || !CheckExistingEventRecurrenceForMatch(FeatureEnableEvent, CalculateDaysOfWeekRecurrence()))
{
Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureEnableEvent.Name);
FeatureEventGroup.DeleteEvent(FeatureEnableEvent);
FeatureEnableEvent = null;
CreateEvent(FeatureEnableEvent, FeatureEnableEventName);
}
}
}
/// <summary>
/// Adds the Enable event to the local event group and sets its properties based on config
/// </summary>
void AddDisableEventToGroup()
{
if (!FeatureEventGroup.ScheduledEvents.ContainsKey(FeatureDisableEventName))
{
CreateEvent(FeatureDisableEvent, FeatureDisableEventName);
}
else
{
FeatureDisableEvent = FeatureEventGroup.ScheduledEvents[FeatureDisableEventName];
Debug.Console(1, this, "Disable event already found in group");
// Check config times against DateAndTime of existing event. If different, delete existing event and create new event
if(!CheckExistingEventTimeForMatch(FeatureDisableEvent, FeatureDisabledTime))
{
Debug.Console(1, this, "Existing event does not match new config properties. Deleting exisiting event: '{0}'", FeatureDisableEvent.Name);
FeatureEventGroup.DeleteEvent(FeatureDisableEvent);
FeatureDisableEvent = null;
CreateEvent(FeatureDisableEvent, FeatureDisableEventName);
}
}
}
/// <summary>
/// Calculates the correct bitfield enum value for the event recurrence based on the config values
/// </summary>
/// <returns></returns>
ScheduledEventCommon.eWeekDays CalculateDaysOfWeekRecurrence()
{
ScheduledEventCommon.eWeekDays value = new ScheduledEventCommon.eWeekDays();
if (PropertiesConfig.EnableSunday)
value = value | ScheduledEventCommon.eWeekDays.Sunday;
if (PropertiesConfig.EnableMonday)
value = value | ScheduledEventCommon.eWeekDays.Monday;
if (PropertiesConfig.EnableTuesday)
value = value | ScheduledEventCommon.eWeekDays.Tuesday;
if (PropertiesConfig.EnableWednesday)
value = value | ScheduledEventCommon.eWeekDays.Wednesday;
if (PropertiesConfig.EnableThursday)
value = value | ScheduledEventCommon.eWeekDays.Thursday;
if (PropertiesConfig.EnableFriday)
value = value | ScheduledEventCommon.eWeekDays.Friday;
if (PropertiesConfig.EnableSaturday)
value = value | ScheduledEventCommon.eWeekDays.Saturday;
return value;
}
/// <summary>
/// Callback for event that enables feature. Enables feature if config property is true
/// </summary>
/// <param name="SchEvent"></param>
/// <param name="type"></param>
void FeatureEnableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type)
{
if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration)
{
if(PropertiesConfig.EnableRoomOnWhenOccupied)
FeatureEnabled = true;
Debug.Console(1, this, "RoomOnToDefaultSourceWhenOccupied Feature Enabled.");
}
}
/// <summary>
/// Callback for event that enables feature. Disables feature
/// </summary>
/// <param name="SchEvent"></param>
/// <param name="type"></param>
void FeatureDisableEvent_UserCallBack(ScheduledEvent SchEvent, ScheduledEventCommon.eCallbackReason type)
{
if (type == ScheduledEventCommon.eCallbackReason.NormalExpiration)
{
FeatureEnabled = false;
Debug.Console(1, this, "RoomOnToDefaultSourceWhenOccupied Feature Disabled.");
}
}
}
public class RoomOnToDefaultSourceWhenOccupiedConfig
{
[JsonProperty("roomKey")]
public string RoomKey { get; set; }
[JsonProperty("enableRoomOnWhenOccupied")]
public bool EnableRoomOnWhenOccupied { get; set; }
[JsonProperty("occupancyStartTime")]
public string OccupancyStartTime { get; set; }
[JsonProperty("occupancyEndTime")]
public string OccupancyEndTime { get; set; }
[JsonProperty("enableSunday")]
public bool EnableSunday { get; set; }
[JsonProperty("enableMonday")]
public bool EnableMonday { get; set; }
[JsonProperty("enableTuesday")]
public bool EnableTuesday { get; set; }
[JsonProperty("enableWednesday")]
public bool EnableWednesday { get; set; }
[JsonProperty("enableThursday")]
public bool EnableThursday { get; set; }
[JsonProperty("enableFriday")]
public bool EnableFriday { get; set; }
[JsonProperty("enableSaturday")]
public bool EnableSaturday { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Room.Config
{
public class EssentialsDualDisplayRoomPropertiesConfig : EssentialsNDisplayRoomPropertiesConfig
{
public const string LeftDisplayId = "leftDisplay";
public const string RightDisplayId = "rightDisplay";
}
}

View File

@@ -8,19 +8,10 @@ using Newtonsoft.Json;
namespace PepperDash.Essentials.Room.Config
{
public class EssentialsHuddleVtc1PropertiesConfig : EssentialsRoomPropertiesConfig
public class EssentialsHuddleVtc1PropertiesConfig : EssentialsConferenceRoomPropertiesConfig
{
[JsonProperty("defaultDisplayKey")]
public string DefaultDisplayKey { get; set; }
[JsonProperty("defaultAudioKey")]
public string DefaultAudioKey { get; set; }
[JsonProperty("sourceListKey")]
public string SourceListKey { get; set; }
[JsonProperty("defaultSourceItem")]
public string DefaultSourceItem { get; set; }
[JsonProperty("videoCodecKey")]
public string VideoCodecKey { get; set; }
[JsonProperty("audioCodecKey")]
public string AudioCodecKey { get; set; }
}
}

View File

@@ -4,22 +4,27 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Essentials.Room.Config
{
/// <summary>
///
/// </summary>
public class EssentialsNDisplayRoomPropertiesConfig : EssentialsRoomPropertiesConfig
public class EssentialsNDisplayRoomPropertiesConfig : EssentialsConferenceRoomPropertiesConfig
{
[JsonProperty("defaultAudioBehavior")]
public string DefaultAudioBehavior { get; set; }
public string DefaultAudioKey { get; set; }
[JsonProperty("defaultVideoBehavior")]
public string DefaultVideoBehavior { get; set; }
[JsonProperty("displays")]
public Dictionary<string, string> Displays { get; set; }
public string SourceListKey { get; set; }
public EssentialsNDisplayRoomPropertiesConfig()
{
Displays = new Dictionary<string, string>();
}
}
}

View File

@@ -76,7 +76,7 @@ namespace PepperDash.Essentials.Room.Config
}
// Get the MicrophonePrivacy device from the device manager
var mP = (DeviceManager.GetDeviceForKey(props.MicrophonePrivacy.DeviceKey) as
PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController);
Core.Privacy.MicrophonePrivacyController);
// Set this room as the IPrivacy device
if (mP == null)
{
@@ -175,6 +175,25 @@ namespace PepperDash.Essentials.Room.Config
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; set; }
}
public class EssentialsAvRoomPropertiesConfig : EssentialsRoomPropertiesConfig
{
[JsonProperty("defaultAudioKey")]
public string DefaultAudioKey { get; set; }
[JsonProperty("sourceListKey")]
public string SourceListKey { get; set; }
[JsonProperty("defaultSourceItem")]
public string DefaultSourceItem { get; set; }
}
public class EssentialsConferenceRoomPropertiesConfig : EssentialsAvRoomPropertiesConfig
{
[JsonProperty("videoCodecKey")]
public string VideoCodecKey { get; set; }
[JsonProperty("audioCodecKey")]
public string AudioCodecKey { get; set; }
}
public class EssentialsEnvironmentPropertiesConfig
{
public bool Enabled { get; set; }

View File

@@ -12,15 +12,7 @@ using PepperDash.Essentials.Room.Config;
namespace PepperDash.Essentials.Room
{
public abstract class EssentialsRoomEmergencyBase : IKeyed
{
public string Key { get; private set; }
public EssentialsRoomEmergencyBase(string key)
{
Key = key;
}
}
public class EssentialsRoomEmergencyContactClosure : EssentialsRoomEmergencyBase

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Room.Config;
using PepperDash.Essentials.Devices.Common.Codec;
using PepperDash.Essentials.Devices.Common.VideoCodec;
using PepperDash.Essentials.Devices.Common.AudioCodec;
namespace PepperDash.Essentials.Room.Types
{
public class EssentialsDualDisplayRoom : EssentialsNDisplayRoomBase, IHasCurrentVolumeControls,
IRunRouteAction, IPrivacy, IPrivacy, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public EssentialsHuddleVtc1PropertiesConfig PropertiesConfig { get; private set; }
//************************
// Call-related stuff
public BoolFeedback InCallFeedback { get; private set; }
/// <summary>
/// States: 0 for on hook, 1 for video, 2 for audio, 3 for telekenesis
/// </summary>
public IntFeedback CallTypeFeedback { get; private set; }
/// <summary>
///
/// </summary>
public BoolFeedback PrivacyModeIsOnFeedback { get; private set; }
/// <summary>
/// When something in the room is sharing with the far end or through other means
/// </summary>
public BoolFeedback IsSharingFeedback { get; private set; }
IRoutingSinkWithSwitching LeftDisplay { get; private set; }
IRoutingSinkWithSwitching RightDisplay { get; private set; }
protected override Func<bool> OnFeedbackFunc
{
get
{
return () =>
{
var leftDisp = LeftDisplay as DisplayBase;
var rightDisp = RightDisplay as DisplayBase;
var val = leftDisp != null && leftDisp.CurrentSourceInfo != null
&& leftDisp.CurrentSourceInfo.Type == eSourceListItemType.Route
&& rightDisp != null && rightDisp.CurrentSourceInfo != null
&& rightDisp.CurrentSourceInfo.Type == eSourceListItemType.Route;
return val;
};
}
}
}
}

View File

@@ -16,7 +16,7 @@ namespace PepperDash.Essentials
public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute, IHasCurrentVolumeControls
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
public event SourceInfoChangeHandler CurrentSourceChange;
protected override Func<bool> OnFeedbackFunc
{
@@ -76,11 +76,6 @@ namespace PepperDash.Essentials
public bool ExcludeFromGlobalFunctions { get; set; }
/// <summary>
/// The config name of the source list
/// </summary>
public string SourceListKey { get; set; }
public string DefaultSourceItem { get; set; }
public ushort DefaultVolume { get; set; }
@@ -128,7 +123,7 @@ namespace PepperDash.Essentials
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
var handler = CurrentSourceChange;
// remove from in-use tracker, if so equipped
if(_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
@@ -251,7 +246,7 @@ namespace PepperDash.Essentials
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
this.LogoUrl = PropertiesConfig.Logo.GetUrl();
this.SourceListKey = PropertiesConfig.SourceListKey;

View File

@@ -20,7 +20,7 @@ namespace PepperDash.Essentials
IPrivacy, IHasCurrentVolumeControls, IRunRouteAction, IRunDefaultCallRoute, IHasVideoCodec, IHasAudioCodec
{
public event EventHandler<VolumeDeviceChangeEventArgs> CurrentVolumeDeviceChange;
public event SourceInfoChangeHandler CurrentSingleSourceChange;
public event SourceInfoChangeHandler CurrentSourceChange;
//************************
@@ -166,7 +166,7 @@ namespace PepperDash.Essentials
{
if (value == _CurrentSourceInfo) return;
var handler = CurrentSingleSourceChange;
var handler = CurrentSourceChange;
// remove from in-use tracker, if so equipped
if(_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control");
@@ -330,7 +330,7 @@ namespace PepperDash.Essentials
// Add Occupancy object from config
if (PropertiesConfig.Occupancy != null)
this.SetRoomOccupancy(DeviceManager.GetDeviceForKey(PropertiesConfig.Occupancy.DeviceKey) as
PepperDash.Essentials.Devices.Common.Occupancy.IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
IOccupancyStatusProvider, PropertiesConfig.Occupancy.TimeoutMinutes);
this.LogoUrl = PropertiesConfig.Logo.GetUrl();
this.SourceListKey = PropertiesConfig.SourceListKey;

View File

@@ -19,13 +19,10 @@ namespace PepperDash.Essentials.Room.Types
/// </summary>
public abstract class EssentialsNDisplayRoomBase : EssentialsRoomBase
{
public event SourceInfoChangeHandler CurrentSingleSourceChange;
//public event SourceInfoChangeHandler CurrentSingleSourceChange;
public Dictionary<string, IRoutingSinkWithSwitching> Displays { get; protected set; }
protected override Func<bool> IsWarmingFeedbackFunc { get { return () => false; ; } }
protected override Func<bool> IsCoolingFeedbackFunc { get { return () => false; } }
public EssentialsNDisplayRoomBase(DeviceConfig config)
: base (config)
{

View File

@@ -1,297 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.Scheduler;
using PepperDash.Core;
using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config;
using PepperDash.Essentials.Core.Devices;
using PepperDash.Essentials.Devices.Common.Occupancy;
namespace PepperDash.Essentials
{
/// <summary>
///
/// </summary>
public abstract class EssentialsRoomBase : ReconfigurableDevice
{
/// <summary>
///
/// </summary>
public BoolFeedback OnFeedback { get; private set; }
/// <summary>
/// Fires when the RoomOccupancy object is set
/// </summary>
public event EventHandler<EventArgs> RoomOccupancyIsSet;
public BoolFeedback IsWarmingUpFeedback { get; private set; }
public BoolFeedback IsCoolingDownFeedback { get; private set; }
public IOccupancyStatusProvider RoomOccupancy { get; private set; }
public bool OccupancyStatusProviderIsRemote { get; private set; }
protected abstract Func<bool> IsWarmingFeedbackFunc { get; }
protected abstract Func<bool> IsCoolingFeedbackFunc { get; }
/// <summary>
/// Timer used for informing the UIs of a shutdown
/// </summary>
public SecondsCountdownTimer ShutdownPromptTimer { get; private set; }
/// <summary>
///
/// </summary>
public int ShutdownPromptSeconds { get; set; }
public int ShutdownVacancySeconds { get; set; }
public eShutdownType ShutdownType { get; private set; }
public PepperDash.Essentials.Room.EssentialsRoomEmergencyBase Emergency { get; set; }
public PepperDash.Essentials.Devices.Common.Microphones.MicrophonePrivacyController MicrophonePrivacy { get; set; }
public string LogoUrl { get; set; }
protected SecondsCountdownTimer RoomVacancyShutdownTimer { get; private set; }
public eVacancyMode VacancyMode { get; private set; }
/// <summary>
/// Seconds after vacancy prompt is displayed until shutdown
/// </summary>
protected int RoomVacancyShutdownSeconds;
/// <summary>
/// Seconds after vacancy detected until prompt is displayed
/// </summary>
protected int RoomVacancyShutdownPromptSeconds;
/// <summary>
///
/// </summary>
protected abstract Func<bool> OnFeedbackFunc { get; }
protected Dictionary<IBasicVolumeWithFeedback, uint> SavedVolumeLevels = new Dictionary<IBasicVolumeWithFeedback, uint>();
/// <summary>
/// When volume control devices change, should we zero the one that we are leaving?
/// </summary>
public bool ZeroVolumeWhenSwtichingVolumeDevices { get; private set; }
public EssentialsRoomBase(DeviceConfig config)
: base(config)
{
// Setup the ShutdownPromptTimer
ShutdownPromptTimer = new SecondsCountdownTimer(Key + "-offTimer");
ShutdownPromptTimer.IsRunningFeedback.OutputChange += (o, a) =>
{
if (!ShutdownPromptTimer.IsRunningFeedback.BoolValue)
ShutdownType = eShutdownType.None;
};
ShutdownPromptTimer.HasFinished += (o, a) => Shutdown(); // Shutdown is triggered
ShutdownPromptSeconds = 60;
ShutdownVacancySeconds = 120;
ShutdownType = eShutdownType.None;
RoomVacancyShutdownTimer = new SecondsCountdownTimer(Key + "-vacancyOffTimer");
//RoomVacancyShutdownTimer.IsRunningFeedback.OutputChange += (o, a) =>
//{
// if (!RoomVacancyShutdownTimer.IsRunningFeedback.BoolValue)
// ShutdownType = ShutdownType.Vacancy;
//};
RoomVacancyShutdownTimer.HasFinished += new EventHandler<EventArgs>(RoomVacancyShutdownPromptTimer_HasFinished); // Shutdown is triggered
RoomVacancyShutdownPromptSeconds = 1500; // 25 min to prompt warning
RoomVacancyShutdownSeconds = 240; // 4 min after prompt will trigger shutdown prompt
VacancyMode = eVacancyMode.None;
OnFeedback = new BoolFeedback(OnFeedbackFunc);
IsWarmingUpFeedback = new BoolFeedback(IsWarmingFeedbackFunc);
IsCoolingDownFeedback = new BoolFeedback(IsCoolingFeedbackFunc);
AddPostActivationAction(() =>
{
if (RoomOccupancy != null)
OnRoomOccupancyIsSet();
});
}
void RoomVacancyShutdownPromptTimer_HasFinished(object sender, EventArgs e)
{
switch (VacancyMode)
{
case eVacancyMode.None:
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
break;
case eVacancyMode.InInitialVacancy:
StartRoomVacancyTimer(eVacancyMode.InShutdownWarning);
break;
case eVacancyMode.InShutdownWarning:
{
StartShutdown(eShutdownType.Vacancy);
Debug.Console(0, this, "Shutting Down due to vacancy.");
break;
}
default:
break;
}
}
/// <summary>
///
/// </summary>
/// <param name="type"></param>
public void StartShutdown(eShutdownType type)
{
// Check for shutdowns running. Manual should override other shutdowns
if (type == eShutdownType.Manual)
ShutdownPromptTimer.SecondsToCount = ShutdownPromptSeconds;
else if (type == eShutdownType.Vacancy)
ShutdownPromptTimer.SecondsToCount = ShutdownVacancySeconds;
ShutdownType = type;
ShutdownPromptTimer.Start();
Debug.Console(0, this, "ShutdwonPromptTimer Started. Type: {0}. Seconds: {1}", ShutdownType, ShutdownPromptTimer.SecondsToCount);
}
public void StartRoomVacancyTimer(eVacancyMode mode)
{
if (mode == eVacancyMode.None)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownPromptSeconds;
else if (mode == eVacancyMode.InInitialVacancy)
RoomVacancyShutdownTimer.SecondsToCount = RoomVacancyShutdownSeconds;
VacancyMode = mode;
RoomVacancyShutdownTimer.Start();
Debug.Console(0, this, "Vacancy Timer Started. Mode: {0}. Seconds: {1}", VacancyMode, RoomVacancyShutdownTimer.SecondsToCount);
}
/// <summary>
/// Resets the vacancy mode and shutsdwon the room
/// </summary>
public void Shutdown()
{
VacancyMode = eVacancyMode.None;
EndShutdown();
}
/// <summary>
/// This method is for the derived class to define it's specific shutdown
/// requirements but should not be called directly. It is called by Shutdown()
/// </summary>
protected abstract void EndShutdown();
/// <summary>
/// Override this to implement a default volume level(s) method
/// </summary>
public abstract void SetDefaultLevels();
/// <summary>
/// Sets the object to be used as the IOccupancyStatusProvider for the room. Can be an Occupancy Aggregator or a specific device
/// </summary>
/// <param name="statusProvider"></param>
public void SetRoomOccupancy(IOccupancyStatusProvider statusProvider, int timeoutMinutes)
{
if (statusProvider == null)
{
Debug.Console(0, this, "ERROR: Occupancy sensor device is null");
return;
}
// If status provider is fusion, set flag to remote
if (statusProvider is PepperDash.Essentials.Fusion.EssentialsHuddleSpaceFusionSystemControllerBase)
OccupancyStatusProviderIsRemote = true;
if(timeoutMinutes > 0)
RoomVacancyShutdownSeconds = timeoutMinutes * 60;
Debug.Console(1, this, "RoomVacancyShutdownSeconds set to {0}", RoomVacancyShutdownSeconds);
RoomOccupancy = statusProvider;
OnRoomOccupancyIsSet();
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange -= RoomIsOccupiedFeedback_OutputChange;
RoomOccupancy.RoomIsOccupiedFeedback.OutputChange += RoomIsOccupiedFeedback_OutputChange;
Debug.Console(0, this, "Room Occupancy set to device: '{0}'", (statusProvider as Device).Key);
}
void OnRoomOccupancyIsSet()
{
var handler = RoomOccupancyIsSet;
if (handler != null)
handler(this, new EventArgs());
}
/// <summary>
/// To allow base class to power room on to last source
/// </summary>
public abstract void PowerOnToDefaultOrLastSource();
/// <summary>
/// To allow base class to power room on to default source
/// </summary>
/// <returns></returns>
public abstract bool RunDefaultPresentRoute();
void RoomIsOccupiedFeedback_OutputChange(object sender, EventArgs e)
{
if (RoomOccupancy.RoomIsOccupiedFeedback.BoolValue == false)
{
Debug.Console(1, this, "Notice: Vacancy Detected");
// Trigger the timer when the room is vacant
StartRoomVacancyTimer(eVacancyMode.InInitialVacancy);
}
else
{
Debug.Console(1, this, "Notice: Occupancy Detected");
// Reset the timer when the room is occupied
RoomVacancyShutdownTimer.Cancel();
}
}
/// <summary>
/// Executes when RoomVacancyShutdownTimer expires. Used to trigger specific room actions as needed. Must nullify the timer object when executed
/// </summary>
/// <param name="o"></param>
public abstract void RoomVacatedForTimeoutPeriod(object o);
}
/// <summary>
/// To describe the various ways a room may be shutting down
/// </summary>
public enum eShutdownType
{
None = 0,
External,
Manual,
Vacancy
}
public enum eVacancyMode
{
None = 0,
InInitialVacancy,
InShutdownWarning
}
/// <summary>
///
/// </summary>
public enum eWarmingCoolingMode
{
None,
Warming,
Cooling
}
}

View File

@@ -25,8 +25,8 @@ namespace PepperDash.Essentials
public void RegisterForSourceChange(IHasCurrentSourceInfoChange room)
{
room.CurrentSingleSourceChange -= room_CurrentSourceInfoChange;
room.CurrentSingleSourceChange += room_CurrentSourceInfoChange;
room.CurrentSingleDisplaySourceChange -= room_CurrentSourceInfoChange;
room.CurrentSingleDisplaySourceChange += room_CurrentSourceInfoChange;
}
void room_CurrentSourceInfoChange(EssentialsRoomBase room, SourceListItem info, ChangeType type)

View File

@@ -733,7 +733,7 @@ namespace PepperDash.Essentials
// Disconnect current room
_CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange;
ClearAudioDeviceConnections();
_CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange;
_CurrentRoom.CurrentSourceChange -= this.CurrentRoom_SourceInfoChange;
DisconnectSource(_CurrentRoom.CurrentSourceInfo);
_CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted;
_CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished;
@@ -803,7 +803,7 @@ namespace PepperDash.Essentials
_CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange;
RefreshAudioDeviceConnections();
_CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange;
_CurrentRoom.CurrentSourceChange += CurrentRoom_SourceInfoChange;
RefreshSourceInfo();
(Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom);

View File

@@ -885,7 +885,7 @@ namespace PepperDash.Essentials
// Disconnect current room
_CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange;
ClearAudioDeviceConnections();
_CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange;
_CurrentRoom.CurrentSourceChange -= this.CurrentRoom_SourceInfoChange;
DisconnectSource(_CurrentRoom.CurrentSourceInfo);
_CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted;
_CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished;
@@ -924,7 +924,7 @@ namespace PepperDash.Essentials
_CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange;
RefreshAudioDeviceConnections();
_CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange;
_CurrentRoom.CurrentSourceChange += CurrentRoom_SourceInfoChange;
RefreshSourceInfo();
if (_CurrentRoom.VideoCodec is IHasScheduleAwareness)
@@ -939,7 +939,7 @@ namespace PepperDash.Essentials
SetActiveCallListSharingContentStatus();
if (_CurrentRoom != null)
_CurrentRoom.CurrentSingleSourceChange += new SourceInfoChangeHandler(CurrentRoom_CurrentSingleSourceChange);
_CurrentRoom.CurrentSourceChange += new SourceInfoChangeHandler(CurrentRoom_CurrentSingleSourceChange);
TriList.SetSigFalseAction(UIBoolJoin.CallStopSharingPress, () => _CurrentRoom.RunRouteAction("codecOsd"));

View File

@@ -64,7 +64,7 @@ namespace PepperDash.Essentials
parent.SetItemMainText(index, room.Name);
UpdateItem(room.CurrentSourceInfo);
// Watch for later changes
room.CurrentSingleSourceChange += new SourceInfoChangeHandler(room_CurrentSourceInfoChange);
room.CurrentSourceChange += new SourceInfoChangeHandler(room_CurrentSourceInfoChange);
parent.SetItemButtonAction(index, buttonAction);
}

View File

@@ -9,8 +9,8 @@ using PepperDash.Essentials.Core;
namespace PepperDash.Essentials
{
/// <summary>
/// The handler type for a Room's SourceInfoChange
/// </summary>
public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type);
///// <summary>
///// The handler type for a Room's SourceInfoChange
///// </summary>
//public delegate void SourceInfoChangeHandler(EssentialsRoomBase room, SourceListItem info, ChangeType type);
}