Z-Wave protokollen i C# – Del 3

2. januar, 2010 af Henrik Leidecker Jørgensen Skriv en kommentar »

I denne artikel forbedres beskedhåndteringen og en lysdæmper (Dimmer) tilføjes til deviceklasserne.

For at få det fulde udbytte af artiklen er det en fordel at have læst de tidligere artikler på dette site.

Det er vigtigt, at en påbegyndt beskedsekvens er afsluttet før en ny påbegyndes. Dette er nødvendigt for at overholde protokollen. Den nuværende strategi bygger på princippet om, at det er det deviceobjekt, der har initieret en beskedsekvens, som også afgører og signalerer, hvornår og når beskedsekvensen er afsluttet.
I de tidligere eksempler, hvor der kun eksisterede én enhed og dermed ét deviceobjekt, så beskedsekvensen for at tænde node ‘6′ således ud.

/*
    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
*/

Alle beskeder til deviceobjektet fra Z-Wave controlleren var derfor relateret til ét og kun ét objekt. Med flere enheder i Z-Wave netværket, skal hvert enkelt deviceobjekt til at forstå, om beskeder fra Z-Wave controlleren er relateret til dem eller et andet objekt. Uden denne viden vil alle deviceobjekter indikere, at en beskedsekvens er afsluttet, når et vilkårligt response modtages. Husk at alle beskeder fra Z-Wave controlleren sendes til alle deviceobjekter.

I Z-Wave protokollen findes der et begreb, der hedder callback id. Det kan anvendes til at holde styr på request/response par. Et callback id defineres hver gang en request sendes fra et af deviceobjekterne. Når der anvendes callback id, hvilket er frivilligt, så indsættes det altid lige før checksummen. I nedenstående beskedsekvens er callback id ‘3′.

/*
    Message sent: 01 0A 00 13 06 03 20 01 00 05 03 C4
    Message received: 06
    Message received: 01 04 01 13 01 E8
    Message sent: 06
    Message received: 01 05 00 13 03 00 EA
    Message sent: 06
*/

Der tilføjes et ekstra request/response par til beskedsekvensen, hvor det er Z-Wave controlleren, der sender det sidste request. I requesten fra Z-Wave controlleren indgår det callback id (byte 5), der var tilføjet til den oprindelige request fra C# klienten og det er det, der anvendes til at afgøre, hvem der skal signalere, at beskedsekvensen er afsluttet. Det sidst ACK fra C# klient fungerer som response.

I eksemplet fra artiklen anvendes følgende enheder og konfiguration.

  • Z-Wave controller (node id: 0×03)
  • Dimmer (node id: 0×06)
  • Switch (node id: 0×2B)

En ny funktion GetCallbackId oprettes i ZWavePort klassen. Deviceobjekterne kalder funktionen, når et nyt callbackid skal bruges i forbindelse med afsendelsen af en request.

public int GetCallbackId()
{
    lock (this.callbackIdLock)
    {
        return ++this.callbackIdPool;
    }
}

For at få strategien med callback id til at fungere skal deviceklasserne også ændres. Da alle deviceklasser nedarver fra ZWaveNode er det kun nødvendigt at ændre denne klasse. Ændringerne i ZWaveNode klassen dækker følgende områder.

  1. En liste med callback ids tilhørende de requests som deviceklassen har sendt.
  2. Oprette et nyt callback id i SendMessage.
  3. Slette callback id fra listen i MessagingCompleted.
  4. Verificere at beskeden modtaget i MessageHandler funktionen har det rigtige callback id.
  5. Udskrivning af debug information – når MessagingCompleted kaldes.
abstract class ZWaveNode
{
    ...
 
    protected List callbackIds = new List();
 
    ...
 
    protected Boolean SendMessage(byte[] message)
    {
        int callbackId = zp.GetCallbackId(); // Retrieve a callback id from the ZWavePort object
        callbackIds.Add(callbackId); // Add callback id to the list
        message[message.Length - 2] = callbackId; // Insert the callback id into the message
        while (!zp.SendMessage(message)) Thread.Sleep(100);
        return true;
    }
 
    protected void MessagingCompleted(byte callbackId)
    {
        callbackIds.Remove(callbackId); // Remove the callback id
        zp.MessagingCompleted();
    }
 
    public virtual void MessageHandler(byte[] message)
    {
        if ((message[0] != 0x06) && (sessionIds.Contains(sessionId)))
        {
            // Check the callback id
            byte callbackId = message[4];
            if ((message.Length == 7) && callbackIds.Contains(callbackId))
            {
                System.Console.WriteLine(this.GetType().Name.ToString() + " (node id: " + this.NodeId + "): Messaging completed");
                MessagingCompleted(callbackId);
            }
        }
    }
}

Deviceklasserne udvides med en Dimmer (lysdæmper). Det er nødvendigt at vide hvilke bytes, der skal sendes for at sætte dimmeren til et bestemt niveau.

/*
    0x01, 0x09, 0x00, 0x13, nodeId, 0x03, 0x20, 0x01, level, 0x05, callbackId, checksum
*/

Det er de samme bytes, som sendes når en switch tændes/slukkes, med en enkelt undtagelse. Byte 9 kan nu antage værdier mellem 0 – 99, hvor det tidligere kun var muligt at sætte denne byte til 0 eller 255.

  • 0×00 – Sluk
  • 0xFF – Tænd (level sættes til seneste dæmpning)
  • 0xXX – Dæmpning (0 – 99)

Da Switch klassen allerede gør brug af funktionen SetLevel bliver Dimmer klassen meget simpel.

class Dimmer : Switch
{
    public Dimmer(byte nodeId, ZWavePort zp)
        : base(nodeId, zp)
    {
    }
 
    public void Dim(byte level)
    {
        if ((level >= 0x00) && (level <= 0x63))
        {
            SetLevel(level);
        }
    }
}

C# klienten ændres så deviceklassen Dimmer tages i brug. Dæmpningen sættes til et tilfældig niveau mellem o 0g 99.

static void Main(string[] args)
{
    ...
 
    byte nodeId = 0x06;
    Dimmer d = new Dimmer(nodeId, zp);
 
    nodeId = 0x2B;
    Switch s = new Switch(nodeId, zp);
 
    // Generate random number
    Random r = new Random();
    byte level = (byte)r.Next(99);
 
    s.Off();       // Switch off node '6'
    d.Off();       // Switch off node '43'
    s.On();        // Switch on node '6'
    d.Dim(level);  // Dim node '43' to random level
 
    ...
}

Den enkelte deviceklasse kan nu afgøre, om den har ansvaret for den igangværende beskedsekvens og derfor hvornår en ny beskedsekvens kan igangsættes.
Næste artikel ser på, hvordan de enkelte enheder i Z-Wave netværket ‘automatisk’ identificeres og oprettes som objekter.

Kildekoden kan hentes via dette link. Der er ingen begrænsninger på anvendelsen af kildekoden.

Annoncer

Kommentarer er lukket.