Skip to content

Commit 7174690

Browse files
V3.1.0 (#20)
* Key check and Options access * It bothered me * Arch * Update README.md * Update server.js * Update server.js * WS Error Handle * Update Driver.cs * Alpha * Update CHANGELOG.md * DownloadPSI * optimsie Unprovision * Final * Update Program.cs
1 parent 23318a7 commit 7174690

13 files changed

Lines changed: 312 additions & 101 deletions

File tree

.github/workflows/BuildPSI.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@ jobs:
99
strategy:
1010
matrix:
1111
node-version: [16]
12-
os: [windows-latest, macos-latest, ubuntu-latest]
12+
os: [windows-latest, macos-latest, ubuntu-latest, self-hosted]
1313
include:
1414
# Define the binary names to use for uploads
1515
- os: ubuntu-latest
1616
file: server
1717
asset_name: server-ubuntu.psi
1818
asset_body: "Ubuntu Server Binary"
19+
- os: self-hosted
20+
file: server
21+
asset_name: server-debian-arm.psi
22+
asset_body: "Debian ARM Server Binary"
1923
- os: windows-latest
2024
file: server.exe
2125
asset_name: server-win.psi

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
- v3.1.0
2+
3+
- Versions
4+
- ZWave JS Driver Version: 9.3.0
5+
- ZWave JS Server Version: 1.17.0 (Schema Version 17)
6+
7+
- Internal changes
8+
- The **CFGLogConfig** and **CFGStorage** classes can now be set exclusively.
9+
- The child classes of **ZWaveOptions** are now instanciated with default values when calling their constructors.
10+
- The **DownloadPSI** method now pulls down version locked binaries, to remove the potential for incompatible Binary/library combinations
11+
12+
- New Fearures
13+
- Added ARM prebuilt binary (Debian, RPi)
14+
- The **DownloadPSI** method - now has an optional override, allwowing the PSI to be focibly downloaded, i.e to ensure you have the correct version.
15+
16+
- Fixes
17+
- Any inclusion or replace node method now checks that Security Keys are present if needed.
18+
- Handle unexpected WS Disconnects.
19+
120
- v3.0.0
221

322
- Versions

PSI/server.js

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
const { Driver, ZWaveError, ZWaveErrorCodes } = require("zwave-js");
1+
const { Driver } = require("zwave-js");
22
const { ZwavejsServer } = require("@zwave-js/server");
33

44
console.log("ZWaveJS.NET: Preparing server...");
55

66
const serialPort = process.env.SERIAL_PORT;
77
const wsPort = parseInt(process.env.WS_PORT);
88
const driverOptions = JSON.parse(process.env.CONFIG);
9+
let ServerStarted = false;
10+
let DriverStarted = false;
911

1012
console.log(`ZWaveJS.NET: Serial Port: ${serialPort}, WSPort: ${wsPort}`);
1113

@@ -21,19 +23,31 @@ if (driverOptions.securityKeys) {
2123
console.log("ZWaveJS.NET: Instantiating driver...");
2224
const driver = new Driver(serialPort, driverOptions);
2325
const server = new ZwavejsServer(driver, { port: wsPort, host: "localhost" });
24-
driver.on("error", (e) => {
25-
/*
26-
if (e instanceof ZWaveError && e.code === ZWaveErrorCodes.Driver_Failed) {
27-
process.stderr.write("2\n");
28-
}
29-
*/
30-
});
26+
server.on("listening",() =>{
27+
ServerStarted = true;
28+
})
29+
driver.on("error", (e) => {});
3130

3231
driver.on("driver ready", () => {
3332
server.start();
33+
ServerStarted = true;
3434
});
3535

3636
console.log("ZWaveJS.NET: Starting driver...");
37-
driver.start().catch((e) => {
37+
driver.start()
38+
.then(() =>{
39+
DriverStarted = true;
40+
process.stdin.on("data",HandleInput)
41+
})
42+
.catch((e) => {
3843
process.stderr.write("1\n");
39-
});
44+
})
45+
46+
const HandleInput = async (Data) =>{
47+
if(Data.toString().trim() === "KILL"){
48+
console.log("ZWaveJS.NET: Cleaning up...");
49+
if(ServerStarted) await server.destroy();
50+
if(DriverStarted) await driver.destroy();
51+
process.exit(0);
52+
}
53+
}

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,19 @@ The library will connect to an already running instance of [zwave-js-server](htt
7676
The library will host its own zwave-js instance.
7777
You might ask, if in this mode, **nodejs** and **npm** is needed on the host system - it is not!
7878

79-
This is all possible with an accompanying file - **server.psi**.
79+
This is all possible with an accompanying file - **server.psi**. (Platform Support Image)
8080

8181
Its an executable that is running silently/hidden,
8282
and it contains everything necessary for .NET to work with zwave-js.
8383

8484
**server.psi** files are platform specific, but the assembly isn't - it will run on windows, OSX and Linux, and the platform specifics i.e **node** are contained in **server.psi**.
8585

86+
## Prebuilt PSI's
87+
- Windows x64
88+
- MacOS x64 (Should support Apple Silicon via Rosetta2)
89+
- Ubuntu Linux x64
90+
- Debian Arm
91+
8692
## Building yor own platform specific binary.
8793

8894
To build an image for your platform:

Visual Studio Projects/ZWaveJS.NET/Scratch Pad/Program.cs

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,12 @@ class Program
1313
static void Main(string[] args)
1414
{
1515

16+
ZWaveJS.NET.Helpers.DownloadPSI().ContinueWith((R) => {
1617

17-
18+
var B = "sadsdsa";
19+
1820

19-
ZWaveOptions ZWO = new ZWaveOptions();
20-
_Driver = new Driver("COM3", ZWO);
21-
_Driver.DriverReady += _Driver_DriverReady;
22-
23-
_Driver.Start();
24-
25-
Console.ReadLine();
21+
});
2622
}
2723

2824
private static void _Driver_StartupErrorEvent(string Message)
@@ -32,18 +28,13 @@ private static void _Driver_StartupErrorEvent(string Message)
3228

3329
private static void _Driver_DriverReady()
3430
{
31+
var ddd = new InclusionOptions();
32+
ddd.strategy = Enums.InclusionStrategy.Security_S0;
33+
_Driver.Controller.ReplaceFailedNode(4, ddd).ContinueWith((R) => {
3534

36-
VirtualNode VN = _Driver.Controller.GetMulticastGroup(new int[] { 2,3,4,6,7});
37-
VN.GetDefinedValueIDs();
38-
VN.GetEndpointCount();
39-
40-
41-
42-
43-
44-
45-
46-
35+
var Res = R;
36+
37+
});
4738
}
4839

4940
private static void Program_NodeDead(ZWaveNode Node)

Visual Studio Projects/ZWaveJS.NET/ZWaveJS.NET/Controller.cs

Lines changed: 99 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -271,12 +271,12 @@ public Task<CMDResult> RestoreNVM(byte[] NVMData, ConvertRestoreNVMProgress Conv
271271
Driver.Callbacks.Add(ID, (JO) =>
272272
{
273273
CMDResult Res = new CMDResult(JO);
274-
Result.SetResult(Res);
275274
if (Res.Success)
276275
{
277276
_Driver.Restart();
278277
}
279-
278+
Result.SetResult(Res);
279+
280280
});
281281

282282
Dictionary<string, object> Request = new Dictionary<string, object>();
@@ -327,35 +327,56 @@ public Task<CMDResult> ReplaceFailedNode(int NodeID, InclusionOptions Options)
327327

328328
Guid ID = Guid.NewGuid();
329329
TaskCompletionSource<CMDResult> Result = new TaskCompletionSource<CMDResult>();
330-
330+
331331
switch (Options.strategy)
332332
{
333+
case Enums.InclusionStrategy.Default:
334+
CMDResult Res = new CMDResult(Enums.ErrorCodes.InvalidStrategy, "Invalid Strategy for 'ReplaceFailedNode' Valid Strategies are : [Insecure, Security_S0, Security_S2]", false);
335+
Result.SetResult(Res);
336+
return Result.Task;
337+
333338
case Enums.InclusionStrategy.Security_S2:
334339
ValidateDSKAndEnterPINSub = Options.userCallbacks?.validateDSKAndEnterPIN ?? null;
335340
GrantSecurityClassesSub = Options.userCallbacks?.grantSecurityClasses ?? null;
336341
AbortSub = Options.userCallbacks?.abort ?? null;
337342
break;
338-
}
339343

340-
if (Options.strategy == Enums.InclusionStrategy.Default)
344+
}
345+
346+
if (Options.strategy == Enums.InclusionStrategy.Security_S2)
341347
{
342348
if (ValidateDSKAndEnterPINSub == null || GrantSecurityClassesSub == null || AbortSub == null)
343349
{
344-
CMDResult Res = new CMDResult("ZWJS.NET.ERR.002", "Invalid Strategy for 'ReplaceFailedNode' Valid Strategies are : [Insecure, Security_S0, Security_S2]", false);
350+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingS2Callbacks, "S2 Security require userCallbacks to be provided [validateDSKAndEnterPIN, grantSecurityClasses, abort]", false);
351+
Result.SetResult(Res);
352+
return Result.Task;
353+
}
354+
355+
if (_Driver.Options != null && _Driver.Options.MissingKeys(true, false))
356+
{
357+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingKeys, "Missing Security Keys in Options", false);
345358
Result.SetResult(Res);
346359
return Result.Task;
347360
}
348361
}
349362

350-
if (Options.strategy == Enums.InclusionStrategy.Security_S2)
363+
if(Options.strategy == Enums.InclusionStrategy.Security_S0)
351364
{
352-
if(ValidateDSKAndEnterPINSub == null || GrantSecurityClassesSub == null || AbortSub == null)
365+
if (_Driver.Options != null && _Driver.Options.MissingKeys(false, true))
353366
{
354-
CMDResult Res = new CMDResult("ZWJS.NET.ERR.001", "S2 Security require userCallbacks to be provided [validateDSKAndEnterPIN, grantSecurityClasses, abort]", false);
367+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingKeys, "Missing Security Keys in Options", false);
355368
Result.SetResult(Res);
356369
return Result.Task;
357370
}
358371
}
372+
373+
if (_Driver.Options != null && !_Driver.Options.CheckKeyLength())
374+
{
375+
CMDResult Res = new CMDResult(Enums.ErrorCodes.InvalidkeyLength, "Invalid Key length. All Security Keys must be a 32 character hexadecimal string (representing 16 bytes)", false);
376+
Result.SetResult(Res);
377+
return Result.Task;
378+
}
379+
359380

360381
Driver.Callbacks.Add(ID, (JO) =>
361382
{
@@ -497,18 +518,62 @@ public Task<CMDResult> BeginInclusion(InclusionOptions Options)
497518
AbortSub = Options.userCallbacks?.abort ?? null;
498519
break;
499520
}
521+
522+
if (Options.strategy == Enums.InclusionStrategy.Default)
523+
{
524+
525+
if (ValidateDSKAndEnterPINSub == null || GrantSecurityClassesSub == null || AbortSub == null)
526+
{
527+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingS2Callbacks, "S2 Security require userCallbacks to be provided [validateDSKAndEnterPIN, grantSecurityClasses, abort]", false);
528+
Result.SetResult(Res);
529+
return Result.Task;
530+
}
500531

501-
if (Options.strategy == Enums.InclusionStrategy.Default || Options.strategy == Enums.InclusionStrategy.Security_S2)
532+
if (_Driver.Options != null && _Driver.Options.MissingKeys(true, true))
533+
{
534+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingKeys, "Missing Security Keys in Options", false);
535+
Result.SetResult(Res);
536+
return Result.Task;
537+
}
538+
}
539+
540+
if (Options.strategy == Enums.InclusionStrategy.Security_S2)
502541
{
542+
503543
if (ValidateDSKAndEnterPINSub == null || GrantSecurityClassesSub == null || AbortSub == null)
504544
{
505-
CMDResult Res = new CMDResult("ZWJS.NET.ERR.001", "S2 Security require userCallbacks to be provided [validateDSKAndEnterPIN, grantSecurityClasses, abort]", false);
545+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingS2Callbacks, "S2 Security require userCallbacks to be provided [validateDSKAndEnterPIN, grantSecurityClasses, abort]", false);
546+
Result.SetResult(Res);
547+
return Result.Task;
548+
}
549+
550+
if (_Driver.Options != null && _Driver.Options.MissingKeys(true, false))
551+
{
552+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingKeys, "Missing Security Keys in Options", false);
506553
Result.SetResult(Res);
507554
return Result.Task;
508555
}
556+
}
509557

558+
if (Options.strategy == Enums.InclusionStrategy.Security_S0)
559+
{
560+
if (_Driver.Options != null && _Driver.Options.MissingKeys(false, true))
561+
{
562+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingKeys, "Missing Security Keys in Options", false);
563+
Result.SetResult(Res);
564+
return Result.Task;
565+
}
510566
}
511-
567+
568+
569+
570+
if (_Driver.Options != null && !_Driver.Options.CheckKeyLength())
571+
{
572+
CMDResult Res = new CMDResult(Enums.ErrorCodes.InvalidkeyLength, "Invalid Key length. All Security Keys must be a 32 character hexadecimal string (representing 16 bytes)", false);
573+
Result.SetResult(Res);
574+
return Result.Task;
575+
}
576+
512577
Driver.Callbacks.Add(ID, (JO) =>
513578
{
514579
CMDResult Res = new CMDResult(JO);
@@ -550,31 +615,18 @@ public Task<CMDResult> StopInclusion()
550615

551616
return Result.Task;
552617
}
553-
618+
554619
public Task<CMDResult> UnprovisionSmartStartNode(int NodeID)
555620
{
556-
Guid ID = Guid.NewGuid();
557-
TaskCompletionSource<CMDResult> Result = new TaskCompletionSource<CMDResult>();
558-
559-
Driver.Callbacks.Add(ID, (JO) =>
560-
{
561-
CMDResult Res = new CMDResult(JO);
562-
Result.SetResult(Res);
563-
});
564-
565-
Dictionary<string, object> Request = new Dictionary<string, object>();
566-
567-
Request.Add("messageId", ID);
568-
Request.Add("command", Enums.Commands.UnprovisionSmartStartNode);
569-
Request.Add("dskOrNodeId", NodeID);
570-
571-
string RequestPL = Newtonsoft.Json.JsonConvert.SerializeObject(Request);
572-
Driver.Client.SendAsync(RequestPL);
573-
574-
return Result.Task;
621+
return _UnprovisionSmartStartNode(NodeID);
575622
}
576623

577624
public Task<CMDResult> UnprovisionSmartStartNode(string DSK)
625+
{
626+
return _UnprovisionSmartStartNode(DSK);
627+
}
628+
629+
private Task<CMDResult> _UnprovisionSmartStartNode(object dskOrNodeId)
578630
{
579631
Guid ID = Guid.NewGuid();
580632
TaskCompletionSource<CMDResult> Result = new TaskCompletionSource<CMDResult>();
@@ -589,7 +641,7 @@ public Task<CMDResult> UnprovisionSmartStartNode(string DSK)
589641

590642
Request.Add("messageId", ID);
591643
Request.Add("command", Enums.Commands.UnprovisionSmartStartNode);
592-
Request.Add("dskOrNodeId", DSK);
644+
Request.Add("dskOrNodeId", dskOrNodeId);
593645

594646
string RequestPL = Newtonsoft.Json.JsonConvert.SerializeObject(Request);
595647
Driver.Client.SendAsync(RequestPL);
@@ -603,6 +655,20 @@ public Task<CMDResult> ProvisionSmartStartNode(string QRCode)
603655
Guid ID = Guid.NewGuid();
604656
TaskCompletionSource<CMDResult> Result = new TaskCompletionSource<CMDResult>();
605657

658+
if(_Driver.Options != null && _Driver.Options.MissingKeys(true,true))
659+
{
660+
CMDResult Res = new CMDResult(Enums.ErrorCodes.MissingKeys, "Missing Security Keys in Options", false);
661+
Result.SetResult(Res);
662+
return Result.Task;
663+
}
664+
665+
if (_Driver.Options != null && !_Driver.Options.CheckKeyLength())
666+
{
667+
CMDResult Res = new CMDResult(Enums.ErrorCodes.InvalidkeyLength, "Invalid Key length. All Security Keys must be a 32 character hexadecimal string (representing 16 bytes)", false);
668+
Result.SetResult(Res);
669+
return Result.Task;
670+
}
671+
606672
Driver.Callbacks.Add(ID, (JO) =>
607673
{
608674
CMDResult Res = new CMDResult(JO);

0 commit comments

Comments
 (0)