Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor library to support multiple drivers. #62

Merged
merged 3 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions PSI/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
"name": "server",
"bin": "./server.js",
"dependencies": {
"@zwave-js/server": "1.33.0",
"zwave-js": "12.2.1"
"@zwave-js/server": "1.34.0",
"zwave-js": "12.4.4"
},
"devDependencies": {
"pkg": "^5.8.1",
"esbuild": "^0.19.5"
"@yao-pkg/pkg": "^5.11.4",
"esbuild": "^0.20.1"
},
"scripts": {
"build": "npm run do_esbuild && npm run do_pkgbuild",
Expand Down
127 changes: 64 additions & 63 deletions Visual Studio Projects/ZWaveJS.NET/ZWaveJS.NET/Controller.cs

Large diffs are not rendered by default.

79 changes: 51 additions & 28 deletions Visual Studio Projects/ZWaveJS.NET/ZWaveJS.NET/Driver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ namespace ZWaveJS.NET
{
public class Driver
{
internal static volatile Driver Instance;
// Global List of Socket Ports that are registered
internal static List<int> UsedPorts = new List<int>();

internal Websocket.Client.WebsocketClient ClientWebSocket;
internal Dictionary<Guid, Action<JObject>> Callbacks;
Expand All @@ -22,13 +23,15 @@ public class Driver
private Dictionary<string, Action<JObject>> NodeEventMap;
private Dictionary<string, Action<JObject>> ControllerEventMap;
private Dictionary<string, Action<JObject>> DriverEventMap;
private static Semver.SemVersion SchemaVersionID = new Semver.SemVersion(1, 33, 0);
private Semver.SemVersion SchemaVersionID = new Semver.SemVersion(1, 34, 0);
private string SerialPort;
private bool RequestedExit = false;
private JsonSerializer _jsonSerializer;


private Uri WSAddress;
private bool Host = true;
private Server _server;

private string _ZWaveJSDriverVersion;
public string ZWJSS_DriverVersion
Expand All @@ -48,8 +51,8 @@ public string ZWJSS_ServerVersion
}
}

public static int ServerCommunicationPort = 50001;
public static int ServerErrorThrottleTime = 10000;
public int ServerCommunicationPort { get; private set; }
public int ServerErrorThrottleTime { get; private set; }
private DateTime LastError;

public Controller Controller { get; internal set; }
Expand Down Expand Up @@ -226,7 +229,7 @@ private void MapNodeEvents()
NodeEventMap.Add("ready", (JO) =>
{
int NID = JO.SelectToken("event.nodeId").ToObject<int>();
ZWaveNode NNI = JO.SelectToken("event.nodeState").ToObject<ZWaveNode>();
ZWaveNode NNI = JO.SelectToken("event.nodeState").ToObject<ZWaveNode>(_jsonSerializer);

ZWaveNode N = this.Controller.Nodes.Get(NID);
this.Controller.Nodes.ReplaceInformation(NNI, N);
Expand Down Expand Up @@ -402,7 +405,7 @@ private void MapControllerEvents()
int NID = JO.SelectToken("event.node.nodeId").ToObject<int>();
InclusionResultArgs IR = JO.SelectToken("event.result").ToObject<InclusionResultArgs>();

ZWaveNode NN = new ZWaveNode();
ZWaveNode NN = new ZWaveNode(this);
NN.id = NID;

this.Controller.Nodes.AddNodeToCollection(NN);
Expand Down Expand Up @@ -516,15 +519,19 @@ private void MapEvents()
}

// Client Mode
public Driver(Uri Server, int SchemaVersion = 0)
public Driver(Uri Server, int SchemaVersion = 0, int ServerErrorThrottleTime = 10000)
{

Instance = this;

Newtonsoft.Json.JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};

var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
settings.Converters.Add(new ZWJSSJsonConverter(this));
_jsonSerializer = JsonSerializer.Create(settings);

if (SchemaVersion > 0)
{
Expand All @@ -536,43 +543,56 @@ public Driver(Uri Server, int SchemaVersion = 0)

this.WSAddress = Server;
this.Host = false;
this.ServerErrorThrottleTime = ServerErrorThrottleTime;

InternalPrep();

}

// Host Mode
public Driver(string SerialPort, ZWaveOptions Options)
public Driver(string SerialPort, ZWaveOptions Options, int ServerCommunicationPort = 50001, int ServerErrorThrottleTime = 10000)
{

Instance = this;

if (UsedPorts.Contains(ServerCommunicationPort))
{
throw new Exception(string.Format("Web Socket Port: {0} already in use", ServerCommunicationPort));
}

UsedPorts.Add(ServerCommunicationPort);

Newtonsoft.Json.JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore
};

var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
settings.Converters.Add(new ZWJSSJsonConverter(this));
_jsonSerializer = JsonSerializer.Create(settings);

Callbacks = new Dictionary<Guid, Action<JObject>>();
MapEvents();

this.SerialPort = SerialPort;
this.Options = Options;
this.ServerCommunicationPort = ServerCommunicationPort;
this.WSAddress = new Uri("ws://localhost:" + ServerCommunicationPort);
this.Host = true;
this.ServerErrorThrottleTime = ServerErrorThrottleTime;
this._server = new Server();

InternalPrep();

}

// Prep
private void InternalPrep()
{
if (this.Host)
{

Server.Start(SerialPort, Options, ServerCommunicationPort);
Server.Exited += Server_Exited;
Server.FatalError += Server_FatalError;
_server.Start(SerialPort, Options, ServerCommunicationPort);
_server.Exited += Server_Exited;
_server.FatalError += Server_FatalError;
}

var Factory = new Func<ClientWebSocket>(() => new ClientWebSocket
Expand Down Expand Up @@ -657,14 +677,19 @@ private void DestroySocket()
ClientWebSocket.Stop(WebSocketCloseStatus.NormalClosure, "Destroy");
}

if (Host)
{
UsedPorts.Remove(WSAddress.Port);
}

ClientWebSocket.Dispose();
ClientWebSocket = null;
}
}

private void DestroyServer()
{
Server.Terminate();
_server?.Terminate();
}

public void Destroy()
Expand All @@ -678,10 +703,7 @@ public void Destroy()
}

DestroySocket();
DestroyServer();



DestroyServer();
}

async internal void Restart()
Expand Down Expand Up @@ -767,9 +789,10 @@ private void StartListetningCB(JObject JO)
{
if (JO.Value<bool>("success"))
{
Controller C = JO.SelectToken("result.state.controller").ToObject<Controller>();
Controller C = JO.SelectToken("result.state.controller").ToObject<Controller>(_jsonSerializer);


ZWaveNode[] Nodes = JO.SelectToken("result.state.nodes").ToObject<ZWaveNode[]>();
ZWaveNode[] Nodes = JO.SelectToken("result.state.nodes").ToObject<ZWaveNode[]>(_jsonSerializer);
C.deviceConfig = Nodes.FirstOrDefault((N) => N.isControllerNode).deviceConfig;
Nodes = Nodes.Where((N) => !N.isControllerNode).ToArray();

Expand Down
16 changes: 10 additions & 6 deletions Visual Studio Projects/ZWaveJS.NET/ZWaveJS.NET/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ namespace ZWaveJS.NET
{
public class Endpoint
{
internal Endpoint() { }

private Driver _driver;
internal Endpoint(Driver driver = null)
{
_driver = driver;
}

// CHECKED
public Task<CMDResult> SupportsCCAPI(int CommandClass)
{
Guid ID = Guid.NewGuid();

TaskCompletionSource<CMDResult> Result = new TaskCompletionSource<CMDResult>();
Driver.Instance.Callbacks.Add(ID, (JO) =>
_driver.Callbacks.Add(ID, (JO) =>
{
CMDResult Res = new CMDResult(JO);
if (Res.Success)
Expand All @@ -36,7 +40,7 @@ public Task<CMDResult> SupportsCCAPI(int CommandClass)
Request.Add("commandClass", CommandClass);

string RequestPL = JsonConvert.SerializeObject(Request);
Driver.Instance.ClientWebSocket.SendInstant(RequestPL);
_driver.ClientWebSocket.SendInstant(RequestPL);

return Result.Task;
}
Expand All @@ -48,7 +52,7 @@ public Task<CMDResult> InvokeCCAPI(int CommandClass, string Method, params objec
Guid ID = Guid.NewGuid();

TaskCompletionSource<CMDResult> Result = new TaskCompletionSource<CMDResult>();
Driver.Instance.Callbacks.Add(ID, (JO) =>
_driver.Callbacks.Add(ID, (JO) =>
{
CMDResult Res = new CMDResult(JO);
if (Res.Success)
Expand All @@ -71,7 +75,7 @@ public Task<CMDResult> InvokeCCAPI(int CommandClass, string Method, params objec


string RequestPL = JsonConvert.SerializeObject(Request);
Driver.Instance.ClientWebSocket.SendInstant(RequestPL);
_driver.ClientWebSocket.SendInstant(RequestPL);

return Result.Task;
}
Expand Down
29 changes: 16 additions & 13 deletions Visual Studio Projects/ZWaveJS.NET/ZWaveJS.NET/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ namespace ZWaveJS.NET
internal class Server
{

private static Process ServerProcess;


private Process ServerProcess;

internal delegate void FatalErrorEvent();
internal static event FatalErrorEvent FatalError;
internal event FatalErrorEvent FatalError;

internal delegate void ProcessdExitedEvent();
internal static event ProcessdExitedEvent Exited;
internal event ProcessdExitedEvent Exited;

internal static void Terminate()
internal void Terminate()
{
if (ServerProcess != null && !ServerProcess.HasExited)
{
Expand All @@ -26,21 +28,26 @@ internal static void Terminate()
}
}

internal static void Start(string SerialPort, ZWaveOptions Config, int WSPort)
internal void Start(string SerialPort, ZWaveOptions Config, int WSPort)
{


Process[] Zombies = Process.GetProcessesByName("server.psi");
string ProcessName = string.Format("server.{0}.psi", WSPort);

Process[] Zombies = Process.GetProcessesByName(ProcessName);
foreach(Process Zombie in Zombies)
{
Zombie.Kill();
File.Delete(ProcessName);
}

if (!File.Exists("server.psi"))
{
throw new FileNotFoundException("No Platform Snapshot Image (server.psi) found");
}

File.Copy("server.psi",ProcessName, true);

JsonSerializerSettings JSS = new JsonSerializerSettings();
JSS.NullValueHandling = NullValueHandling.Ignore;
string _Config = JsonConvert.SerializeObject(Config, JSS);
Expand All @@ -58,7 +65,7 @@ internal static void Start(string SerialPort, ZWaveOptions Config, int WSPort)
PSI.EnvironmentVariables.Add("WS_PORT", WSPort.ToString());
PSI.EnvironmentVariables.Add("NODE_ENV", "production");

PSI.FileName = "server.psi";
PSI.FileName = ProcessName;
PSI.UseShellExecute = false;
PSI.WindowStyle = ProcessWindowStyle.Hidden;
PSI.CreateNoWindow = true;
Expand All @@ -70,17 +77,15 @@ internal static void Start(string SerialPort, ZWaveOptions Config, int WSPort)
ServerProcess.StartInfo = PSI;
ServerProcess.Start();
ServerProcess.BeginErrorReadLine();


}

private static void ServerProcess_Exited(object sender, EventArgs e)
private void ServerProcess_Exited(object sender, EventArgs e)
{
// Exited?.Invoke(); I think this will be indirectly handled by the socket client now
ServerProcess.Dispose();
}

private static void ServerProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
private void ServerProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
int Code;
if (int.TryParse(e.Data, out Code))
Expand All @@ -92,8 +97,6 @@ private static void ServerProcess_ErrorDataReceived(object sender, DataReceivedE
break;
}
}


}
}
}
Loading