Working 2-way communication with Cotija Node server for Essentials Huddle Room Type

This commit is contained in:
Neil Dorin
2017-06-26 10:11:12 -06:00
parent e6281b7048
commit 615880a3d8
12 changed files with 572 additions and 265 deletions

View File

@@ -1,157 +1,167 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharpPro; using Crestron.SimplSharpPro;
using Crestron.SimplSharpPro.DM; using Crestron.SimplSharpPro.DM;
using Crestron.SimplSharpPro.DM.Endpoints; using Crestron.SimplSharpPro.DM.Endpoints;
using Crestron.SimplSharpPro.DM.Endpoints.Transmitters; using Crestron.SimplSharpPro.DM.Endpoints.Transmitters;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.Core.Routing; using PepperDash.Essentials.Core.Routing;
namespace PepperDash.Essentials.Core namespace PepperDash.Essentials.Core
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback public class MockDisplay : TwoWayDisplayBase, IBasicVolumeWithFeedback
{ {
public RoutingInputPort HdmiIn1 { get; private set; } public RoutingInputPort HdmiIn1 { get; private set; }
public RoutingInputPort HdmiIn2 { get; private set; } public RoutingInputPort HdmiIn2 { get; private set; }
public RoutingInputPort HdmiIn3 { get; private set; } public RoutingInputPort HdmiIn3 { get; private set; }
public RoutingInputPort ComponentIn1 { get; private set; } public RoutingInputPort ComponentIn1 { get; private set; }
public RoutingInputPort VgaIn1 { get; private set; } public RoutingInputPort VgaIn1 { get; private set; }
bool _PowerIsOn; bool _PowerIsOn;
bool _IsWarmingUp; bool _IsWarmingUp;
bool _IsCoolingDown; bool _IsCoolingDown;
protected override Func<bool> PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } } protected override Func<bool> PowerIsOnFeedbackFunc { get { return () => _PowerIsOn; } }
protected override Func<bool> IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } } protected override Func<bool> IsCoolingDownFeedbackFunc { get { return () => _IsCoolingDown; } }
protected override Func<bool> IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } } protected override Func<bool> IsWarmingUpFeedbackFunc { get { return () => _IsWarmingUp; } }
ushort _FakeVolumeLevel = 31768; ushort _FakeVolumeLevel = 31768;
bool _IsMuted; bool _IsMuted;
public MockDisplay(string key, string name) public MockDisplay(string key, string name)
: base(key, name) : base(key, name)
{ {
HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo, HdmiIn1 = new RoutingInputPort(RoutingPortNames.HdmiIn1, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, null, this); eRoutingPortConnectionType.Hdmi, null, this);
HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo, HdmiIn2 = new RoutingInputPort(RoutingPortNames.HdmiIn2, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, null, this); eRoutingPortConnectionType.Hdmi, null, this);
HdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo, HdmiIn3 = new RoutingInputPort(RoutingPortNames.HdmiIn3, eRoutingSignalType.AudioVideo,
eRoutingPortConnectionType.Hdmi, null, this); eRoutingPortConnectionType.Hdmi, null, this);
ComponentIn1 = new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Video, ComponentIn1 = new RoutingInputPort(RoutingPortNames.ComponentIn, eRoutingSignalType.Video,
eRoutingPortConnectionType.Component, null, this); eRoutingPortConnectionType.Component, null, this);
VgaIn1 = new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Video, VgaIn1 = new RoutingInputPort(RoutingPortNames.VgaIn, eRoutingSignalType.Video,
eRoutingPortConnectionType.Composite, null, this); eRoutingPortConnectionType.Composite, null, this);
InputPorts.AddRange(new[] { HdmiIn1, HdmiIn2, HdmiIn3, ComponentIn1, VgaIn1 }); InputPorts.AddRange(new[] { HdmiIn1, HdmiIn2, HdmiIn3, ComponentIn1, VgaIn1 });
VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; }); VolumeLevelFeedback = new IntFeedback(() => { return _FakeVolumeLevel; });
MuteFeedback = new BoolFeedback(CommonBoolCue.MuteOn, () => _IsMuted); MuteFeedback = new BoolFeedback(CommonBoolCue.MuteOn, () => _IsMuted);
} }
public override void PowerOn() public override void PowerOn()
{ {
if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) if (!PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{ {
_IsWarmingUp = true; _IsWarmingUp = true;
IsWarmingUpFeedback.FireUpdate(); IsWarmingUpFeedback.FireUpdate();
// Fake power-up cycle // Fake power-up cycle
WarmupTimer = new CTimer(o => WarmupTimer = new CTimer(o =>
{ {
_IsWarmingUp = false; _IsWarmingUp = false;
_PowerIsOn = true; _PowerIsOn = true;
IsWarmingUpFeedback.FireUpdate(); IsWarmingUpFeedback.FireUpdate();
PowerIsOnFeedback.FireUpdate(); PowerIsOnFeedback.FireUpdate();
}, WarmupTime); }, WarmupTime);
} }
} }
public override void PowerOff() public override void PowerOff()
{ {
// If a display has unreliable-power off feedback, just override this and // If a display has unreliable-power off feedback, just override this and
// remove this check. // remove this check.
if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown) if (PowerIsOnFeedback.BoolValue && !_IsWarmingUp && !_IsCoolingDown)
{ {
_IsCoolingDown = true; _IsCoolingDown = true;
_PowerIsOn = false; _PowerIsOn = false;
PowerIsOnFeedback.FireUpdate(); PowerIsOnFeedback.FireUpdate();
IsCoolingDownFeedback.FireUpdate(); IsCoolingDownFeedback.FireUpdate();
// Fake cool-down cycle // Fake cool-down cycle
CooldownTimer = new CTimer(o => CooldownTimer = new CTimer(o =>
{ {
Debug.Console(2, this, "Cooldown timer ending"); Debug.Console(2, this, "Cooldown timer ending");
_IsCoolingDown = false; _IsCoolingDown = false;
IsCoolingDownFeedback.FireUpdate(); IsCoolingDownFeedback.FireUpdate();
}, CooldownTime); }, CooldownTime);
} }
} }
public override void PowerToggle() public override void PowerToggle()
{ {
if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue) if (PowerIsOnFeedback.BoolValue && !IsWarmingUpFeedback.BoolValue)
PowerOff(); PowerOff();
else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue) else if (!PowerIsOnFeedback.BoolValue && !IsCoolingDownFeedback.BoolValue)
PowerOn(); PowerOn();
} }
public override void ExecuteSwitch(object selector) public override void ExecuteSwitch(object selector)
{ {
Debug.Console(2, this, "ExecuteSwitch: {0}", selector); Debug.Console(2, this, "ExecuteSwitch: {0}", selector);
} }
#region IBasicVolumeWithFeedback Members #region IBasicVolumeWithFeedback Members
public IntFeedback VolumeLevelFeedback { get; private set; } public IntFeedback VolumeLevelFeedback { get; private set; }
public void SetVolume(ushort level) public void SetVolume(ushort level)
{ {
_FakeVolumeLevel = level; _FakeVolumeLevel = level;
VolumeLevelFeedback.FireUpdate(); VolumeLevelFeedback.FireUpdate();
} }
public void MuteOn() public void MuteOn()
{ {
_IsMuted = true; _IsMuted = true;
MuteFeedback.FireUpdate(); MuteFeedback.FireUpdate();
} }
public void MuteOff() public void MuteOff()
{ {
_IsMuted = false; _IsMuted = false;
MuteFeedback.FireUpdate(); MuteFeedback.FireUpdate();
} }
public BoolFeedback MuteFeedback { get; private set; } public BoolFeedback MuteFeedback { get; private set; }
#endregion #endregion
#region IBasicVolumeControls Members #region IBasicVolumeControls Members
public void VolumeUp(bool pressRelease) public void VolumeUp(bool pressRelease)
{ {
Debug.Console(0, this, "Volume Down {0}", pressRelease); Debug.Console(2, this, "Volume Down {0}", pressRelease);
} if (pressRelease)
{
public void VolumeDown(bool pressRelease) var newLevel = _FakeVolumeLevel + 655;
{ SetVolume((ushort)newLevel);
Debug.Console(0, this, "Volume Up {0}", pressRelease); }
} }
public void MuteToggle() public void VolumeDown(bool pressRelease)
{ {
_IsMuted = !_IsMuted; Debug.Console(2, this, "Volume Up {0}", pressRelease);
MuteFeedback.FireUpdate(); if (pressRelease)
} {
var newLevel = _FakeVolumeLevel - 655;
#endregion SetVolume((ushort)newLevel);
} }
}
public void MuteToggle()
{
_IsMuted = !_IsMuted;
MuteFeedback.FireUpdate();
}
#endregion
}
} }

View File

@@ -338,15 +338,15 @@ namespace PepperDash.Essentials.Devices.Displays
public void VolumeDown(bool pressRelease) public void VolumeDown(bool pressRelease)
{ {
throw new NotImplementedException(); //throw new NotImplementedException();
#warning need incrementer for these //#warning need incrementer for these
//Send(VolumeDownCmd); SetVolume(_VolumeLevel++);
} }
public void VolumeUp(bool pressRelease) public void VolumeUp(bool pressRelease)
{ {
throw new NotImplementedException(); //throw new NotImplementedException();
//Send(VolumeUpCmd); SetVolume(_VolumeLevel--);
} }
#endregion #endregion

View File

@@ -1,68 +1,73 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharpPro; using Crestron.SimplSharpPro;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PepperDash.Core; using PepperDash.Core;
using PepperDash.Essentials.Core; using PepperDash.Essentials.Core;
using PepperDash.Essentials.Core.Config; using PepperDash.Essentials.Core.Config;
namespace PepperDash.Essentials namespace PepperDash.Essentials
{ {
public class DeviceFactory public class DeviceFactory
{ {
public static IKeyed GetDevice(DeviceConfig dc) public static IKeyed GetDevice(DeviceConfig dc)
{ {
var key = dc.Key; var key = dc.Key;
var name = dc.Name; var name = dc.Name;
var type = dc.Type; var type = dc.Type;
var properties = dc.Properties; var properties = dc.Properties;
var typeName = dc.Type.ToLower(); var typeName = dc.Type.ToLower();
if (typeName == "amplifier") if (typeName == "amplifier")
{ {
return new Amplifier(dc.Key, dc.Name); return new Amplifier(dc.Key, dc.Name);
} }
else if (dc.Group.ToLower() == "touchpanel") // typeName.StartsWith("tsw")) else if (dc.Group.ToLower() == "touchpanel") // typeName.StartsWith("tsw"))
{ {
var comm = CommFactory.GetControlPropertiesConfig(dc); var comm = CommFactory.GetControlPropertiesConfig(dc);
var props = JsonConvert.DeserializeObject<CrestronTouchpanelPropertiesConfig>( var props = JsonConvert.DeserializeObject<CrestronTouchpanelPropertiesConfig>(
properties.ToString()); properties.ToString());
return new EssentialsTouchpanelController(key, name, typeName, props, comm.IpIdInt); return new EssentialsTouchpanelController(key, name, typeName, props, comm.IpIdInt);
} }
else if (typeName == "mockdisplay") else if (typeName == "mockdisplay")
{ {
return new MockDisplay(key, name); return new MockDisplay(key, name);
} }
// MOVE into something else??? else if (typeName == "generic")
else if (typeName == "basicirdisplay") {
{ return new Device(key, name);
var ir = IRPortHelper.GetIrPort(properties); }
if (ir != null)
return new BasicIrDisplay(key, name, ir.Port, ir.FileName); // MOVE into something else???
} else if (typeName == "basicirdisplay")
{
else if (typeName == "commmock") var ir = IRPortHelper.GetIrPort(properties);
{ if (ir != null)
var comm = CommFactory.CreateCommForDevice(dc); return new BasicIrDisplay(key, name, ir.Port, ir.FileName);
var props = JsonConvert.DeserializeObject<ConsoleCommMockDevicePropertiesConfig>( }
properties.ToString());
return new ConsoleCommMockDevice(key, name, props, comm); else if (typeName == "commmock")
{
var comm = CommFactory.CreateCommForDevice(dc);
var props = JsonConvert.DeserializeObject<ConsoleCommMockDevicePropertiesConfig>(
properties.ToString());
return new ConsoleCommMockDevice(key, name, props, comm);
} }
else if (typeName == "webserver") else if (typeName == "webserver")
{ {
var props = JsonConvert.DeserializeObject<CotijaConfig>(properties.ToString()); var props = JsonConvert.DeserializeObject<CotijaConfig>(properties.ToString());
return new CotijaSystemController(key, name, props); return new CotijaSystemController(key, name, props);
} }
return null; return null;
} }
} }
} }

View File

@@ -162,6 +162,8 @@ namespace PepperDash.Essentials
{ {
if (room is EssentialsHuddleSpaceRoom) if (room is EssentialsHuddleSpaceRoom)
{ {
DeviceManager.AddDevice(room);
Debug.Console(1, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion"); Debug.Console(1, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion");
DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemController((EssentialsHuddleSpaceRoom)room, 0xf1)); DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemController((EssentialsHuddleSpaceRoom)room, 0xf1));

View File

@@ -0,0 +1,226 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Essentials.Core;
namespace PepperDash.Essentials
{
public class CotijaEssentialsHuddleSpaceRoomBridge
{
CotijaSystemController Parent;
public EssentialsHuddleSpaceRoom Room { get; private set; }
public CotijaEssentialsHuddleSpaceRoomBridge(CotijaSystemController parent, EssentialsHuddleSpaceRoom room)
{
Parent = parent;
Room = room;
// Source Changes and room off
Parent.AddAction(string.Format(@"/room/{0}/status",Room.Key), new Action(() => Room_RoomFullStatus(Room)));
Parent.AddAction(string.Format(@"/room/{0}/source", Room.Key), new Action<SourceSelectMessageContent>(c => room.RunRouteAction(c.SourceSelect)));
Parent.AddAction(string.Format(@"/room/{0}/event/masterVolumeUpBtn", Room.Key), new Action<bool>(b => room.CurrentVolumeControls.VolumeUp(b)));
Parent.AddAction(string.Format(@"/room/{0}/event/masterVolumeDownBtn", Room.Key), new Action<bool>(b => room.CurrentVolumeControls.VolumeDown(b)));
Parent.AddAction(string.Format(@"/room/{0}/event/muteToggle", Room.Key), new Action(() => room.CurrentVolumeControls.MuteToggle()));
Room.CurrentSingleSourceChange += new SourceInfoChangeHandler(Room_CurrentSingleSourceChange);
Room.CurrentVolumeDeviceChange += new EventHandler<VolumeDeviceChangeEventArgs>(Room_CurrentVolumeDeviceChange);
Room.OnFeedback.OutputChange += new EventHandler<EventArgs>(OnFeedback_OutputChange);
// Registers for initial volume events, if possible
var currentVolumeDevice = Room.CurrentVolumeControls;
if (currentVolumeDevice != null)
{
if (currentVolumeDevice is IBasicVolumeWithFeedback)
{
var newDev = currentVolumeDevice as IBasicVolumeWithFeedback;
newDev.MuteFeedback.OutputChange += new EventHandler<EventArgs>(VolumeLevelFeedback_OutputChange);
newDev.VolumeLevelFeedback.OutputChange += new EventHandler<EventArgs>(VolumeLevelFeedback_OutputChange);
}
}
}
void OnFeedback_OutputChange(object sender, EventArgs e)
{
/* Example message
* {
"type":"/room/status",
"content": {
"isOn": false
}
}
*/
JObject roomStatus = new JObject();
roomStatus.Add("isOn", (sender as BoolFeedback).BoolValue);
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.PostToServer(Room, message);
}
void Room_CurrentVolumeDeviceChange(object sender, VolumeDeviceChangeEventArgs e)
{
if (e.OldDev is IBasicVolumeWithFeedback)
{
var oldDev = e.OldDev as IBasicVolumeWithFeedback;
oldDev.MuteFeedback.OutputChange -= VolumeLevelFeedback_OutputChange;
oldDev.VolumeLevelFeedback.OutputChange -= VolumeLevelFeedback_OutputChange;
}
if (e.NewDev is IBasicVolumeWithFeedback)
{
var newDev = e.NewDev as IBasicVolumeWithFeedback;
newDev.MuteFeedback.OutputChange += new EventHandler<EventArgs>(VolumeLevelFeedback_OutputChange);
newDev.VolumeLevelFeedback.OutputChange += new EventHandler<EventArgs>(VolumeLevelFeedback_OutputChange);
}
}
void VolumeLevelFeedback_OutputChange(object sender, EventArgs e)
{
/* Example message
* {
"type":"/room/status",
"content": {
"masterVolumeLevel": 12345,
"masterVolumeMuteState": false
}
}
*/
var huddleRoom = Room as EssentialsHuddleSpaceRoom;
if(huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback)
{
JObject roomStatus = new JObject();
if (huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var currentVolumeConstrols = huddleRoom.CurrentVolumeControls as IBasicVolumeWithFeedback;
roomStatus.Add("masterVolumeLevel", currentVolumeConstrols.VolumeLevelFeedback.IntValue);
roomStatus.Add("masterVolumeMuteState", currentVolumeConstrols.MuteFeedback.BoolValue);
}
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.PostToServer(Room, message);
}
}
void Room_CurrentSingleSourceChange(EssentialsRoomBase room, PepperDash.Essentials.Core.SourceListItem info, ChangeType type)
{
/* Example message
* {
"type":"/room/status",
"content": {
"selectedSourceKey": "off",
}
}
*/
if (type != ChangeType.DidChange)
return;
JObject roomStatus = new JObject();
var huddleRoom = room as EssentialsHuddleSpaceRoom;
//roomStatus.Add("isOn", huddleRoom.OnFeedback.BoolValue);
roomStatus.Add("selectedSourceKey", huddleRoom.CurrentSourceInfoKey);
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.PostToServer(Room, message);
}
/// <summary>
/// Posts the full status of the room to the server
/// </summary>
/// <param name="room"></param>
void Room_RoomFullStatus(EssentialsRoomBase room)
{
/* Example message
* {
"type":"/room/status",
"content": {
"selectedSourceKey": "off",
"isOn": false,
"masterVolumeLevel": 50,
"masterVolumeMuteState": false
}
}
*/
JObject roomStatus = new JObject();
var huddleRoom = room as EssentialsHuddleSpaceRoom;
roomStatus.Add("isOn", huddleRoom.OnFeedback.BoolValue);
roomStatus.Add("selectedSourceKey", huddleRoom.CurrentSourceInfoKey);
if(huddleRoom.CurrentVolumeControls is IBasicVolumeWithFeedback)
{
var currentVolumeConstrols = huddleRoom.CurrentVolumeControls as IBasicVolumeWithFeedback;
roomStatus.Add("masterVolumeLevel", currentVolumeConstrols.VolumeLevelFeedback.IntValue);
roomStatus.Add("masterVolumeMuteState", currentVolumeConstrols.MuteFeedback.BoolValue);
}
JObject message = new JObject();
message.Add("type", "/room/status/");
message.Add("content", roomStatus);
Parent.PostToServer(Room, message);
}
}
public class SourceSelectMessageContent
{
public string Destination { get; set; }
public string SourceSelect { get; set; }
}
//public class PostMessage
//{
// [JsonProperty("type")]
// public string Type { get; set; }
// [JsonProperty("content")]
// public JToken Content { get; set; }
//}
//public class RoomStatusMessageContent
//{
// [JsonProperty("selectedSourceKey")]
// public string SelectedSourceKey { get; set; }
// [JsonProperty("isOn")]
// public bool? IsOn { get; set; }
// [JsonProperty("masterVolumeLevel")]
// public int? MasterVolumeLevel { get; set; }
// [JsonProperty("masterVolumeMuteState")]
// public bool? MasterVolumeMuteState { get; set; }
//}
}

View File

@@ -42,18 +42,33 @@ namespace PepperDash.Essentials
CotijaRooms = new List<CotijaEssentialsHuddleSpaceRoomBridge>(); CotijaRooms = new List<CotijaEssentialsHuddleSpaceRoomBridge>();
CrestronConsole.AddNewConsoleCommand(ConnectSseClient, "InitializeHttpClient", "Initializes a new HTTP client connection to a specified URL", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(RegisterSystemToServer, "InitializeHttpClient", "Initializes a new HTTP client connection to a specified URL", ConsoleAccessLevelEnum.AccessOperator);
CrestronConsole.AddNewConsoleCommand(DisconnectSseClient, "CloseHttpClient", "Closes the active HTTP client", ConsoleAccessLevelEnum.AccessOperator); CrestronConsole.AddNewConsoleCommand(DisconnectSseClient, "CloseHttpClient", "Closes the active HTTP client", ConsoleAccessLevelEnum.AccessOperator);
AddPostActivationAction(() => RegisterSystemToServer(null)); AddPostActivationAction(() => RegisterSystemToServer(null));
} }
/// <summary>
/// Adds an action to the dictionary
/// </summary>
/// <param name="key">The path of the API command</param>
/// <param name="action">The action to be triggered by the commmand</param>
public void AddAction(string key, object action) public void AddAction(string key, object action)
{ {
// This might blow up if an action with that key already exists if (!ActionDictionary.ContainsKey(key))
ActionDictionary.Add(key, action); {
ActionDictionary.Add(key, action);
}
else
{
Debug.Console(1, this, "Cannot add action with key '{0}' because key already exists in ActionDictionary.");
}
} }
/// <summary>
/// Removes and action from the dictionary
/// </summary>
/// <param name="key"></param>
public void RemoveAction(string key) public void RemoveAction(string key)
{ {
if (ActionDictionary.ContainsKey(key)) if (ActionDictionary.ContainsKey(key))
@@ -135,22 +150,39 @@ namespace PepperDash.Essentials
/// <param name="o">object to be serialized and sent in post body</param> /// <param name="o">object to be serialized and sent in post body</param>
public void PostToServer(EssentialsRoomBase room, JObject o) public void PostToServer(EssentialsRoomBase room, JObject o)
{ {
if(Client == null) try
Client = new HttpClient(); {
if (Client == null)
Client = new HttpClient();
HttpClientRequest request = new HttpClientRequest(); //HttpClient client = new HttpClient();
Client.Verbose = true; HttpClientRequest request = new HttpClientRequest();
Client.KeepAlive = true;
string url = string.Format("http://{0}/api/room/{1}", Config.serverUrl, string.Format("{0}-{1}", SystemUuid, room.Key)); Client.Verbose = true;
Client.KeepAlive = true;
request.Url.Parse(url); string url = string.Format("http://{0}/api/room/{1}/status", Config.serverUrl, string.Format("{0}--{1}", SystemUuid, room.Key));
request.RequestType = RequestType.Post;
request.Header.SetHeaderValue("Content-Type", "application/json");
request.ContentString = o.ToString();
Client.DispatchAsync(request, PostConnectionCallback); request.Url.Parse(url);
request.RequestType = RequestType.Post;
request.Header.SetHeaderValue("Content-Type", "application/json");
request.KeepAlive = true;
// Ignore any null objects when serializing and remove formatting
string ignored = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
request.ContentString = ignored;
Debug.Console(1, this, "Posting to '{0}':\n{1}", url, request.ContentString);
Client.DispatchAsync(request, (r, err) => { if (r != null) { Debug.Console(1, this, "Status Response Code: {0}", r.Code); } });
StartReconnectTimer(5000, 5000);
}
catch(Exception e)
{
Debug.Console(1, this, "Error Posting to Server: {0}", e);
}
} }
/// <summary> /// <summary>
@@ -181,6 +213,13 @@ namespace PepperDash.Essentials
{ {
if (resp != null && resp.Code == 200) if (resp != null && resp.Code == 200)
{ {
if(Reconnect != null)
{
Reconnect.Stop();
Reconnect = null;
}
if (SseClient == null) if (SseClient == null)
{ {
ConnectSseClient(null); ConnectSseClient(null);
@@ -188,12 +227,12 @@ namespace PepperDash.Essentials
} }
else else
{ {
Debug.Console(0, this, "Unable to initialize SSE Client"); Debug.Console(0, this, "Response from server: {0}\n{1}", resp.Code, err);
} }
} }
catch (Exception e) catch (Exception e)
{ {
Debug.Console(1, this, "Error Initializeing SSE Client: {0}", e); Debug.Console(1, this, "Error Initializing SSE Client: {0}", e);
} }
} }
@@ -205,15 +244,22 @@ namespace PepperDash.Essentials
{ {
if (Heartbeat != null) if (Heartbeat != null)
{ {
Debug.Console(1, this, "Heartbeat Timer Expired.");
Heartbeat.Stop(); Heartbeat.Stop();
Heartbeat = null; Heartbeat = null;
} }
// Start the reconnect timer StartReconnectTimer(5000, 5000);
Reconnect = new CTimer(ReconnectToServer, null, 5000, 5000); }
Reconnect.Reset(5000, 5000); void StartReconnectTimer(long dueTime, long repeatTime)
{
// Start the reconnect timer
Reconnect = new CTimer(ReconnectToServer, null, dueTime, repeatTime);
Reconnect.Reset(dueTime, repeatTime);
} }
@@ -246,11 +292,8 @@ namespace PepperDash.Essentials
SseClient.Url = string.Format("http://{0}/api/system/stream/{1}", Config.serverUrl, uuid); SseClient.Url = string.Format("http://{0}/api/system/stream/{1}", Config.serverUrl, uuid);
SseClient.Connect(); SseClient.Connect();
//Heartbeat = new CTimer(HeartbeatExpired, null, 20000, 20000);
//Heartbeat.Reset(20000, 20000);
} }
void LineGathered_LineReceived(object sender, GenericCommMethodReceiveTextArgs e) void LineGathered_LineReceived(object sender, GenericCommMethodReceiveTextArgs e)
{ {
@@ -260,8 +303,6 @@ namespace PepperDash.Essentials
{ {
var message = e.Text.Substring(6); var message = e.Text.Substring(6);
string roomId = null;
Debug.Console(1, this, "Message: '{0}'", message); Debug.Console(1, this, "Message: '{0}'", message);
try try
@@ -270,11 +311,21 @@ namespace PepperDash.Essentials
var type = messageObj["type"].Value<string>(); var type = messageObj["type"].Value<string>();
if(type == "/system/hearbeat") if (type == "hello")
{ {
//Heartbeat.Reset(20000, 20000); Heartbeat = new CTimer(HeartbeatExpired, null, 20000, 20000);
Debug.Console(2, this, "Heartbeat Timer Started.");
Heartbeat.Reset(20000, 20000);
} }
else if(type == "close") else if (type == "/system/heartbeat")
{
Heartbeat.Reset(20000, 20000);
Debug.Console(2, this, "Heartbeat Timer Reset.");
}
else if (type == "close")
{ {
SseClient.Disconnect(); SseClient.Disconnect();
@@ -285,19 +336,21 @@ namespace PepperDash.Essentials
} }
else else
{ {
// Check path against Action dictionary // Check path against Action dictionary
if (ActionDictionary.ContainsKey(type)) if (ActionDictionary.ContainsKey(type))
{ {
var action = ActionDictionary[type]; var action = ActionDictionary[type];
if (action is Action<bool>) if (action is Action)
{
(action as Action)();
}
else if (action is Action<bool>)
{ {
var stateString = messageObj["content"]["state"].Value<string>(); var stateString = messageObj["content"]["state"].Value<string>();
// Look for a button press event // Look for a button press event
if(!string.IsNullOrEmpty(stateString)) if (!string.IsNullOrEmpty(stateString))
{ {
#warning deal with held state later #warning deal with held state later
if (stateString == "held") if (stateString == "held")
@@ -320,7 +373,7 @@ namespace PepperDash.Essentials
.ToObject<SourceSelectMessageContent>()); .ToObject<SourceSelectMessageContent>());
} }
} }
} }
} }

View File

@@ -80,14 +80,16 @@ namespace PepperDash.Essentials
_CurrentSourceInfo = value; _CurrentSourceInfo = value;
// add to in-use tracking // add to in-use tracking
if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking)
(_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control"); (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control");
if (handler != null) if (handler != null)
handler(this, _CurrentSourceInfo, ChangeType.DidChange); handler(this, _CurrentSourceInfo, ChangeType.DidChange);
} }
} }
SourceListItem _CurrentSourceInfo; SourceListItem _CurrentSourceInfo;
public string CurrentSourceInfoKey { get; private set; }
/// <summary> /// <summary>
/// ///
@@ -154,9 +156,15 @@ namespace PepperDash.Essentials
Debug.Console(2, this, "Action {0} has {1} steps", Debug.Console(2, this, "Action {0} has {1} steps",
item.SourceKey, item.RouteList.Count); item.SourceKey, item.RouteList.Count);
// Let's run it // Let's run it
if (routeKey.ToLower() != "roomoff") if (routeKey.ToLower() != "roomoff")
LastSourceKey = routeKey; {
LastSourceKey = routeKey;
}
else
{
CurrentSourceInfoKey = null;
}
foreach (var route in item.RouteList) foreach (var route in item.RouteList)
{ {
@@ -203,9 +211,12 @@ namespace PepperDash.Essentials
} }
CurrentVolumeControls = volDev; CurrentVolumeControls = volDev;
// store the name and UI info for routes // store the name and UI info for routes
if (item.SourceKey != null) if (item.SourceKey != null)
CurrentSourceInfo = item; {
CurrentSourceInfoKey = routeKey;
CurrentSourceInfo = item;
}
// And finally, set the "control". This will trigger event // And finally, set the "control". This will trigger event
//CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device; //CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device;

View File

@@ -94,7 +94,7 @@ namespace PepperDash.Essentials
var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, props); var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, props);
// Then the AV driver // Then the AV driver
// spin up different room drivers depending on room type // spin up different room drivers depending on room type
var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey); var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey);
if (room is EssentialsHuddleSpaceRoom) if (room is EssentialsHuddleSpaceRoom)
{ {