Z-Way C API Quick Develop Introduction
Z-Way library is a middleware between Silicon Labs Z-Wave transceiver and your application. Z-Way offers pretty high level API to control Z-Wave devices and manage wireless network.
Interaction with the library covers three aspects:
- sending commands to Z-Wave devices;
- sending network management commands to the transceiver;
- receiving updates from the network.
Sending commands
Every command request generates an outgoing packet (job). Before generating a packet, library will validate parameters and check whether the command is supported by recipient. In case of failure command will return error immediately.
Once a job is generated, it is placed into outgoing queue for future send. The queued jobs are handled internally by Z-Way engine according to commands priorities, nodes states and capabilities, transceiver state etc.
Once the job is sent, it must be first confirmed it was successfully delivered to Z-Wave stack, and then confirmed it was delivered to recipient. All these operations are performed asynchronously, so command may provide a callback function to call in case of success or failure if it is needed to know delivery result.
After the delivery was confirmed, command is considered executed. If it was a state request command (i.e. SensorMultilevel Get), response packet may be delayed (or even not sent at all), so command's success/failure callbacks cannot be used to get requested state immediately.
Receiving updates
All incoming packets from Z-Wave network are automatically parsed by Z-Way and stored in special variables called data holders. Data holder is a named variable that stores a value along with its data type and time the value was last updated and "invalidated". Each data holder may also contain a set of child data holders, so they form a hierarchical data storage. Data holders also support callbacks, so custom code may be executed each time the value is updated.
For example, level
data holder stores dimming level of a dimmer. Once application executes a Get command for that dimmer, Z-Way will update invalidateTime
property on the level
data holder, so application knows the current value is assumed to be outdated, but the new one was not received yet.
Once Z-Way received a packet with new value of the dimmer, it will store it in level
data holder and update updateTime
property. Since updateTime
is greater that invalidateTime
, the value is considered valid now.
Some Z-Wave packets contain multiple values. In that case multiple data holders are updated. To have them all already updated in your callback function subscribe to the last modified data holder. The order of update of data holders from one packet is always the same. Some values are stored in data holders subtrees. In that case the subtree parent is updated the last, so the callback is better to be registered on that data holder.
Z-Wave device can also send unsolicited state reports to controller (without a request from controller's side; e.g. due to local operation or periodically). Due to asynchronous nature of Z-Wave protocol, controller can't tell whether the packet was sent unsolicited or it is a response to the previous command. So unsolicited packet will be handled the same way exactly.
Command Classes
Z-Way inherits structure of Z-Wave protocol and divides data holders and command on different Command Classes (CC). Command Classes are building blocks of Z-Wave functionality. For example, dimming is provided by Command Class SwitchMultilevel
, relay operation by CC SwitchBinary
, sensors by CCs SensorMultilevel
and SensorBinary
etc. Please consult Z-Wave protocol basics to understand Z-Wave Command Classes.
All Command Classes share a minimal subset of common data holders:
supported
says if CC is supported by device (it implements that functionality) or only controlled (it can control other devices implementing that functionality).version
stores version of the CC. Used internally to know how to deal with that Command Class.security
tells if CC communications should be encrypted using Z-Wave AES security mechanism.interviewDone
andinterviewCounter
describe the status of initial interview process during which Z-Way asks the device about its CC capabilities. If the interview is incomplete, Z-Way might fail to use some Command Classes with this device. All Z-Wave certified devices MUST pass interview process.
All the other data holders are specific to each Command Class. For example, SwitchMultilevel
Command Class contains level
data holder, SensorBinary
has two-level storage, grouping data by sensor types: 0 → {sensorTypeString, level}, 5 → {sensorTypeString, level}, ...
where type identifiers are Z-Wave specific constants. Every Z-Wave specific constant value will have corresponding verbal description (in case of SensorBinary
it is in sensorTypeString
data holder).
Some Command Classes are hidden under the hood of Z-Way: MultiCmd
, Security
, SecurityS2
, CRC16
, MultiChannel
, ApplicationStatus
, Supervision
, Transport Services
. They're handled internally by Z-Way software, and shouldn't be used directly.
Some Command Classes have no public APIs, but their data holders may be very useful in your application: AssociationGroupInformation
, DeviceResetLocally
, ManufacturerSpecific
, Version
, ZWavePlusInfo
.
All the remaing Command Classes have their Get and Set commands specific to functionality of the Command Class. Consult CommandClassesPublic.h
header file for more info about available commands for different Command Classes and their meaning.
Network management
Z-Way offers API for network management operations: include new devices, exclude devices, discover neighbor devices, remove failed nodes, frequency selection, controller reset etc. These functions are described in ZWayLib.h
header file.
Z-Way also provides a low level access to Z-Wave transceiver functionality through Silicon Labs Z-Wave Serial API. These functions are provided by Function Classes. You should use them only if you have deep knowledge of Z-Wave networking. Check FunctionClassesPublic.h
for more info.
Using Z-Way
To use Z-Way one need to include few header files:
#include <ZWayLib.h>
#include <ZLogging.h>
Z-Way will need to know where to write the log to, so first of all you need to create logging context using zlog_create()
call. You can disable logging by passing NULL instead of logging context to Z-Way.
Then create new Z-Way context using zway_init()
. It will only allocate memory, read log files, initialize internal structures. At this point you can already attach your handlers on new device/instance/Command Class creation (you will also be able to do it at any time later). Do it using zway_device_add_callback()
call. Warning: you should initialize ZWay pointer with NULL before passing it to zway_init
!
Executing zway_start()
will open serial port and start a new thread that will handle all communications with the transceiver. From now Z-Way can receive packets from the network, but can not parse them yet, since devices were not discovered yet. All received packets will just be queued to be parsed later after discovery process.
Last step to run Z-Way is zway_discover()
call. It will start communications with the Z-Wave transceiver and ask about devices in the network, their capabilities, network state etc. During discovery phase Z-Way will create structures for all devices and load saved data from file stored in config/zddx
folder.
From now on, Z-Way is ready to operate. Incoming events will trigger callback functions attached by application, and executing commands will put new packets in the queue.
You will also need few other functions zway_is_running()
, zway_is_idle()
, zway_stop()
, zway_terminate()
to handler termination process.
We suggest you to check z-way-test project and look on comments in header files and read Z-Way documentation.
Handling secure inclusion
Security S0 inclusion is completely handled by the Z-Way library.
Security S2 inclusion with Z-Way library requires user interaction. Z-Way offers various options:
-
Use Smart Start technology:
Callzway_fc_smart_start_enable()
on start (this is done by the library on start).
Add the device DSK usingzway_node_provisioning_dsk_add()
with a pointer to 16 bytes DSK and filled theNodeProvisioningData
structure (instead of filling it one can fill it with zeros).
The inclusion and key exchange will happen automatically on the device's power-up.
All keys will be granted to the device.
zway_dsk_string_to_bytes()
can be used to convert AAAAA-BBBBB-...-HHHHH into 16 bytes.
-
Use the standard key grant process:
After inclusion start subscribe to Command Classes creation (usingzway_device_add_callback()
withCommandAdded
flag) and wait for SecurityS2 creation. Then subscribe to the change ofrequestedKeys
andpuclickKey
data holders on SecurityS2 Command Class data (usingzdata_add_callback()
).
OnrequestedKeys
change inspect inner data holders for the list of requested keys and fill allgrantedKeys
inner data holders (by settingTRUE
orFALSE
).
Once done, setTRUE
on thegrantedKeys
data holder.
OnpuclickKey
update check it against the DSK on the device (it is good to show the full key to the customer to allow full check).
Copy the key in thepuclickKeyVerified
data holder to confirm. IfpublicKeyVerificationRequires
is set toTRUE
, the user should also be asked for the PIN code. This two-bytes code should replace the two leading zero bytes of thepuclickKey
.
If Z-Way has successfully included this device in the past, it will fill thepublicKeyKnownPIN
data holder with the memorized PIN code of that device. This value can be used in the user interface to assist the user in the form where the PIN code is asked. -
Set the PIN and the list of desired security keys before inclusion:
Just before starting the inclusion process withzway_controller_add_node_to_network
set data holders on the controllerS2AutoInclude.pin=XXXXX
(PIN number) andS2AutoInclude.keys=Y
(-1 for all keys, 0x80 for S0 only, 0x01 for S2 Unauthenticated, 0x02 for S2 Authenticated, 0x04 for S2 Access, or any ORed combination to provide multiple keys)
If there is no need for S2 Authentication or S2 Access keys, just specify pin=0 and keys=0x01. This will give S2Unauthenticated without entering the PIN code. keys=0x81 will grant S0 and S2 Unauthenticated.
Working with data holders
To access data holders one can use zdata_...
functions defined in ZData.h
(e.g. zdata_get_integer_array()
, zdata_get_binary()
, zdata_get_string()
). zdata_get_...
functions return pointers to the memory inside data holders. The caller should never directly alter or free that memory in any case. Instead use zdata_set_...
functions.
A lock should always be aquired before working with data holders and held until the value is not used anymore (using zway_aquire_lock()
and zway_release_lock()
). For long term usage copy the value in your own memory.
Offline data storage
Z-Way is storing network topology and devices' information in memory. To remember that data over restarts, Z-Way is storing this information in a special XML file config/zddx/xxxxxxxx-DevicesData.xml, where xxxxxxxx is the Z-Wave Home ID. This file contains the fill datas holder tree for all devices and of the controller.
This file is updated on topology changes, device's interview steps as well as on Z-Way stop. Daily changes (devices' status updates) might be lost on inappropriate Z-Way stop or hardware power off. To reduce the impact of old values stored in the offline storage, it is recommended to save this information hourly using the call zddx_save_to_xml()
.
Z-Way API change
Z-Way C library API changes are registered in the Z-Way Change Log. In addition to the C API, sometimes the data holder structre is also changed. This affects the format of the offline stroage. To transform Z-Way offline storage from the old format to the new one the z-cfg-update tool can be used. It updates the format of xxxxxxxx-DevicesData.xml file. It should be called before Z-Way start after each update or on each Z-Way start.