diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/CrestronWebServerBase.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/CrestronWebServerBase.cs
new file mode 100644
index 00000000..d9649a7d
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/CrestronWebServerBase.cs
@@ -0,0 +1,197 @@
+using System;
+using Crestron.SimplSharp;
+using Crestron.SimplSharp.WebScripting;
+using PepperDash.Core;
+
+namespace PepperDash.Essentials.Core
+{
+ public class CrestronWebServerBase : EssentialsDevice, IDisposable
+ {
+ private HttpCwsServer _server;
+ private readonly CCriticalSection _serverLock = new CCriticalSection();
+
+ ///
+ /// CWS base path
+ ///
+ public string BasePath { get; private set; }
+
+ ///
+ /// Constructor
+ ///
+ ///
+ ///
+ ///
+ public CrestronWebServerBase(string key, string name, string basePath)
+ : base(key, name)
+ {
+ Key = key;
+
+ BasePath = string.IsNullOrEmpty(basePath) ? "/api" : basePath;
+
+ CrestronEnvironment.ProgramStatusEventHandler += programEvent =>
+ {
+ if (programEvent != eProgramStatusEventType.Stopping)
+ return;
+
+ Dispose(true);
+ };
+ }
+
+ ///
+ /// Initializes the CWS class
+ ///
+ public override void Initialize()
+ {
+ ServerStart();
+ base.Initialize();
+ }
+
+ ///
+ /// Starts the CWS server
+ ///
+ public void ServerStart()
+ {
+ try
+ {
+ _serverLock.Enter();
+
+ if (_server != null)
+ {
+ Debug.Console(1, this, "Server is already running");
+ return;
+ }
+
+ Debug.Console(1, this, "Starting server");
+
+ _server = new HttpCwsServer(BasePath)
+ {
+ HttpRequestHandler = new RequestHandlerUnknown()
+ };
+
+ // TODO [ ] Add server paths
+ }
+ catch (Exception ex)
+ {
+ Debug.Console(1, this, "ServerStart Exception Message: {0}", ex.Message);
+ Debug.Console(2, this, "ServerStart Exception StackTrace: {0}", ex.StackTrace);
+ if (ex.InnerException != null)
+ Debug.Console(2, this, "ServerStart Exception InnerException: {0}", ex.InnerException);
+ }
+ finally
+ {
+ _serverLock.Leave();
+ }
+ }
+
+ ///
+ /// Stops the CWS server
+ ///
+ public void ServerStop()
+ {
+ try
+ {
+ _serverLock.Enter();
+ if (_server == null)
+ {
+ Debug.Console(1, this, "Server is already stopped");
+ return;
+ }
+
+ _server.Unregister();
+ _server.Dispose();
+ _server = null;
+ }
+ catch (Exception ex)
+ {
+ Debug.Console(1, this, "ServerStop Exception Message: {0}", ex.Message);
+ Debug.Console(2, this, "ServerStop Exception StackTrace: {0}", ex.StackTrace);
+ if (ex.InnerException != null)
+ Debug.Console(2, this, "ServerStop Exception InnerException: {0}", ex.InnerException);
+ }
+ finally
+ {
+ _serverLock.Leave();
+ }
+ }
+
+ ///
+ /// Received request handler
+ ///
+ ///
+ ///
+ public void ReceivedRequestEventHandler(object sender, HttpCwsRequestEventArgs args)
+ {
+ try
+ {
+ // TODO [ ] Add logic for received requests
+ Debug.Console(1, this, @"RecieveRequestEventHandler
+Method: {0}
+Path: {1}
+PathInfo: {2}
+PhysicalPath: {3}
+ContentType: {4}
+RawUrl: {5}
+Url: {6}
+UserAgent: {7}
+UserHostAddress: {8}
+UserHostName: {9}",
+ args.Context.Request.HttpMethod,
+ args.Context.Request.Path,
+ args.Context.Request.PathInfo,
+ args.Context.Request.PhysicalPath,
+ args.Context.Request.ContentType,
+ args.Context.Request.RawUrl,
+ args.Context.Request.Url,
+ args.Context.Request.UserAgent,
+ args.Context.Request.UserHostAddress,
+ args.Context.Request.UserHostName);
+
+ }
+ catch (Exception ex)
+ {
+ Debug.Console(1, this, "ReceivedRequestEventHandler Exception Message: {0}", ex.Message);
+ Debug.Console(2, this, "ReceivedRequestEventHandler Exception StackTrace: {0}", ex.StackTrace);
+ if (ex.InnerException != null)
+ Debug.Console(2, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException);
+ }
+ }
+
+ #region Dispose
+
+ ///
+ /// Tracks if the CWS is disposed
+ ///
+ public bool Disposed { get; private set; }
+
+ ///
+ /// Disposes of the CWS
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ CrestronEnvironment.GC.SuppressFinalize(this);
+ }
+
+ protected void Dispose(bool disposing)
+ {
+ if (Disposed)
+ {
+ Debug.Console(1, this, "Server has already been disposed");
+ return;
+ }
+
+ if (!disposing) return;
+
+ if (_server != null) ServerStop();
+
+ Disposed = _server == null;
+ }
+
+ ~CrestronWebServerBase()
+ {
+ Dispose(true);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/CrestronWebServerFactory.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/CrestronWebServerFactory.cs
new file mode 100644
index 00000000..ab442ecb
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/CrestronWebServerFactory.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using PepperDash.Core;
+using PepperDash.Essentials.Core.Config;
+
+namespace PepperDash.Essentials.Core
+{
+ public class CrestronWebServerFactory : EssentialsDeviceFactory
+ {
+ public CrestronWebServerFactory()
+ {
+ TypeNames = new List { "crestroncws", "cws" };
+ }
+ public override EssentialsDevice BuildDevice(DeviceConfig dc)
+ {
+ Debug.Console(1, "Factory Attempting to create new Crestron CWS Device");
+
+ return new CrestronWebServerBase(dc.Key, dc.Name, "");
+ }
+ }
+}
\ No newline at end of file
diff --git a/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/RequestHandlerUnknown.cs b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/RequestHandlerUnknown.cs
new file mode 100644
index 00000000..71cf383a
--- /dev/null
+++ b/essentials-framework/Essentials Core/PepperDashEssentialsBase/Crestron Web Server/RequestHandlerUnknown.cs
@@ -0,0 +1,19 @@
+using Crestron.SimplSharp.WebScripting;
+
+namespace PepperDash.Essentials.Core
+{
+ ///
+ /// Crestron CWS unknown request handler
+ ///
+ public class RequestHandlerUnknown : IHttpCwsHandler
+ {
+
+ public void ProcessRequest(HttpCwsContext context)
+ {
+ // TODO [ ] Modify unknown request handler
+ context.Response.StatusCode = 418;
+ context.Response.ContentType = "application/json";
+ context.Response.Write(string.Format("{0} {1}", context.Request.HttpMethod, context.Request.RawUrl), true);
+ }
+ }
+}
\ No newline at end of file