mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-16 13:15:03 +00:00
Compiled, for review
This commit is contained in:
@@ -60,7 +60,7 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Crestron.SimplSharpPro.Lighting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
<Reference Include="Crestron.SimplSharpPro.Lighting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Lighting.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SSPDevices\Crestron.SimplSharpPro.Lighting.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="mscorlib" />
|
<Reference Include="mscorlib" />
|
||||||
<Reference Include="PepperDash_Core, Version=1.0.4.20530, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="PepperDash_Core, Version=1.0.4.20530, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using PepperDash.Essentials.Core;
|
|||||||
using PepperDash.Essentials.Devices.Common;
|
using PepperDash.Essentials.Devices.Common;
|
||||||
using PepperDash.Essentials.DM;
|
using PepperDash.Essentials.DM;
|
||||||
using PepperDash.Essentials.Fusion;
|
using PepperDash.Essentials.Fusion;
|
||||||
|
using PepperDash.Essentials.Room.Cotija;
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
@@ -31,10 +32,16 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override void InitializeSystem()
|
public override void InitializeSystem()
|
||||||
{
|
{
|
||||||
//CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Reloads configuration file",
|
<<<<<<< HEAD
|
||||||
//ConsoleAccessLevelEnum.AccessOperator);
|
DeterminePlatform();
|
||||||
//CrestronConsole.AddNewConsoleCommand(s => TearDown(), "ungo", "Unloads configuration file",
|
|
||||||
|
//CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file",
|
||||||
// ConsoleAccessLevelEnum.AccessOperator);
|
// ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
=======
|
||||||
|
CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file",
|
||||||
|
ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
>>>>>>> 600b9f11ff1bbc186f7c2a2945955731b3523b3c
|
||||||
|
|
||||||
CrestronConsole.AddNewConsoleCommand(s =>
|
CrestronConsole.AddNewConsoleCommand(s =>
|
||||||
{
|
{
|
||||||
foreach (var tl in TieLineCollection.Default)
|
foreach (var tl in TieLineCollection.Default)
|
||||||
@@ -42,9 +49,64 @@ namespace PepperDash.Essentials
|
|||||||
},
|
},
|
||||||
"listtielines", "Prints out all tie lines", ConsoleAccessLevelEnum.AccessOperator);
|
"listtielines", "Prints out all tie lines", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
GoWithLoad();
|
CrestronConsole.AddNewConsoleCommand(s =>
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse
|
||||||
|
("Current running configuration. This is the merged system and template configuration");
|
||||||
|
CrestronConsole.ConsoleCommandResponse(Newtonsoft.Json.JsonConvert.SerializeObject
|
||||||
|
(ConfigReader.ConfigObject, Newtonsoft.Json.Formatting.Indented));
|
||||||
|
}, "showconfig", "Shows the current running merged config", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
|
CrestronConsole.AddNewConsoleCommand(s =>
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("This system can be found at the following URLs:\r" +
|
||||||
|
"System URL: {0}\r" +
|
||||||
|
"Template URL: {1}", ConfigReader.ConfigObject.SystemUrl, ConfigReader.ConfigObject.TemplateUrl);
|
||||||
|
}, "portalinfo", "Shows portal URLS from configuration", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
|
//GoWithLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the program is running on a processor (appliance) or server (XiO Edge).
|
||||||
|
///
|
||||||
|
/// Sets Global.FilePathPrefix based on platform
|
||||||
|
/// </summary>
|
||||||
|
public void DeterminePlatform()
|
||||||
|
{
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Determining Platform....");
|
||||||
|
|
||||||
|
string filePathPrefix;
|
||||||
|
|
||||||
|
var dirSeparator = Global.DirectorySeparator;
|
||||||
|
|
||||||
|
var version = Crestron.SimplSharp.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
|
||||||
|
var versionString = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
|
||||||
|
|
||||||
|
string directoryPrefix;
|
||||||
|
|
||||||
|
//directoryPrefix = Crestron.SimplSharp.CrestronIO.Directory.GetApplicationRootDirectory();
|
||||||
|
#warning ^ For use with beta Include4.dat for XiO Edge
|
||||||
|
directoryPrefix = "";
|
||||||
|
|
||||||
|
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server)
|
||||||
|
{
|
||||||
|
filePathPrefix = directoryPrefix + dirSeparator + "NVRAM"
|
||||||
|
+ dirSeparator + string.Format("program{0}", InitialParametersClass.ApplicationNumber) + dirSeparator;
|
||||||
|
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on 3-series Appliance", versionString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filePathPrefix = directoryPrefix + dirSeparator + "User" + dirSeparator;
|
||||||
|
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials v{0} on XiO Edge Server", versionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
Global.SetFilePathPrefix(filePathPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Do it, yo
|
/// Do it, yo
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -56,22 +118,17 @@ namespace PepperDash.Essentials
|
|||||||
ConsoleAccessLevelEnum.AccessOperator);
|
ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
//PortalSync = new PepperDashPortalSyncClient();
|
//PortalSync = new PepperDashPortalSyncClient();
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Starting Essentials load from configuration");
|
||||||
Debug.Console(0, "Starting Essentials load from configuration");
|
|
||||||
|
|
||||||
var filesReady = SetupFilesystem();
|
var filesReady = SetupFilesystem();
|
||||||
if (filesReady)
|
if (filesReady)
|
||||||
{
|
{
|
||||||
Debug.Console(0, "Folder structure verified. Loading config...");
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Folder structure verified. Loading config...");
|
||||||
if (!ConfigReader.LoadConfig2())
|
if (!ConfigReader.LoadConfig2())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Load();
|
Load();
|
||||||
<<<<<<< HEAD
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Essentials load complete\r" +
|
||||||
=======
|
|
||||||
|
|
||||||
>>>>>>> origin/feature/ecs-342-neil
|
|
||||||
Debug.Console(0, "Essentials load complete\r" +
|
|
||||||
"-------------------------------------------------------------");
|
"-------------------------------------------------------------");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -101,17 +158,16 @@ namespace PepperDash.Essentials
|
|||||||
bool SetupFilesystem()
|
bool SetupFilesystem()
|
||||||
{
|
{
|
||||||
Debug.Console(0, "Verifying and/or creating folder structure");
|
Debug.Console(0, "Verifying and/or creating folder structure");
|
||||||
var appNum = InitialParametersClass.ApplicationNumber;
|
var configDir = Global.FilePathPrefix;
|
||||||
var configDir = @"\NVRAM\Program" + appNum;
|
|
||||||
var configExists = Directory.Exists(configDir);
|
var configExists = Directory.Exists(configDir);
|
||||||
if (!configExists)
|
if (!configExists)
|
||||||
Directory.Create(configDir);
|
Directory.Create(configDir);
|
||||||
|
|
||||||
var irDir = string.Format(@"\NVRAM\Program{0}\ir", appNum);
|
var irDir = Global.FilePathPrefix + "ir";
|
||||||
if (!Directory.Exists(irDir))
|
if (!Directory.Exists(irDir))
|
||||||
Directory.Create(irDir);
|
Directory.Create(irDir);
|
||||||
|
|
||||||
var sgdDir = string.Format(@"\NVRAM\Program{0}\sgd", appNum);
|
var sgdDir = Global.FilePathPrefix + "sgd";
|
||||||
if (!Directory.Exists(sgdDir))
|
if (!Directory.Exists(sgdDir))
|
||||||
Directory.Create(sgdDir);
|
Directory.Create(sgdDir);
|
||||||
|
|
||||||
@@ -150,11 +206,7 @@ namespace PepperDash.Essentials
|
|||||||
LoadRooms();
|
LoadRooms();
|
||||||
LoadLogoServer();
|
LoadLogoServer();
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
DeviceManager.ActivateAll();
|
DeviceManager.ActivateAll();
|
||||||
=======
|
|
||||||
DeviceManager.ActivateAll();
|
|
||||||
>>>>>>> origin/feature/ecs-342-neil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -168,7 +220,7 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Debug.Console(0, "Creating device '{0}'", devConf.Key);
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Creating device '{0}'", devConf.Key);
|
||||||
// Skip this to prevent unnecessary warnings
|
// Skip this to prevent unnecessary warnings
|
||||||
if (devConf.Key == "processor")
|
if (devConf.Key == "processor")
|
||||||
continue;
|
continue;
|
||||||
@@ -187,13 +239,15 @@ namespace PepperDash.Essentials
|
|||||||
if (newDev != null)
|
if (newDev != null)
|
||||||
DeviceManager.AddDevice(newDev);
|
DeviceManager.AddDevice(newDev);
|
||||||
else
|
else
|
||||||
Debug.Console(0, "ERROR: Cannot load unknown device type '{0}', key '{1}'.", devConf.Type, devConf.Key);
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Cannot load unknown device type '{0}', key '{1}'.", devConf.Type, devConf.Key);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.Console(0, "ERROR: Creating device {0}. Skipping device. \r{1}", devConf.Key, e);
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "ERROR: Creating device {0}. Skipping device. \r{1}", devConf.Key, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Devices Loaded.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -206,12 +260,20 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
var tlc = TieLineCollection.Default;
|
var tlc = TieLineCollection.Default;
|
||||||
//tlc.Clear();
|
//tlc.Clear();
|
||||||
|
if (ConfigReader.ConfigObject.TieLines == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines)
|
foreach (var tieLineConfig in ConfigReader.ConfigObject.TieLines)
|
||||||
{
|
{
|
||||||
var newTL = tieLineConfig.GetTieLine();
|
var newTL = tieLineConfig.GetTieLine();
|
||||||
if (newTL != null)
|
if (newTL != null)
|
||||||
tlc.Add(newTL);
|
tlc.Add(newTL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Tie Lines Loaded.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -219,6 +281,12 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void LoadRooms()
|
public void LoadRooms()
|
||||||
{
|
{
|
||||||
|
if (ConfigReader.ConfigObject.Rooms == null)
|
||||||
|
{
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Warning, "WARNING: Configuration contains no rooms");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
|
foreach (var roomConfig in ConfigReader.ConfigObject.Rooms)
|
||||||
{
|
{
|
||||||
var room = roomConfig.GetRoomObject();
|
var room = roomConfig.GetRoomObject();
|
||||||
@@ -228,33 +296,57 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
DeviceManager.AddDevice(room);
|
DeviceManager.AddDevice(room);
|
||||||
|
|
||||||
Debug.Console(1, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion");
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleSpaceRoom, attempting to add to DeviceManager with Fusion");
|
||||||
DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemControllerBase((EssentialsHuddleSpaceRoom)room, 0xf1));
|
DeviceManager.AddDevice(new EssentialsHuddleSpaceFusionSystemControllerBase((EssentialsHuddleSpaceRoom)room, 0xf1));
|
||||||
|
|
||||||
var cotija = DeviceManager.GetDeviceForKey("cotijaServer") as CotijaSystemController;
|
|
||||||
|
|
||||||
if (cotija != null)
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to build Cotija Bridge...");
|
||||||
{
|
// Cotija bridge
|
||||||
cotija.CotijaRooms.Add(new CotijaEssentialsHuddleSpaceRoomBridge(cotija, room as EssentialsHuddleSpaceRoom));
|
var bridge = new CotijaEssentialsHuddleSpaceRoomBridge(room as EssentialsHuddleSpaceRoom);
|
||||||
}
|
AddBridgePostActivationHelper(bridge); // Lets things happen later when all devices are present
|
||||||
|
DeviceManager.AddDevice(bridge);
|
||||||
|
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Cotija Bridge Added...");
|
||||||
}
|
}
|
||||||
else if (room is EssentialsHuddleVtc1Room)
|
else if (room is EssentialsHuddleVtc1Room)
|
||||||
{
|
{
|
||||||
DeviceManager.AddDevice(room);
|
DeviceManager.AddDevice(room);
|
||||||
|
|
||||||
Debug.Console(1, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion");
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is EssentialsHuddleVtc1Room, attempting to add to DeviceManager with Fusion");
|
||||||
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((EssentialsHuddleVtc1Room)room, 0xf1));
|
DeviceManager.AddDevice(new EssentialsHuddleVtc1FusionController((EssentialsHuddleVtc1Room)room, 0xf1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Console(1, "Room is NOT EssentialsHuddleSpaceRoom, attempting to add to DeviceManager w/o Fusion");
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "Room is NOT EssentialsHuddleSpaceRoom, attempting to add to DeviceManager w/o Fusion");
|
||||||
DeviceManager.AddDevice(room);
|
DeviceManager.AddDevice(room);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Debug.Console(0, "WARNING: Cannot create room from config, key '{0}'", roomConfig.Key);
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create room from config, key '{0}'", roomConfig.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "All Rooms Loaded.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helps add the post activation steps that link bridges to main controller
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bridge"></param>
|
||||||
|
void AddBridgePostActivationHelper(CotijaBridgeBase bridge)
|
||||||
|
{
|
||||||
|
bridge.AddPostActivationAction(() =>
|
||||||
|
{
|
||||||
|
var parent = DeviceManager.AllDevices.FirstOrDefault(d => d.Key == "appServer") as CotijaSystemController;
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
Debug.Console(0, bridge, "ERROR: Cannot connect bridge. System controller not present");
|
||||||
|
}
|
||||||
|
Debug.Console(0, bridge, "Linking to parent controller");
|
||||||
|
bridge.AddParent(parent);
|
||||||
|
parent.AddBridge(bridge);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -262,14 +354,13 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
void LoadLogoServer()
|
void LoadLogoServer()
|
||||||
{
|
{
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LogoServer = new HttpLogoServer(8080, @"\html\logo");
|
LogoServer = new HttpLogoServer(8080, Global.FilePathPrefix + "html" + Global.DirectorySeparator + "logo");
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Debug.Console(0, "NOTICE: Logo server cannot be started. Likely already running in another program");
|
Debug.Console(0, Debug.ErrorLogLevel.Notice, "NOTICE: Logo server cannot be started. Likely already running in another program");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
[assembly: AssemblyProduct("PepperDashEssentials")]
|
[assembly: AssemblyProduct("PepperDashEssentials")]
|
||||||
[assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2017")]
|
[assembly: AssemblyCopyright("Copyright © PepperDash Technology Corp 2017")]
|
||||||
<<<<<<< HEAD
|
<<<<<<< HEAD
|
||||||
[assembly: AssemblyVersion("1.0.31.*")]
|
[assembly: AssemblyVersion("1.1.8.*")]
|
||||||
=======
|
=======
|
||||||
[assembly: AssemblyVersion("1.0.33.*")]
|
[assembly: AssemblyVersion("1.3.0.*")]
|
||||||
>>>>>>> origin/feature/ecs-342-neil
|
|
||||||
|
|
||||||
|
>>>>>>> feature/ecs-684
|
||||||
|
|||||||
@@ -0,0 +1,694 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Crestron.SimplSharp;
|
||||||
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
|
using Crestron.SimplSharp.Reflection;
|
||||||
|
using Crestron.SimplSharpPro.CrestronThread;
|
||||||
|
using Crestron.SimplSharp.CrestronWebSocketClient;
|
||||||
|
using Crestron.SimplSharpPro;
|
||||||
|
using Crestron.SimplSharp.Net.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
using PepperDash.Core;
|
||||||
|
using PepperDash.Essentials.Core;
|
||||||
|
using PepperDash.Essentials.Room.Cotija;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials
|
||||||
|
{
|
||||||
|
public class CotijaSystemController : Device
|
||||||
|
{
|
||||||
|
WebSocketClient WSClient;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents post operations from stomping on each other and getting lost
|
||||||
|
/// </summary>
|
||||||
|
CEvent PostLockEvent = new CEvent(true, true);
|
||||||
|
|
||||||
|
CEvent RegisterLockEvent = new CEvent(true, true);
|
||||||
|
|
||||||
|
public CotijaConfig Config { get; private set; }
|
||||||
|
|
||||||
|
Dictionary<string, Object> ActionDictionary = new Dictionary<string, Object>(StringComparer.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
|
Dictionary<string, CTimer> PushedActions = new Dictionary<string, CTimer>();
|
||||||
|
|
||||||
|
CTimer ServerHeartbeatCheckTimer;
|
||||||
|
|
||||||
|
long ServerHeartbeatInterval = 20000;
|
||||||
|
|
||||||
|
CTimer ServerReconnectTimer;
|
||||||
|
|
||||||
|
long ServerReconnectInterval = 5000;
|
||||||
|
|
||||||
|
string SystemUuid;
|
||||||
|
|
||||||
|
List<CotijaBridgeBase> RoomBridges = new List<CotijaBridgeBase>();
|
||||||
|
|
||||||
|
long ButtonHeartbeatInterval = 1000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used for tracking HTTP debugging
|
||||||
|
/// </summary>
|
||||||
|
bool HttpDebugEnabled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
public CotijaSystemController(string key, string name, CotijaConfig config) : base(key, name)
|
||||||
|
{
|
||||||
|
Config = config;
|
||||||
|
Debug.Console(0, this, "Mobile UI controller initializing for server:{0}", config.ServerUrl);
|
||||||
|
|
||||||
|
CrestronConsole.AddNewConsoleCommand(AuthorizeSystem,
|
||||||
|
"mobileauth", "Authorizes system to talk to cotija server", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
CrestronConsole.AddNewConsoleCommand(s => ShowInfo(),
|
||||||
|
"mobileinfo", "Shows information for current mobile control session", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
CrestronConsole.AddNewConsoleCommand(s => {
|
||||||
|
s = s.Trim();
|
||||||
|
if(!string.IsNullOrEmpty(s))
|
||||||
|
{
|
||||||
|
HttpDebugEnabled = (s.Trim() != "0");
|
||||||
|
}
|
||||||
|
CrestronConsole.ConsoleCommandResponse("HTTP Debug {0}", HttpDebugEnabled ? "Enabled" : "Disabled");
|
||||||
|
},
|
||||||
|
"mobilehttpdebug", "1 enables more verbose HTTP response debugging", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
CrestronConsole.AddNewConsoleCommand(TestHttpRequest,
|
||||||
|
"mobilehttprequest", "Tests an HTTP get to URL given", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
||||||
|
{
|
||||||
|
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.", key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes an action from the dictionary
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key"></param>
|
||||||
|
public void RemoveAction(string key)
|
||||||
|
{
|
||||||
|
if (ActionDictionary.ContainsKey(key))
|
||||||
|
ActionDictionary.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bridge"></param>
|
||||||
|
public void AddBridge(CotijaBridgeBase bridge)
|
||||||
|
{
|
||||||
|
RoomBridges.Add(bridge);
|
||||||
|
var b = bridge as IDelayedConfiguration;
|
||||||
|
if (b != null)
|
||||||
|
{
|
||||||
|
Debug.Console(0, this, "Adding room bridge with delayed configuration");
|
||||||
|
b.ConfigurationIsReady += new EventHandler<EventArgs>(bridge_ConfigurationIsReady);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Console(0, this, "Adding room bridge and sending configuration");
|
||||||
|
RegisterSystemToServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
void bridge_ConfigurationIsReady(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Debug.Console(1, this, "Bridge ready. Registering");
|
||||||
|
// send the configuration object to the server
|
||||||
|
RegisterSystemToServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o"></param>
|
||||||
|
void ReconnectToServerTimerCallback(object o)
|
||||||
|
{
|
||||||
|
RegisterSystemToServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies system connection with servers
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command"></param>
|
||||||
|
void AuthorizeSystem(string code)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(code))
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Please enter a user code to authorize a system");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var req = new HttpClientRequest();
|
||||||
|
string url = string.Format("http://{0}/api/system/grantcode/{1}/{2}", Config.ServerUrl, code, SystemUuid);
|
||||||
|
Debug.Console(0, this, "Authorizing to: {0}", url);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Config.ServerUrl))
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Config URL address is not set. Check portal configuration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
req.Url.Parse(url);
|
||||||
|
new HttpClient().DispatchAsync(req, (r, e) =>
|
||||||
|
{
|
||||||
|
CheckHttpDebug(r, e);
|
||||||
|
if (e == HTTP_CALLBACK_ERROR.COMPLETED)
|
||||||
|
{
|
||||||
|
if (r.Code == 200)
|
||||||
|
{
|
||||||
|
Debug.Console(0, "System authorized, sending config.");
|
||||||
|
RegisterSystemToServer();
|
||||||
|
}
|
||||||
|
else if (r.Code == 404)
|
||||||
|
{
|
||||||
|
if (r.ContentString.Contains("codeNotFound"))
|
||||||
|
{
|
||||||
|
Debug.Console(0, "Authorization failed, code not found for system UUID {0}", SystemUuid);
|
||||||
|
}
|
||||||
|
else if (r.ContentString.Contains("uuidNotFound"))
|
||||||
|
{
|
||||||
|
Debug.Console(0, "Authorization failed, uuid {0} not found. Check Essentials configuration is correct",
|
||||||
|
SystemUuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Debug.Console(0, this, "Error {0} in authorizing system", e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Console(0, this, "Error in authorizing: {0}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dumps info in response to console command.
|
||||||
|
/// </summary>
|
||||||
|
void ShowInfo()
|
||||||
|
{
|
||||||
|
var url = Config != null ? Config.ServerUrl : "No config";
|
||||||
|
string name;
|
||||||
|
string code;
|
||||||
|
if (RoomBridges != null && RoomBridges.Count > 0)
|
||||||
|
{
|
||||||
|
name = RoomBridges[0].RoomName;
|
||||||
|
code = RoomBridges[0].UserCode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = "No config";
|
||||||
|
code = "Not available";
|
||||||
|
}
|
||||||
|
var conn = WSClient == null ? "No client" : (WSClient.Connected ? "Yes" : "No");
|
||||||
|
|
||||||
|
CrestronConsole.ConsoleCommandResponse(@"Mobile Control Information:
|
||||||
|
Server address: {0}
|
||||||
|
System Name: {1}
|
||||||
|
System UUID: {2}
|
||||||
|
System User code: {3}
|
||||||
|
Connected?: {4}", url, name, SystemUuid,
|
||||||
|
code, conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Registers the room with the server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="url">URL of the server, including the port number, if not 80. Format: "serverUrlOrIp:port"</param>
|
||||||
|
void RegisterSystemToServer()
|
||||||
|
{
|
||||||
|
var ready = RegisterLockEvent.Wait(20000);
|
||||||
|
if (!ready)
|
||||||
|
{
|
||||||
|
Debug.Console(1, this, "RegisterSystemToServer failed to enter after 20 seconds. Ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RegisterLockEvent.Reset();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var confObject = ConfigReader.ConfigObject;
|
||||||
|
confObject.Info.RuntimeInfo.AppName = Assembly.GetExecutingAssembly().GetName().Name;
|
||||||
|
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
confObject.Info.RuntimeInfo.AssemblyVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.Build);
|
||||||
|
confObject.Info.RuntimeInfo.OsVersion = Crestron.SimplSharp.CrestronEnvironment.OSVersion.Firmware;
|
||||||
|
|
||||||
|
string postBody = JsonConvert.SerializeObject(confObject);
|
||||||
|
SystemUuid = confObject.SystemUuid;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(postBody))
|
||||||
|
{
|
||||||
|
Debug.Console(1, this, "ERROR: Config body is empty. Cannot register with server.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var regClient = new HttpClient();
|
||||||
|
regClient.Verbose = true;
|
||||||
|
regClient.KeepAlive = true;
|
||||||
|
|
||||||
|
string url = string.Format("http://{0}/api/system/join/{1}", Config.ServerUrl, SystemUuid);
|
||||||
|
Debug.Console(1, this, "Joining server at {0}", url);
|
||||||
|
|
||||||
|
HttpClientRequest request = new HttpClientRequest();
|
||||||
|
request.Url.Parse(url);
|
||||||
|
request.RequestType = RequestType.Post;
|
||||||
|
request.Header.SetHeaderValue("Content-Type", "application/json");
|
||||||
|
request.ContentString = postBody;
|
||||||
|
|
||||||
|
var err = regClient.DispatchAsync(request, RegistrationConnectionCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Console(0, this, "ERROR: Initilizing Room: {0}", e);
|
||||||
|
RegisterLockEvent.Set();
|
||||||
|
StartReconnectTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends a message to the server from a room
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="room">room from which the message originates</param>
|
||||||
|
/// <param name="o">object to be serialized and sent in post body</param>
|
||||||
|
public void SendMessageToServer(JObject o)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (WSClient != null && WSClient.Connected)
|
||||||
|
{
|
||||||
|
string message = JsonConvert.SerializeObject(o, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
|
||||||
|
Debug.Console(1, this, "Message TX: {0}", message);
|
||||||
|
var messageBytes = System.Text.Encoding.UTF8.GetBytes(message);
|
||||||
|
WSClient.Send(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME);
|
||||||
|
//WSClient.SendAsync(messageBytes, (uint)messageBytes.Length, WebSocketClient.WEBSOCKET_PACKET_TYPES.LWS_WS_OPCODE_07__TEXT_FRAME);
|
||||||
|
}
|
||||||
|
<<<<<<< HEAD
|
||||||
|
|
||||||
|
=======
|
||||||
|
|
||||||
|
>>>>>>> feature/ecs-684
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disconnects the SSE Client and stops the heartbeat timer
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command"></param>
|
||||||
|
void DisconnectStreamClient(string command)
|
||||||
|
{
|
||||||
|
//if(SseClient != null)
|
||||||
|
// SseClient.Disconnect();
|
||||||
|
|
||||||
|
if (WSClient != null && WSClient.Connected)
|
||||||
|
WSClient.Disconnect();
|
||||||
|
|
||||||
|
if (ServerHeartbeatCheckTimer != null)
|
||||||
|
{
|
||||||
|
ServerHeartbeatCheckTimer.Stop();
|
||||||
|
|
||||||
|
ServerHeartbeatCheckTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The callback that fires when we get a response from our registration attempt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resp"></param>
|
||||||
|
/// <param name="err"></param>
|
||||||
|
void RegistrationConnectionCallback(HttpClientResponse resp, HTTP_CALLBACK_ERROR err)
|
||||||
|
{
|
||||||
|
CheckHttpDebug(resp, err);
|
||||||
|
Debug.Console(1, this, "RegistrationConnectionCallback: {0}", err);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (resp != null && resp.Code == 200)
|
||||||
|
{
|
||||||
|
if(ServerReconnectTimer != null)
|
||||||
|
{
|
||||||
|
ServerReconnectTimer.Stop();
|
||||||
|
ServerReconnectTimer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success here!
|
||||||
|
ConnectStreamClient();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (resp != null)
|
||||||
|
Debug.Console(1, this, "Response from server: {0}\n{1}", resp.Code, err);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Console(1, this, "Null response received from server.");
|
||||||
|
}
|
||||||
|
StartReconnectTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Console(1, this, "Error Initializing Stream Client: {0}", e);
|
||||||
|
StartReconnectTimer();
|
||||||
|
}
|
||||||
|
RegisterLockEvent.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes when we don't get a heartbeat message in time. Triggers reconnect.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o">For CTimer callback. Not used</param>
|
||||||
|
void HeartbeatExpiredTimerCallback(object o)
|
||||||
|
{
|
||||||
|
Debug.Console(1, this, "Heartbeat Timer Expired.");
|
||||||
|
if (ServerHeartbeatCheckTimer != null)
|
||||||
|
{
|
||||||
|
ServerHeartbeatCheckTimer.Stop();
|
||||||
|
ServerHeartbeatCheckTimer = null;
|
||||||
|
}
|
||||||
|
StartReconnectTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dueTime"></param>
|
||||||
|
/// <param name="repeatTime"></param>
|
||||||
|
void StartReconnectTimer()
|
||||||
|
{
|
||||||
|
// Start the reconnect timer
|
||||||
|
if (ServerReconnectTimer == null)
|
||||||
|
{
|
||||||
|
ServerReconnectTimer = new CTimer(ReconnectToServerTimerCallback, null, ServerReconnectInterval, ServerReconnectInterval);
|
||||||
|
Debug.Console(1, this, "Reconnect Timer Started.");
|
||||||
|
}
|
||||||
|
ServerReconnectTimer.Reset(ServerReconnectInterval, ServerReconnectInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dueTime"></param>
|
||||||
|
/// <param name="repeatTime"></param>
|
||||||
|
void ResetOrStartHearbeatTimer()
|
||||||
|
{
|
||||||
|
if (ServerHeartbeatCheckTimer == null)
|
||||||
|
{
|
||||||
|
ServerHeartbeatCheckTimer = new CTimer(HeartbeatExpiredTimerCallback, null, ServerHeartbeatInterval, ServerHeartbeatInterval);
|
||||||
|
|
||||||
|
Debug.Console(1, this, "Heartbeat Timer Started.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerHeartbeatCheckTimer.Reset(ServerHeartbeatInterval, ServerHeartbeatInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Connects the SSE Client
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="o"></param>
|
||||||
|
void ConnectStreamClient()
|
||||||
|
{
|
||||||
|
Debug.Console(0, this, "Initializing Stream client to server.");
|
||||||
|
|
||||||
|
if (WSClient == null)
|
||||||
|
{
|
||||||
|
WSClient = new WebSocketClient();
|
||||||
|
}
|
||||||
|
WSClient.URL = string.Format("wss://{0}/system/join/{1}", Config.ServerUrl, this.SystemUuid);
|
||||||
|
WSClient.Connect();
|
||||||
|
Debug.Console(0, this, "Websocket connected");
|
||||||
|
WSClient.ReceiveCallBack = WebsocketReceiveCallback;
|
||||||
|
//WSClient.SendCallBack = WebsocketSendCallback;
|
||||||
|
WSClient.ReceiveAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets reconnect timer and updates usercode
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="content"></param>
|
||||||
|
void HandleHeartBeat(JToken content)
|
||||||
|
{
|
||||||
|
var code = content["userCode"];
|
||||||
|
if(code != null)
|
||||||
|
{
|
||||||
|
foreach (var b in RoomBridges)
|
||||||
|
{
|
||||||
|
b.SetUserCode(code.Value<string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResetOrStartHearbeatTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Outputs debug info when enabled
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="req"></param>
|
||||||
|
/// <param name="r"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
void CheckHttpDebug(HttpClientResponse r, HTTP_CALLBACK_ERROR e)
|
||||||
|
{
|
||||||
|
if (HttpDebugEnabled)
|
||||||
|
{
|
||||||
|
Debug.Console(0, this, "------ Begin HTTP Debug ---------------------------------------");
|
||||||
|
Debug.Console(0, this, "HTTP Response URL: {0}", r.ResponseUrl.ToString());
|
||||||
|
Debug.Console(0, this, "HTTP Response 'error' {0}", e);
|
||||||
|
Debug.Console(0, this, "HTTP Response code: {0}", r.Code);
|
||||||
|
Debug.Console(0, this, "HTTP Response content: \r{0}", r.ContentString);
|
||||||
|
Debug.Console(0, this, "------ End HTTP Debug -----------------------------------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data"></param>
|
||||||
|
/// <param name="length"></param>
|
||||||
|
/// <param name="opcode"></param>
|
||||||
|
/// <param name="err"></param>
|
||||||
|
int WebsocketReceiveCallback(byte[] data, uint length, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode,
|
||||||
|
WebSocketClient.WEBSOCKET_RESULT_CODES err)
|
||||||
|
{
|
||||||
|
var rx = System.Text.Encoding.UTF8.GetString(data, 0, (int)length);
|
||||||
|
if(rx.Length > 0)
|
||||||
|
ParseStreamRx(rx);
|
||||||
|
WSClient.ReceiveAsync();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Callback to catch possible errors in sending via the websocket
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
int WebsocketSendCallback(Crestron.SimplSharp.CrestronWebSocketClient.WebSocketClient.WEBSOCKET_RESULT_CODES result)
|
||||||
|
{
|
||||||
|
Debug.Console(1, this, "SendCallback result: {0}", result);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
void ParseStreamRx(string message)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrEmpty(message))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Debug.Console(1, this, "Message RX: '{0}'", message);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var messageObj = JObject.Parse(message);
|
||||||
|
|
||||||
|
var type = messageObj["type"].Value<string>();
|
||||||
|
|
||||||
|
if (type == "hello")
|
||||||
|
{
|
||||||
|
ResetOrStartHearbeatTimer();
|
||||||
|
}
|
||||||
|
else if (type == "/system/heartbeat")
|
||||||
|
{
|
||||||
|
HandleHeartBeat(messageObj["content"]);
|
||||||
|
}
|
||||||
|
else if (type == "close")
|
||||||
|
{
|
||||||
|
WSClient.Disconnect();
|
||||||
|
|
||||||
|
ServerHeartbeatCheckTimer.Stop();
|
||||||
|
// Start the reconnect timer
|
||||||
|
StartReconnectTimer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Check path against Action dictionary
|
||||||
|
if (ActionDictionary.ContainsKey(type))
|
||||||
|
{
|
||||||
|
var action = ActionDictionary[type];
|
||||||
|
|
||||||
|
if (action is Action)
|
||||||
|
{
|
||||||
|
(action as Action)();
|
||||||
|
}
|
||||||
|
else if (action is PressAndHoldAction)
|
||||||
|
{
|
||||||
|
var stateString = messageObj["content"]["state"].Value<string>();
|
||||||
|
|
||||||
|
// Look for a button press event
|
||||||
|
if (!string.IsNullOrEmpty(stateString))
|
||||||
|
{
|
||||||
|
switch (stateString)
|
||||||
|
{
|
||||||
|
case "true":
|
||||||
|
{
|
||||||
|
if (!PushedActions.ContainsKey(type))
|
||||||
|
{
|
||||||
|
PushedActions.Add(type, new CTimer(o =>
|
||||||
|
{
|
||||||
|
(action as PressAndHoldAction)(false);
|
||||||
|
PushedActions.Remove(type);
|
||||||
|
}, null, ButtonHeartbeatInterval, ButtonHeartbeatInterval));
|
||||||
|
}
|
||||||
|
// Maybe add an else to reset the timer
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "held":
|
||||||
|
{
|
||||||
|
if (!PushedActions.ContainsKey(type))
|
||||||
|
{
|
||||||
|
PushedActions[type].Reset(ButtonHeartbeatInterval, ButtonHeartbeatInterval);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "false":
|
||||||
|
{
|
||||||
|
if (PushedActions.ContainsKey(type))
|
||||||
|
{
|
||||||
|
PushedActions[type].Stop();
|
||||||
|
PushedActions.Remove(type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(action as PressAndHoldAction)(stateString == "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (action is Action<bool>)
|
||||||
|
{
|
||||||
|
var stateString = messageObj["content"]["state"].Value<string>();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(stateString))
|
||||||
|
{
|
||||||
|
(action as Action<bool>)(stateString == "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (action is Action<ushort>)
|
||||||
|
{
|
||||||
|
(action as Action<ushort>)(messageObj["content"]["value"].Value<ushort>());
|
||||||
|
}
|
||||||
|
else if (action is Action<string>)
|
||||||
|
{
|
||||||
|
(action as Action<string>)(messageObj["content"]["value"].Value<string>());
|
||||||
|
}
|
||||||
|
else if (action is Action<SourceSelectMessageContent>)
|
||||||
|
{
|
||||||
|
(action as Action<SourceSelectMessageContent>)(messageObj["content"]
|
||||||
|
.ToObject<SourceSelectMessageContent>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Console(1, this, "-- Warning: Incoming message has no registered handler");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception err)
|
||||||
|
{
|
||||||
|
//Debug.Console(1, "SseMessageLengthBeforeFailureCount: {0}", SseMessageLengthBeforeFailureCount);
|
||||||
|
//SseMessageLengthBeforeFailureCount = 0;
|
||||||
|
Debug.Console(1, this, "Unable to parse message: {0}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestHttpRequest(string s)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
s = s.Trim();
|
||||||
|
if (string.IsNullOrEmpty(s))
|
||||||
|
{
|
||||||
|
PrintTestHttpRequestUsage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var tokens = s.Split(' ');
|
||||||
|
if (tokens.Length < 2)
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Too few paramaters\r");
|
||||||
|
PrintTestHttpRequestUsage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var url = tokens[1];
|
||||||
|
if (tokens[0].ToLower() == "get")
|
||||||
|
{
|
||||||
|
var resp = new HttpClient().Get(url);
|
||||||
|
CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp);
|
||||||
|
}
|
||||||
|
else if (tokens[0].ToLower() == "post")
|
||||||
|
{
|
||||||
|
var resp = new HttpClient().Post(url, new byte[] { });
|
||||||
|
CrestronConsole.ConsoleCommandResponse("RESPONSE:\r{0}\r\r", resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Only get or post supported\r");
|
||||||
|
PrintTestHttpRequestUsage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (HttpException e)
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Exception in request:\r");
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Response URL: {0}\r", e.Response.ResponseUrl);
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Response Error Code: {0}\r", e.Response.Code);
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Response body: {0}\r", e.Response.ContentString);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintTestHttpRequestUsage()
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("Usage: mobilehttprequest:N get/post url\r");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -13,14 +13,10 @@ using PepperDash.Essentials.Core.PageManagers;
|
|||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
public class EssentialsTouchpanelController : Device, ICommunicationMonitor
|
public class EssentialsTouchpanelController : Device
|
||||||
{
|
{
|
||||||
public BasicTriListWithSmartObject Panel { get; private set; }
|
public BasicTriListWithSmartObject Panel { get; private set; }
|
||||||
|
|
||||||
public StatusMonitorBase CommunicationMonitor { get; private set; }
|
|
||||||
|
|
||||||
public bool IncludeInFusionRoomHealth { get; private set; }
|
|
||||||
|
|
||||||
public PanelDriverBase PanelDriver { get; private set; }
|
public PanelDriverBase PanelDriver { get; private set; }
|
||||||
|
|
||||||
CTimer BacklightTransitionedOnTimer;
|
CTimer BacklightTransitionedOnTimer;
|
||||||
@@ -40,12 +36,11 @@ namespace PepperDash.Essentials
|
|||||||
public EssentialsTouchpanelController(string key, string name, string type, CrestronTouchpanelPropertiesConfig props, uint id)
|
public EssentialsTouchpanelController(string key, string name, string type, CrestronTouchpanelPropertiesConfig props, uint id)
|
||||||
: base(key, name)
|
: base(key, name)
|
||||||
{
|
{
|
||||||
IncludeInFusionRoomHealth = props.IncludeInFusionRoomHealth;
|
|
||||||
|
|
||||||
Debug.Console(0, this, "Creating hardware...");
|
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Creating touchpanel hardware...");
|
||||||
type = type.ToLower();
|
type = type.ToLower();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (type == "crestronapp")
|
if (type == "crestronapp")
|
||||||
{
|
{
|
||||||
var app = new CrestronApp(id, Global.ControlSystem);
|
var app = new CrestronApp(id, Global.ControlSystem);
|
||||||
@@ -70,168 +65,45 @@ namespace PepperDash.Essentials
|
|||||||
Panel = new Tsw1052(id, Global.ControlSystem);
|
Panel = new Tsw1052(id, Global.ControlSystem);
|
||||||
else if (type == "tsw1060")
|
else if (type == "tsw1060")
|
||||||
Panel = new Tsw1060(id, Global.ControlSystem);
|
Panel = new Tsw1060(id, Global.ControlSystem);
|
||||||
else if (type == "xpanel")
|
|
||||||
Panel = new XpanelForSmartGraphics(id, Global.ControlSystem);
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, "WARNING: Cannot create TSW controller with type '{0}'", type);
|
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW controller with type '{0}'", type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserved sigs
|
||||||
|
if (Panel is TswFt5ButtonSystem)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message);
|
var tsw = Panel as TswFt5ButtonSystem;
|
||||||
|
tsw.ExtenderSystemReservedSigs.Use();
|
||||||
|
tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange
|
||||||
|
+= ExtenderSystemReservedSigs_DeviceExtenderSigChange;
|
||||||
|
|
||||||
|
tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Panel.Register() != eDeviceRegistrationUnRegistrationResponse.Success)
|
||||||
|
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "WARNING: Registration failed. Continuing, but panel may not function: {0}", Panel.RegistrationFailureReason);
|
||||||
|
|
||||||
|
// Give up cleanly if SGD is not present.
|
||||||
|
var sgdName = Global.FilePathPrefix
|
||||||
|
+ Global.DirectorySeparator + "sgd" + Global.DirectorySeparator + props.SgdFile;
|
||||||
|
if (!File.Exists(sgdName))
|
||||||
|
{
|
||||||
|
Debug.Console(0, this, "ERROR: Smart object file '{0}' not present. Exiting TSW load", sgdName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommunicationMonitor = new CrestronGenericBaseCommunicationMonitor(this, Panel, 30000, 120000);
|
Panel.LoadSmartObjects(sgdName);
|
||||||
|
Panel.SigChange += Tsw_SigChange;
|
||||||
|
|
||||||
AddPostActivationAction(() =>
|
|
||||||
{
|
|
||||||
//Debug.Console(0, this, "Creating hardware...");
|
|
||||||
//type = type.ToLower();
|
|
||||||
//try
|
|
||||||
//{
|
|
||||||
// if (type == "crestronapp")
|
|
||||||
// {
|
|
||||||
// var app = new CrestronApp(id, Global.ControlSystem);
|
|
||||||
// app.ParameterProjectName.Value = props.ProjectName;
|
|
||||||
// Panel = app;
|
|
||||||
// }
|
|
||||||
// else if (type == "tsw550")
|
|
||||||
// Panel = new Tsw550(id, Global.ControlSystem);
|
|
||||||
// else if (type == "tsw552")
|
|
||||||
// Panel = new Tsw552(id, Global.ControlSystem);
|
|
||||||
// else if (type == "tsw560")
|
|
||||||
// Panel = new Tsw560(id, Global.ControlSystem);
|
|
||||||
// else if (type == "tsw750")
|
|
||||||
// Panel = new Tsw750(id, Global.ControlSystem);
|
|
||||||
// else if (type == "tsw752")
|
|
||||||
// Panel = new Tsw752(id, Global.ControlSystem);
|
|
||||||
// else if (type == "tsw760")
|
|
||||||
// Panel = new Tsw760(id, Global.ControlSystem);
|
|
||||||
// else if (type == "tsw1050")
|
|
||||||
// Panel = new Tsw1050(id, Global.ControlSystem);
|
|
||||||
// else if (type == "tsw1052")
|
|
||||||
// Panel = new Tsw1052(id, Global.ControlSystem);
|
|
||||||
// else if (type == "tsw1060")
|
|
||||||
// Panel = new Tsw1060(id, Global.ControlSystem);
|
|
||||||
// else if (type == "xpanel")
|
|
||||||
// Panel = new XpanelForSmartGraphics(id, Global.ControlSystem);
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// Debug.Console(0, this, "WARNING: Cannot create TSW controller with type '{0}'", type);
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//catch (Exception e)
|
|
||||||
//{
|
|
||||||
// Debug.Console(0, this, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message);
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
// Reserved sigs
|
|
||||||
if (Panel is TswFt5ButtonSystem)
|
|
||||||
{
|
|
||||||
var tsw = Panel as TswFt5ButtonSystem;
|
|
||||||
tsw.ExtenderSystemReservedSigs.Use();
|
|
||||||
tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange
|
|
||||||
+= ExtenderSystemReservedSigs_DeviceExtenderSigChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
//CrestronInvoke.BeginInvoke(o =>
|
|
||||||
// {
|
|
||||||
var regSuccess = Panel.Register();
|
|
||||||
if (regSuccess != eDeviceRegistrationUnRegistrationResponse.Success)
|
|
||||||
Debug.Console(0, this, "WARNING: Registration failed. Continuing, but panel may not function: {0}", regSuccess);
|
|
||||||
|
|
||||||
// Give up cleanly if SGD is not present.
|
|
||||||
var sgdName = @"\NVRAM\Program" + InitialParametersClass.ApplicationNumber
|
|
||||||
+ @"\sgd\" + props.SgdFile;
|
|
||||||
if (!File.Exists(sgdName))
|
|
||||||
{
|
|
||||||
Debug.Console(0, this, "ERROR: Smart object file '{0}' not present. Exiting TSW load", sgdName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Panel.LoadSmartObjects(sgdName);
|
|
||||||
Panel.SigChange += Tsw_SigChange;
|
|
||||||
|
|
||||||
var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, props);
|
|
||||||
// Then the AV driver
|
|
||||||
|
|
||||||
// spin up different room drivers depending on room type
|
|
||||||
var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey);
|
|
||||||
if (room is EssentialsHuddleSpaceRoom)
|
|
||||||
{
|
|
||||||
Debug.Console(0, this, "Adding huddle space driver");
|
|
||||||
var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, props);
|
|
||||||
avDriver.CurrentRoom = room as EssentialsHuddleSpaceRoom;
|
|
||||||
avDriver.DefaultRoomKey = props.DefaultRoomKey;
|
|
||||||
mainDriver.AvDriver = avDriver;
|
|
||||||
LoadAndShowDriver(mainDriver); // This is a little convoluted.
|
|
||||||
|
|
||||||
if (Panel is TswFt5ButtonSystem)
|
|
||||||
{
|
|
||||||
var tsw = Panel as TswFt5ButtonSystem;
|
|
||||||
// Wire up hard keys
|
|
||||||
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.PowerButtonPressed(); });
|
|
||||||
//tsw.Home.UserObject = new Action<bool>(b => { if (!b) HomePressed(); });
|
|
||||||
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
|
|
||||||
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
|
|
||||||
tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (room is EssentialsPresentationRoom)
|
|
||||||
{
|
|
||||||
Debug.Console(0, this, "Adding presentation room driver");
|
|
||||||
var avDriver = new EssentialsPresentationPanelAvFunctionsDriver(mainDriver, props);
|
|
||||||
avDriver.CurrentRoom = room as EssentialsPresentationRoom;
|
|
||||||
avDriver.DefaultRoomKey = props.DefaultRoomKey;
|
|
||||||
mainDriver.AvDriver = avDriver;
|
|
||||||
LoadAndShowDriver(mainDriver);
|
|
||||||
|
|
||||||
if (Panel is TswFt5ButtonSystem)
|
|
||||||
{
|
|
||||||
var tsw = Panel as TswFt5ButtonSystem;
|
|
||||||
// Wire up hard keys
|
|
||||||
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.PowerButtonPressed(); });
|
|
||||||
//tsw.Home.UserObject = new Action<bool>(b => { if (!b) HomePressed(); });
|
|
||||||
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
|
|
||||||
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
|
|
||||||
tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (room is EssentialsHuddleVtc1Room)
|
|
||||||
{
|
|
||||||
Debug.Console(0, this, "Adding huddle space driver");
|
|
||||||
var avDriver = new EssentialsHuddleVtc1PanelAvFunctionsDriver(mainDriver, props);
|
|
||||||
var codecDriver = new PepperDash.Essentials.UIDrivers.VC.EssentialsVideoCodecUiDriver(Panel, avDriver,
|
|
||||||
(room as EssentialsHuddleVtc1Room).VideoCodec);
|
|
||||||
avDriver.SetVideoCodecDriver(codecDriver);
|
|
||||||
avDriver.CurrentRoom = room as EssentialsHuddleVtc1Room;
|
|
||||||
avDriver.DefaultRoomKey = props.DefaultRoomKey;
|
|
||||||
mainDriver.AvDriver = avDriver;
|
|
||||||
LoadAndShowDriver(mainDriver); // This is a little convoluted.
|
|
||||||
|
|
||||||
if (Panel is TswFt5ButtonSystem)
|
|
||||||
{
|
|
||||||
var tsw = Panel as TswFt5ButtonSystem;
|
|
||||||
// Wire up hard keys
|
|
||||||
tsw.Power.UserObject = new Action<bool>(b => { if (!b) avDriver.EndMeetingPress(); });
|
|
||||||
//tsw.Home.UserObject = new Action<bool>(b => { if (!b) HomePressed(); });
|
|
||||||
tsw.Up.UserObject = new Action<bool>(avDriver.VolumeUpPress);
|
|
||||||
tsw.Down.UserObject = new Action<bool>(avDriver.VolumeDownPress);
|
|
||||||
tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Console(0, this, "ERROR: Cannot load AvFunctionsDriver for room '{0}'", props.DefaultRoomKey);
|
|
||||||
}
|
|
||||||
//}, 0);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadAndShowDriver(PanelDriverBase driver)
|
public void LoadAndShowDriver(PanelDriverBase driver)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user