The Z-Wave protocol in C# – Part 1

December 13th, 2009 by Henrik Leidecker Jørgensen | Edit this entry Leave a reply »

The example developed in this article will be able to switch on a Z-Wave device and the switch it off again. This requires some of the basic Z-Wave protocol elements to be implemented.

It is important to understand the two previous articles to get the most out of the example shown here.

For this example the same devices and configurations are used as in ‘An introduction to Z-Wave programming in C#

‘.
The ZWavePort class will be responsible for the basic communication and protocol handling.

class ZWavePort
{
    ...
}

The communication part consists of sending and receiving messages on the serial port. The protocol part covers sending ACK messages automatically.

The below sequence of messages show the ‘Switch on node 6′ scenario.

/*
    Message sent: 01 09 00 13 06 03 20 01 FF 05 3B
    Message received: 06
    Message received: 01 04 01 13 01 E8
    Message sent: 06
*/

Only two types of messages will be send from the C# client in this example.

  1. Request – the following message from the Z-Wave controller is an ACK so no ACK shall be send from the C# client.
  2. ACK – the following message from the Z-Wave controller is a response for which the C# client must send an ACK.

A variable is introduced to control whether or not the C# client shall send an ACK for an incoming message from the Z-Wave controller.

private Boolean sendACK = true;

The rule about sending ACK messages for incoming messages is implemented in the SendMessage function.

public void SendMessage(byte[] message)
if (sp.IsOpen == true)
{
    if (message != MSG_ACKNOWLEDGE)
    {
        sendACK = false;
        message[message.Length - 1] = GenerateChecksum(message); // Insert checksum
    }
    sp.Write(message, 0, message.Length);
}

A cheksum is added if the message to be send is a request.

All incoming messages were just ignored in the example in the previous article. This no longer works as the protocol requires ACK messages to be send.
Messages are received by polling the serial port data and copy it into a byte array.

private void ReceiveMessage()
{
    while (sp.IsOpen == true)
    {
        int bytesToRead = sp.BytesToRead;
        if ((bytesToRead != 0) & (sp.IsOpen == true))
        {
            byte[] message = new byte[bytesToRead];
            sp.Read(message, 0, bytesToRead);
            if (sendACK) // Does the incoming message require an ACK?
            {
                SendACKMessage();
            }
            sendACK = true;
        }
    }
}

The ReceiveMessage function utilizes the sendACK variable to determine whether or not to send an ACK message when a message is received. The sendACK variable is always set to true after a message has been received to enable the default behavior of sending ACK messages when a message is received.

A separate thread is created for running ReceiveMessage. This enables the C# client to constantly listen for incoming messages from the Z-Wave controller.

receiverThread = new Thread(new System.Threading.ThreadStart(ReceiveMessage));

The thread is then started during the opening of the serial port.

public void Open()
{
    if (sp.IsOpen == false)
    {
        sp.Open();
        receiverThread.Start();
    }
}

The Z-Wave protocol requires a message sequence to be completed before a new sequence is initiated. If a ’switch on’ message is sent then all related requests, responses and ACK messages must be completed before a ’switch off’ message is send.
To make the implementation very simple this has been implemented in the Main function as a 5 seconds delay following the call to the SendMessage function. The assumption is that after 5 seconds the messaging is completed.

static void Main(string[] args)
{
    byte nodeId = 0x06;
 
    byte level = 0xFF; // On
    byte[] message = new byte[] { 0x01, 0x09, 0x00, 0x13, nodeId, 0x03, 0x20, 0x01, level, 0x05, 0x00 };
 
    ZWavePort zp = new ZWavePort();
    zp.Open();
 
    zp.SendMessage(message);
    Thread.Sleep(5000); // Wait for 5 seconds
 
    level = 0x00; // Off
    message = new byte[] { 0x01, 0x09, 0x00, 0x13, nodeId, 0x03, 0x20, 0x01, level, 0x05, 0x00 };
    zp.SendMessage(message);
    Thread.Sleep(5000); // Wait for 5 seconds
 
    System.Console.ReadLine() // Wait for the user to terminate the program
 
    zp.Close();
}

The ReadLine function is called right before the Z-Wave port is closed. Try to press the actual switch on the Z-Wave device and see what happens. A couple of debugging lines have been added to the SendMessage and ReceiveMessage functions. The debug information will print the messages sent and received by the C# client to the screen.

With the example in this article it is now possible to send subsequent messages but the strategy to wait for 5 seconds is not very elegant.
In the next article the ZWavePort class will be altered so this is being handled automatically.

The source code can be downloaded via this link. You are free to use the code in any manner you like.

Advertisement

5 comments

  1. Vullisbak says:

    Great followup!

  2. Luis Silva says:

    Hi,

    I’ve seen in several forums regarding the Z-Wave subject that you ask for sugesttions of things to publish here. I bought a Qees Power module, it has a switch and a power meter. Thanks to your examples I was able to use the switch. Now i’m looking for information regarding the power meter part.
    Do you have any kind of information?

    Best regards,
    Luis Silva

  3. Henrik Leidecker Jørgensen says:

    Hi,
    I will dig out some information for you and post in the forum during this week.
    BR,
    Henrik

  4. Luis Silva says:

    Hi Henrik,

    Thank you, meanwhile i’m doing some more testing to my module but so far I haven’t found anything on the web about reading a Z-Wave power meter.

    Best regards,
    Luis Silva

  5. Adhip says:

    Great Post!..i was trying to use the code and communicate with my Aeon Lab ZStick which i have connected to my Laptop. The problem is that i do not receive anything using the ReceiveMessage function. Also, i am not sure if i have the right node Id.I used mControl v2.1 which gave me a success poll at nodeId =4, and thus using that. Could you help me in identifying the nodeId as well as if there is anything else missing.

    Thanks