GithubHelp home page GithubHelp logo

zwave-js / zwavejs.net Goto Github PK

View Code? Open in Web Editor NEW
16.0 3.0 5.0 51.66 MB

A Z-Wave JS wrapper for the .NET Framework. Supporting various targets, and providing a feature rich Z-Wave API.

License: MIT License

C# 99.32% JavaScript 0.68%
zwave zwave-js csharp dotnet core wrapper zwave-js-server netcore31 netstandard20 netstandard21

zwavejs.net's Introduction

Image

ZWaveJS.NET

Nuget Nuget DeepScan grade GitHub issues GitHub closed issues

ZWaveJS.NET is a class library developed for the .NET framework family, that opens up the zwave-js Driver in .NET, allowing its runtime to be used directly in .NET applications.

Supported Targets

  • NET 4.5
  • NET 4.8
  • NET 5.0
  • NET Standard 2.0
  • NET Standard 2.1
  • NET Core 3.1

The library strictly follows the structure of the zwave-js API.

Examples:

Driver.Controller.BeginHealingNetwork()
Driver.Controller.Nodes.Get(4).GetDefinedValueIDs()
Driver.Controller.Nodes.Get(4).SetValue(ValueID ValueID, object Value, SetValueAPIOptions Options = null)
Driver.Controller.Nodes.Get(4).GetEndpoint(2).InvokeCCAPI(int CommandClass, string Method, params object[] Params)

Features

  • Controller

    • Controller Info
    • NVM Restore/Backup
    • Network Statistics
    • Node Inclusion (Unsecured, S0 & S2 Security)
    • Smart Start
    • Smart Start Provisioning entry management
    • Node Exclusion
    • Network Healing
    • Remove Failed Node
    • Replace Failed Node
    • Multicast support
    • Node added/removed events
    • Inclusion/Exclusion started/stopped events
    • Network Heal progress/completed events
    • Network statistics updated events
  • Node

    • Node Info
    • Network Health Checks
    • Network Statistics
    • Updating, Polling & Fetching Values
    • CCAPI Invoke (and its endpoints)
    • Obtain Value IDs
    • Obtain Value Metadata
    • Interview Node
    • Association Management
    • Firmware Updates
    • Node Ready, Asleep, Awake & Dead events
    • Value Updated, Notification & Value Notification events
    • Interview Started, Completed & Failed events
    • Node Network Statistics updated events

Getting Started.

The library can operate in 2 ways: Client or Self Hosted.

Client
The library will connect to an already running instance of zwave-js-server.

Self Hosted
The library will host its own zwave-js instance.
You might ask, if in this mode, nodejs and npm is needed on the host system - it is not!

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

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

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.

Prebuilt PSI's

  • Windows x64
  • MacOS x64 (Should support Apple Silicon via Rosetta 2)
  • Ubuntu Linux x64
  • Debian ARM64

Building yor own platform specific binary.

To build an image for your platform:

  • Clone the repo
  • cd to ./PSI
  • run yarn install --immutable
  • and finally yarn run build
  • rename dist/server to server.psi, and distrubute with your application/dll.

Every release will include a set of PSI images, so download the one for your platform, and rename it to server.psi, and ensure its in the same location as the dll.

There is also a Helper method that pulls down the correct image if one is needed ZWaveJS.NET.Helpers.DownloadPSI()

server.psi is not needed, if using the library in Client Mode.

The class library contains most of the methods you will need, from including a secure device, to removing it.

Installing.

All releases will be published to nuget, so search for ZWaveJS.NET and install it, the nupkg file will also be attached to the release here, on Github, along with the platform PSI files.

Brief Example

static ZWaveJS.NET.Driver _Driver;
static void Main(string[] args)
{
    // Set encryption keys, enable logging, adjust network timeouts so on and so forth.
     ZWaveJS.NET.ZWaveOptions Options = new  ZWaveJS.NET.ZWaveOptions();

    // Create Driver Instance
    _Driver = new Driver("COM7", Options);

    // Subscribe to driver ready
    _Driver.DriverReady += _Driver_DriverReady;
   
    _Driver.Start();
}

private static void _Driver_DriverReady()
{
    // Update a value
    ZWaveJS.NET.ValueID VID = new ZWaveJS.NET.ValueID();
    VID.commandClass = 135;
    VID.property = "value";
    VID.endpoint = 0;

    // Support for set Value Options
    ZWaveJS.NET.SetValueAPIOptions SVO = new  ZWaveJS.NET.SetValueAPIOptions();
    SVO.transitionDuration = "2s";
    SVO.volume = 30;

    // All methods returns a task, as to not block the UI
    _Driver.Controller.Nodes.Get(4).SetValue(VID, 200, SVO).ContinueWith((res) => {
        if (res.Result.Success) {
            Console.WriteLine("Value Updated");
        }
    });

    // Listen for Value Updates on a node
    _Driver.Controller.Nodes.Get(3).ValueUpdated += Program_ValueUpdated;
    _Driver.Controller.Nodes.Get(3).Notification += Program_Notification;

    // Or All of them
    ZWaveJS.NET.ZWaveNode[] Nodes = _Driver.Controller.Nodes.AsArray();
    foreach(ZWaveJS.NET.ZWaveNode Node in Nodes)
    {
        Node.ValueUpdated += Program_ValueUpdated;
        Node.Notification += Program_Notification;
    }
    
    // Other Node methods
    _Driver.Controller.Nodes.Get(4).GetDefinedValueIDs().ContinueWith((res) => {
        // Do something with Value ID's (res.Result)
    });
}

private static void Program_ValueUpdated(ZWaveNode Node, JObject Args)
{
   // Do something with Args
}

private static void Program_Notification(ZWaveNode Node, int ccId, JObject Args)
{
   // Do something with Args
}

Network Toolkit Demo Application.

The Network Toolkit Application (NET 4.5) serves as a reference, in how the library can be used, but at the same time, can be used as a tool to manage your network. You can download the toolkit demo from the Release pages here, on Github - The source code is also available.

Image

License

MIT License

Copyright (c) 2021 Marcus Davies

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

zwavejs.net's People

Contributors

alcalzone avatar dependabot[bot] avatar marcus-j-davies avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

zwavejs.net's Issues

ZWaveJS.NET does not support multiple drivers

I'm trying to control multiple instances of ZWave JS from the same C# program. For this, I initialize multiple instances of the ZWaveJS.NET.Driver class but as soon as I initialize a second instance, the Driver.Instance of the first instance is overwritten because Driver.Instance is static:

internal static volatile Driver Instance;

So I think we should refactor the library so that it does not use a singleton pattern for the Driver class. Do you agree ?

No error or exception when websocket client fails to connect in client mode

I'm using the ZWaveJS.NET library in client mode, i.e I use some code similar to the example below to connect to an already running ZWave JS server.
If the ZWaveJS Server is not running, I would expect the StartUpError event to be raised but it isn't, and no exception is thrown either. Is there a way to detect that connection has failed?

I'm testing with the 4.0.0 branch, but I think there is the same problem with the main branch.

internal class Program
 {
     static Driver _driver;
     static int schemaVersion = 17;
     static string zWaveJSServerUrl = "ws://localhost:3000";

     static void Main(string[] args)
     {
         try
         {
             _driver = new Driver(new Uri(zWaveJSServerUrl), schemaVersion);
             _driver.DriverReady += Driver_DriverReady;
             _driver.StartUpError += Driver_StartupErrorEvent;
             _driver.Start();

             Console.WriteLine("press enter to stop");
             Console.ReadKey();
         }
         catch(Exception ex)
         {
             Console.WriteLine(ex.ToString());
         }
     }

     static private void Driver_StartupErrorEvent(string message)
     {
         Console.WriteLine(message);
     }

     static private void Driver_DriverReady()
     {
         Console.WriteLine("Driver ready");
     }
}

RefreshValues does not return any error when node is dead.

If the following code is called for a dead node
CMDResult result = await node.RefreshValues();
the result.Success value is always true

other methods like SetValue() correctly return false for result.Success with a message saying "The message cannot be sent because node 53 is dead (ZW0202)"

Looks like the problem is probably more in ZWave JS Server or node-zwave-js, but I wanted to check here first to know what you think.

Event handlers block processing of new events

When the library calls an event handler, it blocks the processing of new events received from Z-Wave JS Server until the event handler returns.
So if what is implemented in the event handler is time consuming it can cause big delays in the whole application.
Moreover if the event handler itself synchronously calls another ZWave JS .NET method which expects a response from the Z-Wave JS server it creates a deadlock.

To workaround this issue all my event handlers look like this:

private void ExclusionStartedEventHandler()
  {
      //need a Task.Run here because event processing in ZWaveJS.NET is delayed by any event handler
      Task.Run(() =>
      {
....
      });
  }

I don't mind to keep doing this, but I wonder if there is any case where we actually want this blocking behavior?

Logging config not settable

Implemented V3 and it looks great!!!! I needed to rework my app to handle mapping of CMDResults to models my app required, but otherwise, working great! Thank-you and well-done!!!!!!

I did notice that the Options.logConfig property is readonly (with a private setter only), so it's not possible to adjust the logging behavior. Not sure if you intended that to be for your own use or generally available. Either way, I thought I would point it out.

Thanks again for your great work!

Method calls for asleep nodes never return

If, for example, the RefreshValues() or SetValue() methods are called for a node that is asleep, the method never return (unless the node wakes up)
Shouldn't there be some sort of timeout in order to guarantee that the method will return within a certain time?

Controller Node is filtered out of the Nodes collection

Why does the library filters out the controller node from the Controller.Nodes collection?

Nodes = Nodes.Where((N) => !N.isControllerNode).ToArray();

The ZWaveNode class includes some useful information like ZWaveNode.deviceConfig.label, ZWaveNode.deviceConfig.manufacturer, that we may want to have access to for the controller node.

Can't create a second Driver after destroying the first one

After calling driver.Destroy() I would expect to be able to create and start a new driver instance.

Instead the DriverReady event is never fired, and I can see this is because the Controller property is never set.

Not sure if something needs to be updated, so that the driver and be re-created and started again.

Driver.Destroy() throws an exception if Driver.Controller is not initialized

If Driver.Destroy() is called for a Driver instance that has not been successfully initialized for example, it throws an exception at

Controller.Nodes = null;

because Controller is null.
it is easily fixable by checking if Controller is null

if (Controller != null)
{
    Controller.Nodes = null;
    Controller = null;
}

but I wonder what is the benefit of setting Controller.Nodes to null at all, since Controller itself is set to null on the next line?

VirtualNode.GetDefinedValueIDs() throws a null reference exception (4.0.0 branch)

Looks like there might be a small mistake in the path for the JO.SelectToken call in the following code:

Driver.Instance.Callbacks.Add(ID, (JO) =>
 {
     CMDResult Res = new CMDResult(JO);
     if (Res.Success)
     {
         Res.SetPayload(JO.SelectToken("result.valueIds").ToObject<ValueID[]>());
     }

     Result.SetResult(Res);
 });

The JSON in the response has "valueIDs" versus the "valueIds" being used in the path.

Access to homeID

When a client connects to the ZWave JS server, the first message it receives includes the homeID that identify the ZWave network.
https://github.com/zwave-js/zwave-js-server#api

Could we add access to this value in version 4?
Or is there any other way to get this value using the ZWaveJS.NET lib?

Thanks

Stack overflow exception in Websocket.Client library

I get a stack overflow crash in our program by doing this:

  1. create a ZWaveJS.NET driver and connect it to an external ZWave JS Server
  2. stop the ZWave JS server and let the ZWaveJS.NET driver goes into reconnection mode.
  3. wait about 10 minutes to trigger hundreds of reconnection attempts
  4. call driver.Destroy()

=> a StackOverflowException occurs in ClientWebSocket.Dispose()

It is 100% reproducible in our program, but I wasn't able to reproduce it with a simple console program, so I must be missing something there.

Anyway, I have traced down the problem to be related to this issue in the Websocket.Client library: Marfusios/websocket-client#124
While debugging in VS, if you "break all" while waiting in step 3 from above, you can see the hundred of recursive calls in the task used for reconnection.
A fix for this problem has been implemented in recent version of the Websocket.Client library, but unfortunately this version has dropped support for netstandard2.0 , so we cannot directly update the library from nuget unless netstandard2.0 is dropped in ZWaveJS.NET as well, which is out of question for us because our program still use .NET Framework.

So I'm not sure how to best fix this issue?
For now, I pulled the source code for Websocket.Client version 4.6.1 (the version currently used by ZwaveJS.NET) and I manually merged the fix for the recursive call problem: Marfusios/websocket-client@df2e007
I successfully tested that it fixes my stack overflow problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.