Sleepy Devices#
Introduction#
The Zigbee Application Framework contains support for sleepy end devices. A sleepy end device is a device on the Zigbee network that spends most of its life in a low-power mode and only wakes up the processor when it needs to do something specific such as to interpret a GPIO interrupt or poll its parent to see if there are any messages waiting for it on the network.
Polling#
Sleepy end devices do not receive data directly from other devices on the network. Instead, they must poll their parent for data and receive the data from their parent. The parent acts as a surrogate for the sleepy device, staying awake and buffering messages while the child sleeps. As a result, the sleep/wake cycle of the sleepy end device is governed by two important timeouts on the Zigbee network: the APS retry timeout (7.8 seconds) and the End Device Poll timeout (defined by the parent defaults to 5 minutes). These two timeouts correspond to two polling intervals on the sleepy end device: the SHORT_POLL and the LONG_POLL intervals. These intervals are sometimes referred to as the “nap duration” and “hibernation duration” respectively. So, when a device is in a state where it is continually sending polls out on the SHORT_POLL interval, it is considered to be “napping,” due to the fact that it is continually waking up after a very short period to poll. When a device is sending out polls on the LONG_POLL interval, it is said to be “hibernating,” since it is sleeping for a longer interval.
When a device needs to be responsive to messages being sent to it from the network, it goes into a state where it polls its parent on the SHORT_POLL interval (napping). This ensures that any messages received by its parent will immediately be retrieved by the sleepy end device and processed. When the device no longer needs to be as responsive on the network, it returns to a state where it polls its parent on the LONG_POLL interval (hibernating) which ensures that the child will remain alive in its parent’s child table but will not be responsive to the network.
The time during which the sleepy end device is polling at an augmented rate based on the SHORT_POLL interval is referred to as the “Short Poll Mode,” “Fast Poll Mode,” or simply “Napping.” All these terms mean the same thing. The sleepy device is polling its parent faster than the 7.68 seconds allowed for an end devices parent to hold onto a message for the end device. Generally, the SHORT_POLL interval will be something less than one second to ensure that all messages sent to the parent are processed in an orderly fashion, because the parent is only required to hold onto a single message. If the messages are not retrieved from the parent quickly enough, they may be overwritten by other incoming messages for the same child or some other child. For more information on Fast Polling, see section Forcing Fast Polling.
The SHORT_POLL Interval#
The SHORT_POLL interval is the amount of time that an end device may wait before polling its parent when it is in the process of sending or receiving a message. This interval must be shorter than the Indirect Transmission Timeout (standardized at 7.68 seconds for Zigbee networks). This is because the end device must send an APS ACK back to the sending device before the sending device decides to resend the message. The result is that, in order for sleepy end devices to reliably communicate with other devices on the network, they must know when they are in the process of sending or receiving a message and must wake and poll their parent for data within the short poll interval until the message transaction is complete.
Setting at Compile Time#
The SHORT_POLL interval is configurable in one-second increments and may be modified at compile-time by configuring the End device support component. This sets the define SL_ZIGBEE_AF_PLUGIN_END_DEVICE_SUPPORT_SHORT_POLL_INTERVAL_SECONDS in code.
Setting at Run Time#
You can also modify the SHORT_POLL interval at runtime using the callbacks sl_zigbee_af_set_short_poll_interval_ms_cb or sl_zigbee_af_get_short_poll_interval_qs_cb.
The LONG_POLL Interval#
The LONG_POLL interval is the amount of time that an end device may wait before polling its parent when it is otherwise inactive. This interval should, but is not required to, be shorter than the End Device Poll Timeout, which is the amount of time a parent device will wait to hear from its child before removing it from its child tables. The default end device poll timeout for Zigbee devices is set to 256 minutes.
Note: The Zigbee protocol does not offer a standard way to timeout entries in a child table. In place of this, several heuristic mechanisms exist for aging entries in a child table. For instance, if a parent hears a device that it thinks is its child interacting with another parent or being represented by another parent, it may remove the entry from its child table. Silicon Labs has developed a more deterministic mechanism for child aging called the End Device Poll Timeout. A parent expects that children will “check in” with their parents within the end device poll timeout. If they do not, it assumes that they have gone away and removes them from its child tables. The End Device Poll Timeout may be modified from its default value by configuring the Zigbee stack or leaf components, depending on the local device type.
The end device does not get to configure the end device poll timeout on its parent and there is no agreed upon protocol for communicating the End Device Poll Timeout value between parent and child. In place of this, Silicon Labs has configured an assumed end device poll timeout on both parent and child.
Depending on its sleep characteristics and battery life considerations, the child may wish to sleep past the assumed end device poll timeout. It is free to do this. However, if it does, it must repair the network connection by performing a network rejoin operation before interacting with the network again. Generally, a device that is likely to do this should check the state of the network when it wakes up to see if any repair is necessary before sending data. A sleepy device should never wake and assume that its parent is still there, unless it knows for certain that its parent is configured with a mutually agreed upon End Device Poll Timeout that it is obeying. For more information on the end device poll timeout see the configuration header file located at stack/config/sl_zigbee_configuration_defaults.h.
Setting at Compile Time#
The LONG_POLL interval is configurable in one-second increments and may be modified at compile-time by configuring the End device support component. This sets the define SL_ZIGBEE_AF_PLUGIN_END_DEVICE_SUPPORT_LONG_POLL_INTERVAL_SECONDS in code.
Setting at Run Time#
You can modify the _LONG_POLL at runtime using the callbacks sl_zigbee_af_set_long_poll_interval_ms_cb
or sl_zigbee_af_set_long_poll_interval_qs_cb
.
Setting Values for the SHORT_POLL and LONG_POLL Intervals#
The SHORT_POLL Interval should be less than the Indirect Transmission Timeout of the parent to prevent lost data/ACKs (< 7.8 seconds). The LONG_POLL Interval should be less than the End Device Poll Timeout of the parent (assuming the parent implements an End Device Poll Timeout) to prevent the parent from aging out the end device due to inactivity. By default, the Zigbee stack ships with a 256-minute End Device Poll Timeout. The manufacturer can change the End Device Poll Timeout as they wish. There is no standard way for routers to report their chosen End Device Poll Timeout to their children and it is not required for routers to implement child aging in the Zigbee specification. As a result, if a device implements a LONG_POLL_INTERVAL that is longer than 256 minutes, Silicon Labs recommends that the device check its network status before spontaneously sending messages through its parent. You want the device to make sure that the connection to the parent is up before it sends a message. If the network is not up, the device should perform a network rejoin to make sure that it has a parent before sending any message out over the air.
Forcing Fast Polling#
Fast Polling is the state during which the stack actively polls its parent device faster than the 7.68 second child message timeout interval. The Zigbee Application Framework polls at the rate defined by the SHORT_POLL interval when it is in this mode. The Zigbee Application Framework automatically keeps the stack in the fast poll mode during the sending and ACKing of an APS message. When a device sends a message that is part of a series of application-level request/responses—as is the case in Smart Energy Registration—it must keep the device in fast poll mode until the entire transaction is completed.
The Zigbee Application Framework can ensure that the application stays in short poll mode for as long as the application requires by setting a flag in the emberAfCurrentAppTasks mask. To do this, create your own flag for the sl_zigbee_af_current_app_tasks
that fits in with what is available according to the named masks in app/framework/include/af.h. The top 16 bits of the sl_zigbee_af_current_app_tasks
mask are reserved for customer use. Once you have chosen a flag for your application, you may use the sl_zigbee_af_current_app_tasks
and sl_zigbee_af_remove_from_current_app_tasks
functions to add and remove your flag. If the flag is present in the sl_zigbee_af_current_app_tasks
global bitmask, the application does not allow the stack to back into hibernation mode and the stack stays in short poll mode, during which it uses the SHORT_POLL interval to determine how quickly to poll the parent. The usage of this API is also documented in app/framework/include/af.h.
Using Fast Polling to Complete a Complex Transaction#
Sometimes a sleepy device needs to stay in fast poll mode while sending a complex series of messages that constitute a complete application-level transaction with another device. The general strategy for this type of interaction on a sleepy end device is as follows:
Sleepy end device A needs to perform a series of messages with device B, called a transaction.
Sleepy end device A creates an event that will serve as a timeout for the application-level transaction, called the transaction timeout event.
Sleepy end device A starts the event and sends the first message to device B.
If the message is an APS message, sleepy end device A will automatically stay in short poll mode until the APS Ack comes back from the responding device.
If the message is a ZCL command, sleepy end device A will also automatically stay in short poll mode long enough to give device B a chance to send any application-level command response required by the ZCL
Sleepy end device A continues with its series of messages back and forth to device B until the whole transaction is complete.
When the final message of the transaction is completed with device B, Sleepy end device A removes the flag from emberAfCurrentAppTasks thereby allowing the device to naturally go back to using the hibernate or LONG_POLL period for sleeping.
If device A and B are not able to complete their transaction as expected, Sleepy End Device A removes the flag from emberAfCurrentAppTasks when the transaction timeout event set up in step 1 fires.
Difference in Polling on SoC and Host+NCP Models#
The requirements of polling result in different sleep patterns for the System-On-Chip (SoC) and the Host + NCP models. In the Host + NCP model, it is the NCP that is responsible for polling at the SHORT_POLL and LONG_POLL intervals. The only responsibility of the host processor is to tell the NCP how frequently to poll. Other than that, the host may sleep indefinitely or until there is some internal event, a GPIO interrupt, or the NCP receives a message that it passes to the host for processing. Conversely, the SoC itself is responsible for polling its parent, so it must be sure to wake within the SHORT_POLL and LONG_POLL intervals in order to do so. The Zigbee Application Framework uses the internal event mechanism on the SoC to schedule polling. On the host, it sends a message down to the NCP to tell it when to poll.
Sleeping and the Event Mechanism#
The Zigbee Application Framework automatically checks with the event mechanism to see when the next application event is scheduled. The Zigbee Application Framework never sleeps through an event. The sleep period is always shorter than the amount of time to the next application event within the framework. On the SoC, the amount of time that a device will sleep is generally governed by the SHORT_POLL and LONG_POLL intervals, because the polling event is also an event within the Zigbee Application Framework. On the host, the processor will attempt to sleep until the next application event.
Never Use Ticks on a Sleepy End Device#
All application events should be scheduled through the event mechanism using either custom or cluster events on a sleepy end device. This is because the event mechanism provides a central repository for the sleep handling code so that it knows how long it can sleep. If you rely on the sl_zigbee_af_main_tick_cb to fire frequently enough to handle application events on your sleepy end device, you will be forced to wake the sleepy end device on an artificially short interval so that the sl_zigbee_af_main_tick_cb can be serviced.
End Device Parent Rediscovery#
If an end device loses contact with its parent, it will automatically begin to rejoin the network either with the existing parent or a new parent by calling sl_zigbee_af_start_move
. The sl_zigbee_af_start_move
function schedules a “move” event in the Zigbee Application Framework’s event scheduling mechanism with the following characteristics:
When the move event fires, the device calls sl_zigbee_find_and_rejoin_network.
The move event is automatically rescheduled so that a network rejoin will be attempted every 10 seconds until
SL_ZIGBEE_AF_REJOIN_ATTEMPTS_MAX
is reached.If
SL_ZIGBEE_AF_REJOIN_ATTEMPTS_MAX
is set to 0xff (default) the rejoin will be attempted every 10 seconds until a network is found.The first attempt to rejoin the network is always performed with security on. Each subsequent attempt is performed with security off.
This orphan behavior can obviously have an impact on the life of a battery-powered device. By default, an end device will attempt a maximum of three rejoin attempts before giving up. This and other related configuration options may be found in the end device support config component.
Sleepy End Devices and the CLI#
It is very difficult to interact with a sleepy end device on the CLI when it is sleeping. If you would like your sleepy end device to stay awake when it is not connected to a network, you can do so by enabling the "Stay awake when NOT joined" option in the Application Framework Common config component.
The other alternative is to provide a button Interrupt Service Routine (ISR) handler that toggles the device between a default wake and sleep state. A sample implementation may be enabled by enabling the “Use button to force wakeup or enable sleep” option in the Application Framework Common config component.
Processor Idling and the Zigbee Application Framework#
The Zigbee Application Framework implements processor idling for sleepy devices. This feature augments power savings for sleepy devices by idling the processor during times that there are no events happening. This means that a sleepy device will not continually run through the application’s main loop when it is awake. Instead, the processor will idle until it receives an interrupt either from an external line or a scheduled event. Once each event has been handled, it is marked as ready to idle. The processor will then wait until the next internal or external interrupt before running through the application’s main loop again.
Some typical examples of when a sleepy device can save energy by idling include:
While a packet—such as a data poll—is being transmitted from a sleepy device, the CPU is usually just waiting for the transmission to finish and can idle.
While waiting for the crystal to stabilize, the CPU eventually runs out of initialization and calibration operations to do, so it can idle.
While waiting for the ACK to a transmitted packet. The radio still needs to be on in receive mode, so the processor cannot deep sleep but can safely idle.