Added Extend Meeting and End Meeting early features, as well as Fusion Events. ECS-316 ECS-317 ECS-320

This commit is contained in:
Neil Dorin
2017-05-17 23:01:29 -06:00
parent 34144c6f13
commit 520f7fa639
7 changed files with 246 additions and 54 deletions

View File

@@ -0,0 +1,18 @@
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 MyProperty { get; set; }
}
public class MeetingChangeEventArgs : EventArgs
{
public Event Meeting { get; set; }
}
}

View File

@@ -26,6 +26,10 @@ namespace PepperDash.Essentials.Fusion
{
public class EssentialsHuddleSpaceFusionSystemController : Device
{
public event EventHandler<ScheduleChangeEventArgs> ScheduleChange;
public event EventHandler<MeetingChangeEventArgs> MeetingEndWarning;
public event EventHandler<MeetingChangeEventArgs> NextMeetingBeginWarning;
FusionRoom FusionRoom;
EssentialsHuddleSpaceRoom Room;
Dictionary<Device, BoolInputSig> SourceToFeedbackSigs =
@@ -35,7 +39,7 @@ namespace PepperDash.Essentials.Fusion
StringSigData SourceNameSig;
ScheduleResponse CurrentSchedule;
RoomSchedule CurrentSchedule;
Event NextMeeting;
@@ -49,8 +53,14 @@ namespace PepperDash.Essentials.Fusion
bool IsRegisteredForSchedulePushNotifications = false;
CTimer PollTimer = null;
CTimer PushNotificationTimer = null;
// Default poll time is 5 min unless overridden by config value
int SchedulePollInterval = 300000;
public long SchedulePollInterval = 300000;
public long PushNotificationTimeout = 5000;
List<StaticAsset> StaticAssets;
@@ -65,6 +75,7 @@ namespace PepperDash.Essentials.Fusion
StaticAssets = new List<StaticAsset>();
var mac = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, 0);
var slot = Global.ControlSystem.ProgramNumber;
@@ -209,7 +220,7 @@ namespace PepperDash.Essentials.Fusion
Debug.Console(0, this, "Fusion Guids successfully read from file:");
Debug.Console(1, this, "\nRoom Name: {0}\nIPID: {1}\n RoomGuid: {2}", Room.Name, IpId, RoomGuid);
Debug.Console(1, this, "\nRoom Name: {0}\nIPID: {1:x}\n RoomGuid: {2}", Room.Name, IpId, RoomGuid);
foreach (StaticAsset asset in StaticAssets)
{
@@ -228,7 +239,6 @@ namespace PepperDash.Essentials.Fusion
}
void CreateSymbolAndBasicSigs(uint ipId)
{
Debug.Console(1, this, "Creating Fusion Room symbol with GUID: {0}", RoomGuid);
@@ -247,6 +257,7 @@ namespace PepperDash.Essentials.Fusion
CrestronConsole.AddNewConsoleCommand(RequestFullRoomSchedule, "FusReqRoomSchedule", "Requests schedule of the room for the next 24 hours", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(ModifyMeetingEndTimeConsoleHelper, "FusReqRoomSchMod", "Ends or extends a meeting by the specified time", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(CreateAsHocMeeting, "FusCreateMeeting", "Creates and Ad Hoc meeting for on hour or until the next meeting", ConsoleAccessLevelEnum.AccessOperator);
// Room to fusion room
Room.OnFeedback.LinkInputSig(FusionRoom.SystemPowerOn.InputSig);
@@ -308,12 +319,11 @@ namespace PepperDash.Essentials.Fusion
}
/// <summary>
/// Generates a room schedule request for this room for the next 24 hours.
/// </summary>
/// <param name="requestID">string identifying this request. Used with a corresponding ScheduleResponse value</param>
public void RequestFullRoomSchedule(string requestID)
public void RequestFullRoomSchedule(object callbackObject)
{
DateTime now = DateTime.Today;
@@ -329,13 +339,20 @@ namespace PepperDash.Essentials.Fusion
// string.Format("<RequestSchedule><RequestID>{0}</RequestID><RoomID>{1}</RoomID><Start>2017-05-02T00:00:00</Start><HourSpan>24</HourSpan></RequestSchedule>", requestID, GUID);
string requestTest =
string.Format("<RequestSchedule><RequestID>{0}</RequestID><RoomID>{1}</RoomID><Start>{2}</Start><HourSpan>24</HourSpan></RequestSchedule>", requestID, RoomGuid, currentTime);
string.Format("<RequestSchedule><RequestID>FullSchedleRequest</RequestID><RoomID>{0}</RoomID><Start>{1}</Start><HourSpan>24</HourSpan></RequestSchedule>", RoomGuid, currentTime);
Debug.Console(1, this, "Sending Fusion ScheduleQuery: \n{0}", requestTest);
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleQuery.StringValue = requestTest;
}
if (IsRegisteredForSchedulePushNotifications)
PushNotificationTimer.Stop();
}
/// <summary>
/// Wrapper method to allow console commands to modify the current meeting end time
/// </summary>
/// <param name="command">meetingID extendTime</param>
public void ModifyMeetingEndTimeConsoleHelper(string command)
{
string requestID;
@@ -357,36 +374,99 @@ namespace PepperDash.Essentials.Fusion
Debug.Console(1, this, "Error parsing console command: {0}", e);
}
Event tempEvent = CurrentSchedule.Events.FirstOrDefault(e => e.MeetingID.Equals(meetingID));
ModifyMeetingEndTime(requestID, extendMinutes);
if (tempEvent != null && extendMinutes > -1)
{
ModifyMeetingEndTime(requestID, tempEvent, extendMinutes);
}
else
{
Debug.Console(1, this, "No matching MeetingID found in CurrentSchedule.Events or invalid time specified");
}
}
/// <summary>
/// Ends or Extends a meeting by the specified number of minutes.
/// Ends or Extends the current meeting by the specified number of minutes.
/// </summary>
/// <param name="extendMinutes">Number of minutes to extend the meeting. A value of 0 will end the meeting.</param>
public void ModifyMeetingEndTime(string requestID, PepperDash.Essentials.Fusion.Event meeting, int extendMinutes)
public void ModifyMeetingEndTime(string requestID, int extendMinutes)
{
string requestTest = string.Format(
"<RequestAction><RequestID>{0}</RequestID><RoomID>{1}</RoomID><ActionID>MeetingChange</ActionID><Parameters><Parameter ID = 'MeetingID' Value = '{2}' /><Parameter ID = 'EndTime' Value = '{3}' /></Parameters></RequestAction>"
, requestID, RoomGuid, meeting.MeetingID, extendMinutes);
if(CurrentMeeting == null)
{
Debug.Console(1, this, "No meeting in progress. Unable to modify end time.");
return;
}
#warning Need to add logic to properly extend from the current time. See S+ module for reference.
if (extendMinutes > -1)
{
if(extendMinutes > 0)
{
var extendTime = CurrentMeeting.dtEnd - DateTime.Now;
double extendMinutesRaw = extendTime.TotalMinutes;
Debug.Console(1, this, "Sending MeetingChange Request: \n{0}", requestTest);
extendMinutes = extendMinutes + (int)Math.Round(extendMinutesRaw);
}
string requestTest = string.Format(
"<RequestAction><RequestID>{0}</RequestID><RoomID>{1}</RoomID><ActionID>MeetingChange</ActionID><Parameters><Parameter ID = 'MeetingID' Value = '{2}' /><Parameter ID = 'EndTime' Value = '{3}' /></Parameters></RequestAction>"
, requestID, RoomGuid, CurrentMeeting.MeetingID, extendMinutes);
Debug.Console(1, this, "Sending MeetingChange Request: \n{0}", requestTest);
FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = requestTest;
}
else
{
Debug.Console(1, this, "Invalid time specified");
}
//FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleQuery.StringValue = requestTest;
FusionRoom.ExtenderFusionRoomDataReservedSigs.ActionQuery.StringValue = requestTest;
}
/// <summary>
/// Creates and Ad Hoc meeting with a duration of 1 hour, or until the next meeting if in less than 1 hour.
/// </summary>
public void CreateAsHocMeeting(string command)
{
string requestID = "CreateAdHocMeeting";
DateTime now = DateTime.Now.AddMinutes(1);
now.AddSeconds(-now.Second);
// Assume 1 hour meeting if possible
DateTime dtEnd = now.AddHours(1);
// Check if room is available for 1 hour before next meeting
if (NextMeeting != null)
{
var roomAvailable = NextMeeting.dtEnd.Subtract(dtEnd);
if (roomAvailable.TotalMinutes < 60)
{
/// Room not available for full hour, book until next meeting starts
dtEnd = NextMeeting.dtEnd;
}
}
string createMeetingRequest =
"<CreateSchedule>" +
string.Format("<RequestID>{0}</RequestID>", requestID) +
string.Format("<RoomID>{0}</RoomID>", RoomGuid) +
"<Event>" +
string.Format("<dtStart>{0}</dtStart>", now.ToString("s")) +
string.Format("<dtEnd>{0}</dtEnd>", dtEnd.ToString("s")) +
"<Subject>AdHoc Meeting</Subject>" +
"<Organizer>Room User</Organizer>" +
"<Body></Body>" +
"</Event>" +
"</CreateSchedule>";
Debug.Console(1, this, "Sending CreateMeeting Request: \n{0}", createMeetingRequest);
FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateMeeting.StringValue = createMeetingRequest;
}
/// <summary>
/// Event handler method for Device Extender sig changes
/// </summary>
/// <param name="currentDeviceExtender"></param>
/// <param name="args"></param>
void ExtenderFusionRoomDataReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args)
{
Debug.Console(1, this, "Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue);
@@ -396,28 +476,80 @@ namespace PepperDash.Essentials.Fusion
{
try
{
ActionResponse actionResponse = new ActionResponse();
//ActionResponse actionResponse = new ActionResponse();
TextReader reader = new StringReader(args.Sig.StringValue);
actionResponse = CrestronXMLSerialization.DeSerializeObject<ActionResponse>(reader);
//TextReader reader = new StringReader(args.Sig.StringValue);
if (actionResponse.RequestID == "InitialPushRequest")
//actionResponse = CrestronXMLSerialization.DeSerializeObject<ActionResponse>(reader);
//if (actionResponse != null)
//{
// if (actionResponse.RequestID == "InitialPushRequest")
// {
// if (actionResponse.Parameters != null)
// {
// var tempParam = actionResponse.Parameters.FirstOrDefault(p => p.ID.Equals("Registered"));
XmlDocument message = new XmlDocument();
message.LoadXml(args.Sig.StringValue);
var actionResponse = message["ActionResponse"];
if (actionResponse != null)
{
var tempParam = actionResponse.Parameters.FirstOrDefault(p => p.ID.Equals("Registered"));
var requestID = actionResponse["RequestID"];
if (tempParam != null)
if (requestID.InnerText == "InitialPushRequest")
{
if (tempParam.Value = 1)
IsRegisteredForSchedulePushNotifications = true;
else
if (actionResponse["ActionID"].InnerText == "RegisterPushModel")
{
IsRegisteredForSchedulePushNotifications = false;
var parameters = actionResponse["Parameters"];
foreach (XmlElement parameter in parameters)
{
if (parameter.HasAttributes)
{
var attributes = parameter.Attributes;
if (attributes["ID"].Value == "Registered")
{
var isRegistered = Int32.Parse(attributes["Value"].Value);
if (isRegistered == 1)
{
IsRegisteredForSchedulePushNotifications = true;
if (PollTimer != null && !PollTimer.Disposed)
{
PollTimer.Stop();
PollTimer.Dispose();
}
PushNotificationTimer = new CTimer(RequestFullRoomSchedule, null, PushNotificationTimeout, PushNotificationTimeout);
PushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout);
}
else if (isRegistered == 0)
{
IsRegisteredForSchedulePushNotifications = false;
if (PushNotificationTimer != null && !PushNotificationTimer.Disposed)
{
PushNotificationTimer.Stop();
PushNotificationTimer.Dispose();
}
PollTimer = new CTimer(RequestFullRoomSchedule, null, SchedulePollInterval, SchedulePollInterval);
PollTimer.Reset(SchedulePollInterval, SchedulePollInterval);
}
}
}
}
}
}
}
}
catch (Exception e)
{
@@ -426,9 +558,14 @@ namespace PepperDash.Essentials.Fusion
}
}
/// <summary>
/// Event handler method for Device Extender sig changes
/// </summary>
/// <param name="currentDeviceExtender"></param>
/// <param name="args"></param>
void FusionRoomSchedule_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args)
{
Debug.Console(1, this, "Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue);
Debug.Console(1, this, "Scehdule Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue);
if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.ScheduleResponse)
@@ -441,22 +578,27 @@ namespace PepperDash.Essentials.Fusion
message.LoadXml(args.Sig.StringValue);
var scheuldResponse = message["ScheduleRespones"];
var response = message["ScheduleResponse"];
if (scheuldResponse != null)
if (response != null)
{
// Check for push notification
if (scheuldResponse["RequestID"].InnerText == "RVRequest")
if (response["RequestID"].InnerText == "RVRequest")
{
var action = scheuldResponse["Action"];
var action = response["Action"];
if (action.InnerText.IndexOf("RequestSchedule") > -1)
if (action.OuterXml.IndexOf("RequestSchedule") > -1)
{
RequestFullRoomSchedule("PushScheduleRefresh");
PushNotificationTimer.Reset(PushNotificationTimeout, PushNotificationTimeout);
}
}
else // Not a push notification
{
CurrentSchedule = new RoomSchedule(); // Clear Current Schedule
CurrentMeeting = null; // Clear Current Meeting
NextMeeting = null; // Clear Next Meeting
bool isNextMeeting = false;
foreach (XmlElement element in message.FirstChild.ChildNodes)
{
@@ -483,15 +625,33 @@ namespace PepperDash.Essentials.Fusion
tempEvent = CrestronXMLSerialization.DeSerializeObject<Event>(reader);
scheduleResponse.Events.Add(tempEvent);
// Check is this is the current event
if (tempEvent.dtStart <= DateTime.Now && tempEvent.dtEnd >= DateTime.Now)
{
CurrentMeeting = tempEvent; // Set Current Meeting
isNextMeeting = true; // Flag that next element is next meeting
}
if (isNextMeeting)
{
NextMeeting = tempEvent; // Set Next Meeting
isNextMeeting = false;
}
CurrentSchedule.Meetings.Add(tempEvent);
}
}
PrintTodaysSchedule();
if (!IsRegisteredForSchedulePushNotifications)
PollTimer.Reset(SchedulePollInterval, SchedulePollInterval);
}
}
CurrentSchedule = scheduleResponse;
PrintTodaysSchedule();
}
catch (Exception e)
@@ -499,22 +659,26 @@ namespace PepperDash.Essentials.Fusion
Debug.Console(1, this, "Error parsing ScheduleResponse: {0}", e);
}
}
else if (args.Sig == FusionRoom.ExtenderRoomViewSchedulingDataReservedSigs.CreateResponse)
{
Debug.Console(1, this, "Create Meeting Response Event: {0}\n Sig: {1}\nFusionResponse:\n{2}", args.Event, args.Sig.Name, args.Sig.StringValue);
}
}
void PrintTodaysSchedule()
{
if (CurrentSchedule.Events.Count > 0)
if (CurrentSchedule.Meetings.Count > 0)
{
Debug.Console(1, this, "Today's Schedule for '{0}'\n", Room.Name);
foreach (Event e in CurrentSchedule.Events)
foreach (Event e in CurrentSchedule.Meetings)
{
Debug.Console(1, this, "Subject: {0}", e.Subject);
Debug.Console(1, this, "Organizer: {0}", e.Organizer);
Debug.Console(1, this, "MeetingID: {0}", e.MeetingID);
Debug.Console(1, this, "Start Time: {0}", e.dtStart);
Debug.Console(1, this, "End Time: {0}", e.dtEnd);
var duration = e.dtEnd.Subtract(e.dtStart);
Debug.Console(1, this, "Duration: {0}\n", e.DurationInMinutes);
}
}
@@ -945,12 +1109,21 @@ namespace PepperDash.Essentials.Fusion
}
}
//***************************************************************************************************
public class RoomSchedule
{
public List<Event> Meetings { get; set; }
public RoomSchedule()
{
Meetings = new List<Event>();
}
}
//****************************************************************************************************
// Helper Classes for XML API
/// <summary>
/// All the data needed for a full schedule request in a room
/// </summary>

View File

@@ -134,6 +134,7 @@
<Compile Include="Devices\DiscPlayer\OppoExtendedBdp.cs" />
<Compile Include="Devices\NUMERIC AppleTV.cs" />
<Compile Include="ControlSystem.cs" />
<Compile Include="Fusion\FusionEventHandlers.cs" />
<Compile Include="REMOVE EssentialsApp.cs" />
<Compile Include="Fusion\FusionSystemController.cs" />
<Compile Include="HttpApiHandler.cs" />