mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-15 20:54:55 +00:00
Working 2-way communication with Cotija Node server for Essentials Huddle Room Type
This commit is contained in:
226
Essentials/PepperDashEssentials/Room/Cotija/CotijaRoomBridge.cs
Normal file
226
Essentials/PepperDashEssentials/Room/Cotija/CotijaRoomBridge.cs
Normal 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; }
|
||||
//}
|
||||
|
||||
}
|
||||
@@ -42,18 +42,33 @@ namespace PepperDash.Essentials
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
// This might blow up if an action with that key already exists
|
||||
ActionDictionary.Add(key, action);
|
||||
if (!ActionDictionary.ContainsKey(key))
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (ActionDictionary.ContainsKey(key))
|
||||
@@ -135,22 +150,39 @@ namespace PepperDash.Essentials
|
||||
/// <param name="o">object to be serialized and sent in post body</param>
|
||||
public void PostToServer(EssentialsRoomBase room, JObject o)
|
||||
{
|
||||
if(Client == null)
|
||||
Client = new HttpClient();
|
||||
try
|
||||
{
|
||||
if (Client == null)
|
||||
Client = new HttpClient();
|
||||
|
||||
HttpClientRequest request = new HttpClientRequest();
|
||||
//HttpClient client = new HttpClient();
|
||||
|
||||
Client.Verbose = true;
|
||||
Client.KeepAlive = true;
|
||||
HttpClientRequest request = new HttpClientRequest();
|
||||
|
||||
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);
|
||||
request.RequestType = RequestType.Post;
|
||||
request.Header.SetHeaderValue("Content-Type", "application/json");
|
||||
request.ContentString = o.ToString();
|
||||
string url = string.Format("http://{0}/api/room/{1}/status", Config.serverUrl, string.Format("{0}--{1}", SystemUuid, room.Key));
|
||||
|
||||
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>
|
||||
@@ -181,6 +213,13 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
if (resp != null && resp.Code == 200)
|
||||
{
|
||||
if(Reconnect != null)
|
||||
{
|
||||
Reconnect.Stop();
|
||||
|
||||
Reconnect = null;
|
||||
}
|
||||
|
||||
if (SseClient == null)
|
||||
{
|
||||
ConnectSseClient(null);
|
||||
@@ -188,12 +227,12 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Debug.Console(1, this, "Heartbeat Timer Expired.");
|
||||
|
||||
Heartbeat.Stop();
|
||||
|
||||
Heartbeat = null;
|
||||
}
|
||||
|
||||
// Start the reconnect timer
|
||||
Reconnect = new CTimer(ReconnectToServer, null, 5000, 5000);
|
||||
StartReconnectTimer(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.Connect();
|
||||
|
||||
//Heartbeat = new CTimer(HeartbeatExpired, null, 20000, 20000);
|
||||
|
||||
//Heartbeat.Reset(20000, 20000);
|
||||
}
|
||||
|
||||
|
||||
void LineGathered_LineReceived(object sender, GenericCommMethodReceiveTextArgs e)
|
||||
{
|
||||
@@ -260,8 +303,6 @@ namespace PepperDash.Essentials
|
||||
{
|
||||
var message = e.Text.Substring(6);
|
||||
|
||||
string roomId = null;
|
||||
|
||||
Debug.Console(1, this, "Message: '{0}'", message);
|
||||
|
||||
try
|
||||
@@ -270,11 +311,21 @@ namespace PepperDash.Essentials
|
||||
|
||||
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();
|
||||
|
||||
@@ -285,19 +336,21 @@ namespace PepperDash.Essentials
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
// Check path against Action dictionary
|
||||
if (ActionDictionary.ContainsKey(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>();
|
||||
|
||||
// Look for a button press event
|
||||
if(!string.IsNullOrEmpty(stateString))
|
||||
if (!string.IsNullOrEmpty(stateString))
|
||||
{
|
||||
#warning deal with held state later
|
||||
if (stateString == "held")
|
||||
@@ -320,7 +373,7 @@ namespace PepperDash.Essentials
|
||||
.ToObject<SourceSelectMessageContent>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user