If your existing Host-NCP solution is lacking Green Power proxy support and you want to add it to the design these steps will walk you through the process of adding it.
Adding host support
First, go to the ZCL Clusters tab and find the Multiple endpoint configuration section at the top. Click the New button to add an endpoint to your device, this will create a second endpoint on the device with identifier 2. Now we need to convert this to a green power endpoint.
In the Configuration column, click the Primary name, which will bring up a button with 3 dots
Click the box to bring up the Endpoint type window
Select the option Create new endpoint type and name your new endpoint Green Power. Click OK.
Keeping the endpoint selected, go to the pull-down menu for ZCL Device Type and change the device to GP Proxy Basic (under GP devices). When this is selected, this will make the endpoint change to number 242. This should also enable Cluster 0x0021, the Green Power cluster, on the device.
Now go to the Plugins tab and on the search bar, enter Green – this will find 4 plugins in the Green Power section:
Check the box next to the Green Power Client and Green Power Common plugins, this will enable them. There isn't any need to change any of the default settings within the plugins, so you can leave those alone.
At this point you should be able to generate and build your host application with no issue and Green Power will be supported. However support for green power needs to be enabled within the NCP.
Adding NCP support
As you are configuring your NCP application, go to the plugins tab and enable the Green Power Stack Library plugin. Make sure the Green Power Stack Stub Library is disabled:
Since this is just a proxy, you can leave the settings as defaulted, proxy table size of 5 and sink table size of 0. However you will need to consider your potential network when configuring your table sizes. A larger proxy table might be needed for supporting all devices on the network.
This is all you need for NCP support. You can generate and build your NCP and combined with your new host code, green power proxy support should be ready to go.
What is the maximum allowed power for ZigBee applications under ETSI EN 300 328?
Although ETSI EN 300 328 allows 20dBm RF output power, there is a limitation for PSD (Power Spectral Density) for wide band modulations other than FHSS. This PSD limit restricts the maximum allowed power for ZigBee applications.
Section 5.4.3.2 in EN 300 328 V2.1.1 details the test method for PSD. The ZigBee modulated signal measured according to Option 2, Step 3 (with sweep time set to 10s):
CW signal with the same power level and spectrum analyzer settings:
The peak power difference between the ZigBee and CW signal measured with RMS detector is ~2.3dB. In order to meet the PSD limit of 10dBm per MHz, the maximum allowed power is 12.3dBm (EIRP).
Note: The 12.3dBm power limit is radiated (EIRP), which means that in case of an antenna with 0dBi, the maximum conducted power allowed is 12.3dBm. For antennas with lower gain than 0dBi, conducted power can be increased, while for antennas with higher gain than 0dBi, conducted power should be reduced.
Measurements were performed on an EFR32MG13 based reference board (BRD4158A Rev A01).
We are now in the home stretch and ready to build our switch to work interfacing a button. The first thing we need to do is put some hooks into our project to give us a place to put our code.
If you remember back when you made the switch project, we enabled the Button Interface plugin, as the name suggests, this gives you an interface for buttons within our callbacks section. If you look at the callbacks tab, you will see these callbacks under the Plugin-specific callbacks. There are callbacks for different button states as well as long and short presses. For this example, let’s pick button 0 as it is generally clear of the ribbon cable on the Thunderboard. We also don’t need much more than a single button press, so let’s make use of the Button0 Pressed Short callback, check the box next to that identifier. *
* Quick note – a short press is by default defined as less than 250 mSec, you can look through the plugin code and the button timeout definition within the plugin to see how this is defined.
Like the light, make sure at the bottom of your callbacks page you have the “Generate project-specific callbacks file” box checked. This will ensure your new callbacks file is generated for your application. You can then save your .ISC file and hit generate to add this new callback. You will get a box that talks about overwriting files. Make sure your Project_callsbacks.c file is checked, you should also create backups, just in case. Then hit OK.
When you see the Generation Successful window, you’re ready to move to the next step.
Locate your project callbacks file on the left view titled Project Explorer and open the file in your editor. You will see that your callbacks file now includes a new, blank function named emberAfPluginButtonInterfaceButton0PressedShortCallback(). This function is called anytime the button is pressed for a short time.
Now we need to take our CLI calls and use this function to make these calls happen within this function. Looking back at our configuration, we send two commands via the CLI to send a message:
zcl on-off toggle
and then either
send 0 1 1
which sent our message outright to a node and endpoint we specified, or
bsend 1
which used a binding table entry to remove our need to know the exact device we were sending a message to.
First let’s look at zcl on-off toggle. To do this, we need something that will construct our message for us. We can look in the Application Framework reference guide and then refer to the Ember Application Framework API Reference and then the Application Framework Command Buffer Loading Interface. In here you will find a number of commands that will help load command or response buffers which can be sent out with some form of a send command.
If you search for the word ‘toggle’ through this document, it should find the function
emberAfFillCommandOnOffClusterToggle()
which is a basic command which constructs our command buffer for us automatically. The benefit of this command is that it handled much of the overhead by utilizing the command buffer, making sending the message much easier later. So, add a call to this function to your button callback function.
Now we need to find a command to send our buffer over the air for us. So let’s return to the Application Framework and click over to the General Application Framework Interface and search for functions that deal with sending messages. On this page, you can search for the word messaging, which locates the function that deal with sending messages within the application framework. If you look through this section, there are a lot of functions which you can call.
You could use a function like emberAfSendUnicast. But this has a lot of parameters. And as we noted, the benefit we had about using the a FillCommand function is that the command buffer overhead has been handled for us. If you look down the list, you will find a number of functions that start out emberAfSendCommand… these are the functions we want to look at. Since this is a specific command send directly to a single node, you can use emberAfSendCommandUnicast(). This takes two options, the first is a messages type and the second is some sort of integer argument that differs based on what your message type is.
If you follow the link for the EmberOutgoingMessageType, you will see a number of different message types. EMBER_OUTGOING_DIRECT would allow you to send a message directly to a node id. Alternatively, a few lines down, you will find EMBER_OUTGOING_VIA_BINDING, which would allow you to leverage a previously made binding to send your message. Let’s take a look at each of these and you can pick the way you want to send your toggle.
EMBER_OUTGOING_DIRECT
If you choose to send a direct unicast to your node ID, this is the same operation as using the command send 0 1 1 to send your message. If you take a look at the send command’s help you will see the pieces you are providing with the numbers:
send (args)
short id of the device to send the message to
The endpoint to send the message from
The endpoint to send the message to
Looking at the emberAfSendCommandUnicast function, your two options are a type and destination. In the case of using type EMBER_OUTGOING_DIRECT, the destination is our short ID of our target. As we noted before, you can use 0x0000 since this is a short id.
This takes care of your node address. But we set our endpoints in the send command, and these are not yet handled. We need some function to configure the endpoints. And we need to configure this before we send our message otherwise it will be too late. Let’s return to the top level of the application framework and look around at operations that manipulate endpoints. If you search for the word endpoints, you will eventually come across the command emberAfSetCommandEndpoints(), which requires a source and destination endpoint. In our case we know both end points are 1, so you can hard code that if you would like, If you want, you can use emberAfPrimaryEndpoint() as the first argument because it’s the only endpoint of our device. However, in the case of the destination endpoint, you can only specify 1 as you need to hard code this.
Now you can test this out. Save your callbacks file and compile your code. Put this new application on your “switch” Thunderboard and press button 0, you should see your light turn on and off.
EMBER_OUTGOING_VIA_BINDING
Alternative to sending a direct message to your node, you can leverage the fact that you have already created a binding and send directly to that. The advantage of this is that it already takes care of all of your settings like node address and endpoints. However, now you must know your binding entry to where you can send this to the on/off cluster.
So go to your console and enter the command ‘option binding-table print’ to display your binding table.
# type nwk loc rem clus node eui
0: UNICA 0 0x01 0x01 0x0003 0x0000 (>)000B57FFFEDEA263
1: UNICA 0 0x01 0x01 0x0006 0x0000 (>)000B57FFFEDEA263
The on-off cluster is 0x0006, so we want to send this to binding table entry 1. You can place this in as the second argument to your function:
Like in _DIRECT format, now test this out. Save your callbacks file and compile your code. Put this new application on your “switch” Thunderboard and press button 0, you should see your light turn on and off.
Follow up
In the end, this isn’t the cleanest code possible. Because this function is hard coded on the button, we are always sending our message. In the included MySwitch_callbacks.c file we have included some code that you can use to check that your network is currently up. We also have print statements to display sensible messages when your light or switch are operating.
Now that we have formed a network, it’s time to verify that we can successfully send messages between our light and switch. To do this will be using simple ZCL commands to start and
First click on the serial console of the switch. At the prompt enter:
zcl on-off toggle
This builds a Zigbee Clusters Library command frame. You can tell it was constructed correctly because of the output:
Command 0x02 is the toggle command and length 3 corresponds to the length of the command buffer.
The buffer is 01 for the frame control, 00 for the sequence number and 02 for the command id for toggle.
Now we want to send this command to our light. Because our light is the coordinator, we know it’s Zigbee node ID is 0x0000. Because we want to send these commands from end point 1 on the switch and to endpoint 1 on the light our command to send this would be:
send 0 1 1
Hitting enter you will see on the light that it received a message for it’s 0x0006 cluster with command 02.
T00000000:RX len 3, ep 01, clus 0x0006 (On/off) FC 01 seq 00 cmd 02 payload[]
On the switch, you will see it received a message as well.
T00000000:RX len 5, ep 01, clus 0x0006 (On/off) FC 08 seq 05 cmd 0B payload[02 00 ]
This is a default response as it is sent back from the light to the switch.
If we look at App Builder, you can see these messages sent in the transaction view, a ZCL: Toggle followed by a ZCL: DefaultResponse. You can look at details of each message as they are sent on the side panel. For example, if you look within the event details of the the DefaultResponse, you can see that the response is Status: SUCCESS, meaning that the message was sent and properly handled.
Because our light is our network coordinator, we know that it’s address is 0x0000. However, most of the time we can’t trust that this will be the case. We need some sort of functionality to get our switch to look for and find our light and then join with the light so that it can easily send messages to the light instead of needing to know the address of the light. Additionally, the switch and light need some means of discovering if they share common clusters, like the off-off cluster. To assist with this, Zigbee provides finding & binding as a standard means of performing just this action.
If you remember back when we created our light and switch, we added a Find and Bind plugin to each device. The Light utilized the Find and Bind Target plugin while the Switch utilized the Find and Bind Initiator plugin. With these plugins, it makes finding and binding easy. Instead of having our light looking for ZCL messages doing endpoint discovery and having to manually construct a full set of ZCL messages to be sent across our network, asking for nodes to identify themselves as well as their endpoints and clusters and then binding like clusters, the plugins will take care of it all for us.
What we will first do is make the light a find and bind target for its endpoints. This will make it monitor network traffic and look for devices which are doing Find and Bind Initiation. To do this we will enter the following command:
plugin find-and-bind target 1
This tells endpoint 1 to act as an endpoint target. You will know the command works because you will see:
Find and Bind Target: Start target: 0x00
Now on the switch we must start it as an initiator. This is a similar function, but instead of target, we use:
plugin find-and-bind initiator 1
When you enter on this, you will see traffic in both the serial window as well as the network capture window as well. The process will be complete when you see
Find and Bind Initiator: Complete: 0x00
In the serial console.
Looking at the network traffic, you can see:
1. Our switch sends out a broadcast ZCL: IdentifyQuery. This is responded to by our light.
2. Then the switch asks the light for its full EUI64 address, the light responds to this with its EUI64.
3. Then finally the switch sends a simple descriptor request to get cluster information from the light. The light responds with 5 clusters which it is server: 0, 3, 4, 5 and 6 and no clusters which it is a client.
From this information our switch with then creates binding with clusters that it matches. For the 5 server clusters on the light, it looks to see if it is a client cluster on any of those, for the switch those are clusters 3 (identify) and 6 (on-off). So if you go to the CLI of the switch and print the binding table, you will see these new bindings, which are bound to the EUI64, not just the short ID. To print the binding table, use the following command:
option binding-table print
The output will look like this:
# type nwk loc rem clus node eui
0: UNICA 0 0x01 0x01 0x0003 0x0000 (>)000B57FFFEDEA263
1: UNICA 0 0x01 0x01 0x0006 0x0000 (>)000B57FFFEDEA263
With these bindings we can then use a bsend command to tell our device to send commands to a binding for a particular endpoint.
zcl on-off toggle
bsend 1
This sends a command to our bindings on endpoint 1.
With this information, we can get to the step of making our light and switch act like a light and switch. The light will turn on or off LEDs based on attribute state, while our switch will respond to a button press instead of sending commands due to CLI entries.
First dock the Mini-Simplicity connectors onto your WSTKs are shown here:
Also connect your ribbon cable as shown. Then connect your Thunderboards on their corresponding 10 pin header. If your mini simplicity connectors do not have keyed headers, make sure to match your pin 1s of both 10 pin headers.
Since we are using Thurnderboards connected externally to our WSTKs, we must make sure our WSTKs are set to debug mode OUT. This can be done via commander. For each WSTK run the following command
commander adapter dbgmode OUT -s XXXXXXX
where XXXXXXX is the serial number of your WSTK.
This can also be performed within Studio from the Launcher perspective. Under the Debug Adapters pane near the top left, you should see the two boards/adapters show up as “J-Link Silicon Labs (4400xxxxx). Highlight each adapter and change the Debug Mode to “OUT”. If you are prompted to update the board firmware, please proceed with the update. Note that when the Debug Mode is OUT, Simplicity Studio does not know about the Thunderboard Sense 2 board anymore and this is expected. (WSTK main board is still recognized.)
Creating bootloaders
Because neither of our applications will run without a bootloader, we want to create a bootloader for each. Fortunately, a default Gecko application bootloader will work for each board in this example.
To generate this bootloader:
Make sure your Simplicity Studio is in either the Launcher view or the Simplicity IDE view.
Then select File > New > Project. This will bring up the New Project Wizard.
On the first screen you want to select Silicon Labs AppBuilder Project and select Next.
Then select Gecko Bootloader and select Next.
When the Select Application screen comes up find the bootloader template titled “SPI Flash Storage Bootloader (single image)”. Select it and hit Next.
Give your Project a name, such as “TB-app-BL” and hit Next.
Finally, you will be asked for your Board, Part and Configuration. Make sure to specify the board as “Thunderboard Sense 2 (BRD4166A)”, this will populate the part field automatically (EFR32MG12P332F1024GL125) then specify your toolchain (GNU ARM 7.2.1 or IAR ARM 8.30.1) and hit Finish.
Once your App Builder project opens, click the generate button to generate your project without any changes. Once the Generation successful window appears, you are done. Then use the Hammer icon on the toolbar to invoke your compiler and build your project. This will give you the binaries to flash onto your board. You will need to locate the file named -combined.s37, it should be located in your projects binary folder.
You should flash this application to each of your Thunderboards, making sure to erase each board as you do this. Because you are flashing an external part, it will ask you to use the device option (-d) to identify the part connected to your board, using EFR32 will be enough to proceed.
We need to verify that each application is properly flashed and running. We will check them from the CLI. To connect to the serial terminals, enter either the Simplicity IDE or Network Analyzer view in Studio. Find your WSTKs under Debug Adapters. Right click on each of them and select “Launch Console.” This will bring up your console window. Switch to the Serial 1 header and press enter a few times, this should cause your Project name to appear as your application prompt.
Ensure that both your Light and Switch are working.
Next, we will step through joining each device onto a network and adding the pieces to each so that you can activate the LEDs of your light and the buttons of your switch.
Now we will form our network with the light and use a Zigbee installation code to join the switch to the network. This will be handled via the CLI, so we will need to connect to the CLI on both devices, this can be done just like in the prior step, right clicking on each WSTK in the Debug Adapter View and select “Launch Console.”
Setting up the network
First, we will form the network on the Light. Go to the CLI for the light and enter the command:
plugin network-creator start 1
This tells the light to invoke the network-creator plugin to start network formation. The 1 option tells the plugin to form the network centralized, this makes the light a trust center as well as a router.
If you see the EMBER_NETWORK_UP, you can check the network settings with the command:
info
This will output network information. They key thing is that your device should have a panID and its nodeID should be 0x0000.
panID [0x06BA] nodeID [0x0000] xpan [0x(>)1989C1541BB9E874]
If this is all set, we can move over to the switch.
Putting the install code on the switch
As noted before, for the switch we are going to use an installation code (also known as an install code) to join our switch to our network. An install code is a means for a device to join a Zigbee network in a reasonably secure fashion. For a complete description of install codes, read AN1089.
The install code itself is a random value installed on the joining device at manufacturing time and is used to encrypt the initial network key transport from the coordinator to the joining device, via a unique link key. To emulate this, we are going to use commander to flash the install code onto our Thunderboard. We have included a file install.txt on this page to give you an install code to work with for this example. While you can use any code you want, this code matches the commands you will see in this example and will allow you to easily follow along with our example. To install this via commander, use this command:
Make sure to flash this onto your Thunderboard that is acting as your switch, it won’t hurt to have the install code on the light, but it has to be on the switch for this join process to work.
The output from commander will look very similar to when you flashed your application to the Thunderboard, but shorter. If you don’t see this output, make sure your Thunderboard is attached to your WSTK and that your WSTK is attached to your computer correctly. Once you have flashed the install code, you can check that it was stored correctly with the following command:
What you are looking for are two sections, at the top that you can see your EUI 64 and near the bottom, that the install code is stored on your device:
If you see this, the install code was correctly installed. You should run this command on your part as you will need your EUI64 for the next steps. NOTE: using the command, the EUI64 and CRC you see there are both in little endian format. Looking at this, the EUI64 is actually: 000B57FFFEDEA4C3 and our CRC is 0x31CE.
Joining the switch to the network
With this information, we will now return to our light. Our light is acting as the coordinator for our network, so It will need to know this information from our joining device. Specifically, it needs to the link key of the joining device. We are going to do a two-step process to get the link key and they move this key to the transient link key table of the light so that the information is changed after the switch joins.
From the light’s CLI, we are going to tell the light the EUI64, the install code and the CRC of the switch, from this information it will hash out the switch’s link key. To do this, enter the following on the light’s CLI:
Let’s look at this command a little closer, because there are a few things to note:
option install-code – this is simply the command which we are running, telling the coordinator we are adding an install-code based link key.
0 – This is the key table entry to add the entry to
{00 0B 57 FF FE DE A4 C3} – this is the EUI64 of the joining device. It is in big endian format. Note, this is the EUI64 of my joining device, you want to make sure to put your EUI64 here.
{31 41 59 26 53 58 97 93 31 CE} – this is our install code (the first 8 bytes) and the CRC (last 4 bytes) we are using. Note that our CRC is in big endian format.
If this command works correctly, you should see the following:
Success: add link key
From this we will then get our new link key from the key table. This is done from the CLI entering:
keys print
This command displays most of the security information for our network. What you are looking for on this display is the key table, which should display information like this:
Link Key Table
0 (>)000B57FFFEDEA4C3 00000000 L y FE 2A 47 BE 40 CC AE B2 DC 54 0E 0A EA DB 82 A1
1/6 entries used.
This is the link key that was derived from the install code. Take note of this new link key, we are going to use it in a future step. With this, you want to delete the key from the permanent key table. To do this enter:
keys delete 0
Which tells the coordinator to delete our 0th entry from the key table.
Now we are going to join the switch to the network. We are also going to watch the process take place on network analyzer, so we can get a graphical representation of the joining process. So first, let’s start our capture. Because we are using an install code, Studio can’t natively see the joining process, so we need to put our install code into Studio. To do this, we need to open Studio’s preference, find the gear icon in Debug Adapter and click it.
This will launch the Preferences window. In the search window enter Security Keys, which should located it under Network Analyzer > Decoding. In that window click New and with the New security Key, enter your link key to allow Studio to be able to decode with it. Hit Apply and then OK to save this information.
Once the link key is added, we can start our capture. From Studio select our two WSTKs again like we did to launch the CLI. We are going to right click on them again, but instead select Start capture (if your environment is particularly noisy, you can select Start capture with options … and only capture off your particular pan ID). This will launch Network Analyzer, Silicon Labs network decryption tool. We won’t dive too deeply into the tool, but we will cover some parts as we work through this example.
At this point you might find it useful to organize Studio to allow you to see more of your windows than you had before. To move around views within Studio, you can drag them around by grabbing their tabs moving them to other areas. When they find a new location, you will see them leave an outline on the window. Since we want to see our network trace as well as both serial windows, you might find an arrangement like this better:
Now we want to return to the CLI of the light. Find the tab that contains the CLI for the light. We are going to open the network for joining and provide the link key of the joining device. We do this with a command from one of our plugins:
plugin network-creator-security open-with-key {00 0B 57 FF FE DE A4 C3} {FE 2A 47 BE 40 CC AE B2 DC 54 0E 0A EA DB 82 A1}
The first set of hex digits is the EUI64 of our joining device, the second is the link key that device will use when joinng. As before, make sure you put your own EUI64 in here. This command will add these keys and open our network for 255 seconds as well.
Now let’s go to the switch CLI. We need to start joining the network. In Zigbee 3.0 this is done by network steering, a plugin we added to our switch. So, in the CLI enter the following:
plugin network-steering start 0
Just like the name says, this starts the network steering process. The 0 option tells the switch to join with no additional options. The primary thing that this does is tell the joining device to change its install code after joining.
If you have arranged your windows as noted, you can watch the process take place in both CLIs and network analyzer. The key step is to watch the transport of the network key. Because have told our device to join with a particular link key, you can watch this key be used to transfer the network key to our device. You can follow other steps graphically, like the device announce of the switch to the network and the request and transport of a new link key.
Now that we have formed our network, it is time for us to start sending communications between our light and switch.
In this tutorial we are going to be demonstrating how to build two simple Zigbee 3.0 applications for a light and a switch using Simplicity Studio on the Thunderboard Sense 2.
This project will start by building up a basic set of applications using AppBuilder which will start out as the framework for our light and switch. Then we will add some custom hardware definitions as well as some custom code and expand the base projects provided to tie the software in with the hardware.
When you are finished you will have a light application that controls the states of LEDs based on software attributes and you will have a switch which reacts to a button to send ZCL messages over the air to update the attributes of the light. Below you will find some basic instructions which walk you along the next few lessons as well as code examples and hardware configuration files to get you started.
Some prerequisites you will need for this tutorial:
NOTE:Version 2.6 of the Gecko SDK introduced EmberZNet 6.6.0. This version of the SDK made fundamental changes in the looks and behaviour of the Application Framework. This Tutorial has been updated to accommodate these changes. The new default wording of the tutorial represents the state of EmberZnet 6.6.0 but for users of the older versions the previous instructions were left in with the following note: "Pre Znet 6.6.0:"
Simplicity Studio 4 with the latest updates
EmberZNet 6.6.3 or later
Pre Znet 6.6.0: EmberZnet 6.4.0 or later (earlier than 6.6.0)
Two Thunderboard Sense 2 boards (BRD4166A)
Two WSTKs (BRD4001A)
Two Mini-Simplicity connectors (BRD8010A) and the included 10 pin ribbon cable
You will also need easy access to Simplicity Commander's CLI interface. While it isn't the only way to program your chips, there are a few steps, like token programming, that require Commander.
So now it’s time to make the physical interface for our light and switch. While being able to send and see messages go across the network is fun, since we are making a light and a switch, we should expect them to act like a light, turning a light source on and off and a switch, taking an input from a button press or similar signal.
First let’s turn our attention to the light, since a light turning on and off is an easier goal to observe. As we have noticed on our last step, we have been toggling one of our cluster attributes, specifically an on-off attribute. What we want is to have our device change based on this attribute’s value. One mechanism that we can use to handle this is through a callback.
A callback is a way that EmberZNet handles events throughout the stack code and application layer as well. If you click on the callbacks tab, you will see a number of calls that can be used throughout your code. These are generally broken down into application callbacks, plugin callbacks, stack callbacks, API callback and cluster callbacks. An in depth look at the callbacks is beyond the scope of this lesson.
For our light code, we are going to need to handle two events. First, at startup we need to enable our lights and configure them. Once that’s done we need to handle the toggling of the light based on the On/Off attribute.
To setup our light, we need to look at the section called “Non-cluster related.” All of these callbacks are in order. As you look down the list you will come across two callbacks Main Init and Main Start, both of these callbacks run at the start of our main() function. Main Init runs right after main executes, but before the network is setup, while Main Start runs right before our main loop executes, after the HAL is done configuring the hardware. In most cases it won’t matter where we set up our LED interface, so for this we will use Main Start, check the box for it.
Next, we need to figure out how to toggle our light on and off. Because this is tied to the on/off cluster, you want to go to the On/Off cluster under the General. Looking through the list, we can find the Server Attribute Changed callback. Since we are operating on the attribute value setting, this is perfect for our needs, check its box as well.
Before we leave this page, make sure at the bottom of your callbacks page you have the “Generate project-specific callbacks file” box checked. This will ensure your new callbacks file is generated for your application.
Before we click generate, we also need to configure all of our GPIOs to work as LEDs. The Thunderboard has 1 green LED, 1 red LED and 4 full color LEDs, for this project we are going to use the full color LEDs. If you read UG309 section 3.4.8, you will see all of the pin definitions, as well as an explanation of how the LEDs are setup.
Next, we need to launch Hardware Configurator (HWConf for short). If you look in your light project, you should see a file named brd4166a_efr32mg12p332f1024gl125.hwconf, this is your header file for your project. Double click on it and it should open in HWConf in the DefaultMode Port I/O. If it isn’t in that format, click that tab at the bottom of the DefaultMode Peripherals window. This view brings us to a graphical representation of the pins, it is where we will set our GPIOs to be available to us within our software.
Setting the GPIOs from within HWConf is fairly straight forward. First you need to go to the Outline view on the top right corner of Studio and open the Port I/O tree. Then click on the Port (A-K) you want to set, this will make those GPIOs become active on the graphical pin grid. Locate the pin you want to setup on the grid (be careful, the pin letters are easy to get confused with their grid identifiers) and click on them. You will then see the Properties of this pin on the middle right of Studio. If you click on the value area within Custom pin name, you will be able to give the pins a name, this will be how you identify the pin in your program.
For example: PJ14 is RGB_LED_ENABLE (note this is configured by default)
Outline view: click on PortJ
DefaultMode Port I/O: Click on PJ14 (located in row B, column 6)
Properties view: name it RGB_LED_ENABLE
Do the same for the following pins – locations provided for easy locating:
PD11 (M10) – LEDS_RED
PD12 (N11) – LEDS_GREEN
PD13 (M11) – LEDS_BLUE
PI0 (G13) – LED0
PI1 (G12) – LED1
PI2 (G11) – LED2
PI3 (F13) – LED3
Remember all of the names you give these pins.
Once this is done, save your HWConf file, this might take some time as it will generate some new hardware configurations. Then return to Simplicity IDE view and click on your MyLight.isc file. Click the Generate button. After some time you will get a validation window to appear. Make sure that all files on this window are checked, Studio will many times leave the *_callbacks.c file unchecked to not overwrite this. Once all the boxes are checked, click OK to continue.
Finally, it is time to put in some code to make our lights turn on and off. First, locate the callbacks file in your project list. It will be called PROJECTNAME_callbacks.c, in our case, this will be MyLight_callbacks.c, double click on it and the code in this file will appear. You will note that you should have 2 additional functions in the project: emberAfMainStartCallback and emberAfOnOffClusterServerAttributeChangedCallback.
First let's enable our lights. Since we need to enable our LEDs as our code starts, we will focus our attention to the emberAfMainStartCallback() function. As noted, this function is called right before our program initiates it's loop while it is running.
Now we will need a fuction to initialize our GPIOs, configuring them as output pins. You can look through docs.silabs.com and find the EMLIB section to discover a function to run this setup. To save you some time, the function you are looking for is:
void GPIO_PinModeSet (GPIO_Port_TypeDef port, unsigned int pin, GPIO_Mode_TypeDef mode, unsigned int out)
The function call for this is defined fully here. But we will step you through the function calls for easy reference.
The first two arguments are the port and pin that we want to configure. Because we have defined our pins in HWConf, you can use those names you assigned these pins in the GUI. They will be something like PIN_NAME_PORT and PIN_NAME_PIN, which correspond do the port letter and port number respectively. If you look in your project tree there is a folder called hal-config and in that folder you will find a file hal-config.h, this file contains the names of the ports and pins for easy reference, locate the section
// $[Custom pin names]
The next argument is how the pin is configured. Fortunately all of our GPIOs are set as outputs and our GPIO mode is going to be gpioModePushPull. A full list of pin options can be found here.
Finally because we are using these as output pins, the last argument is the desired initial state of the pin, either 0: off or 1: on.
Do the same for all of your ports and pins. You should certainly make sure that RGB_LED_ENABLE is on at startup. If you want a particular color, the colored LEDs should be enabled as you want for the color you want to output, red, green or blue, or some combination of them all. LEDs 0-3 can be disabled or enabled, they are what we are going to use to turn on the LEDs.
One final warning the LEDs are quite bright, especially if you turn on all four for white, so be careful when looking at them. After doing so, you might decide you want to start with them off.
At this point you can re-compile your code and test to see if your lights come on. Once you have verified that your LEDs are working, you can then implement the on/off feature.
So now we will move down to the function emberAfOnOffClusterServerAttributeChangedCallback. This function is called anytime a server sided attribute on the light changes. It has two variables in its definition which are the endpoint that is being operated on by the change and the attribute itself which is being changed. In our case we want to change anytime we are seeing a call on our defined endpoint on the on/off attribute and change to the state which is set in that attribute. Despite only having a single endpoint in our project, you should wrap this call to make sure you are calling it on a particular endpoint, because you can then expand it to work for additional endpoint. Since our light functionality is our primary endpoint, you should compare the endpoint passed to this function against this. EmberZnet provides a means of getting this with the function emberAfPrimaryEndpoint(), this means we know that we are getting this called against the main light endpoint.
if (endpoint == emberAfPrimaryEndpoint())
Once we have done that, we need to make sure we are operating on the on/off attribute. First you should look at the file attribute-id.h. This file lists all of the attributes in your project and sets a number of defines for these attributes, using these your code will be much more readable. If you go to the section with the On/off cluster, you will see the ZCL_ON_OFF_ATTRIBUTE_ID, which matches that attribute ID. You can then do some comparison or switch statement and use that as the entry into your function.
if(attributeId == ZCL_ON_OFF_ATTRIBUTE_ID)
Now, we need a means of reading our attribute and turning the light on or off based on this attribute. Because this callback is made after the attribute has changed, we can read this attribute to get its state. To do this we will need to look through the documentation of EmberZNet. If you go to Docs.silabs.com, you can find the Ember Application framework API
On the left, if you click Ember Application Framework API Reference it will show you the sections of the top-level API. At this point we just want the General Application Framework Interface. When you get this page, you will find the Attribute storage section listed at the very top. We are looking for some function to read an attribute, a little searching will find the function emberAfReadServerAttribute, a function that is doing exactly what we want, reading a server attribute, so copy that whole definition and paste it into your code.
Because the function returns an EmberAfStatus, create one to catch the return value. We should only change our LED if the read was successful. You can return to the API guide and look up EmberAfStatus, you will find this is EMBER_ZCL_STATUS_SUCCESS.
if(readStatus == EMBER_ZCL_STATUS_SUCCESS)
Finally we need to make sure we properly read our attribute and change our LED, so go back to emberAfReadServerAttribute function call and let’s set it up properly. We know that our endpoint is the endpoint passed to our callback, so make sure this matches. The cluster ID is that for the on/off cluster. If you look at cluster-id.h, you will see that it is enumerated as ZCL_ON_OFF_CLUSTER_ID, so put that as the 2nd variable in the call. The attribute ID is again ZCL_ON_OFF_ATTRIBUTE_ID, so use that. Finally, we need something to catch the value of the data. I created a boolean type named onOff to catch this, the last two variables of the signature are a pointer to this variable and the size of that variable. In the end our full call looks something like this:
Now we can just use an if-else called against onOff to turn on or turn off our LED. The checking EMLIB again, we see that the function calls for this are:
GPIO_PinOutSet(port, pin);
GPIO_PinOutClear(port, pin);
Make the appropriate calls to the LEDs you want on and off within your code block, save and recompile your code. You can then reflash it to your “light” Thunderboard and use the switch to toggle it from the CLI. If you are able to turn the lights on and off, it’s time to move on to our switch to get it to toggle from the buttons.
Zigbee & Thread Knowledge Base
Adding Green Power Proxy support to an existing Host-NCP
If your existing Host-NCP solution is lacking Green Power proxy support and you want to add it to the design these steps will walk you through the process of adding it.
Adding host support
First, go to the ZCL Clusters tab and find the Multiple endpoint configuration section at the top. Click the New button to add an endpoint to your device, this will create a second endpoint on the device with identifier 2. Now we need to convert this to a green power endpoint.
In the Configuration column, click the Primary name, which will bring up a button with 3 dots
Click the box to bring up the Endpoint type window
Select the option Create new endpoint type and name your new endpoint Green Power. Click OK.
Keeping the endpoint selected, go to the pull-down menu for ZCL Device Type and change the device to GP Proxy Basic (under GP devices). When this is selected, this will make the endpoint change to number 242. This should also enable Cluster 0x0021, the Green Power cluster, on the device.
Now go to the Plugins tab and on the search bar, enter Green – this will find 4 plugins in the Green Power section:
Check the box next to the Green Power Client and Green Power Common plugins, this will enable them. There isn't any need to change any of the default settings within the plugins, so you can leave those alone.
At this point you should be able to generate and build your host application with no issue and Green Power will be supported. However support for green power needs to be enabled within the NCP.
Adding NCP support
As you are configuring your NCP application, go to the plugins tab and enable the Green Power Stack Library plugin. Make sure the Green Power Stack Stub Library is disabled:
Since this is just a proxy, you can leave the settings as defaulted, proxy table size of 5 and sink table size of 0. However you will need to consider your potential network when configuring your table sizes. A larger proxy table might be needed for supporting all devices on the network.
This is all you need for NCP support. You can generate and build your NCP and combined with your new host code, green power proxy support should be ready to go.
Maximum allowed power for ZigBee applications under ETSI EN 300 328
What is the maximum allowed power for ZigBee applications under ETSI EN 300 328?
Although ETSI EN 300 328 allows 20dBm RF output power, there is a limitation for PSD (Power Spectral Density) for wide band modulations other than FHSS. This PSD limit restricts the maximum allowed power for ZigBee applications.
Section 5.4.3.2 in EN 300 328 V2.1.1 details the test method for PSD. The ZigBee modulated signal measured according to Option 2, Step 3 (with sweep time set to 10s):
CW signal with the same power level and spectrum analyzer settings:
The peak power difference between the ZigBee and CW signal measured with RMS detector is ~2.3dB. In order to meet the PSD limit of 10dBm per MHz, the maximum allowed power is 12.3dBm (EIRP).
Note: The 12.3dBm power limit is radiated (EIRP), which means that in case of an antenna with 0dBi, the maximum conducted power allowed is 12.3dBm. For antennas with lower gain than 0dBi, conducted power can be increased, while for antennas with higher gain than 0dBi, conducted power should be reduced.
Measurements were performed on an EFR32MG13 based reference board (BRD4158A Rev A01).
Upgrading the device firmware through UART XMODEM
ZigBee 3.0 Tutorial - Light and Switch from Scratch - Step 7
Physical interface - Switch
Project Overview | Previous Step
We are now in the home stretch and ready to build our switch to work interfacing a button. The first thing we need to do is put some hooks into our project to give us a place to put our code.
If you remember back when you made the switch project, we enabled the Button Interface plugin, as the name suggests, this gives you an interface for buttons within our callbacks section. If you look at the callbacks tab, you will see these callbacks under the Plugin-specific callbacks. There are callbacks for different button states as well as long and short presses. For this example, let’s pick button 0 as it is generally clear of the ribbon cable on the Thunderboard. We also don’t need much more than a single button press, so let’s make use of the Button0 Pressed Short callback, check the box next to that identifier. *
* Quick note – a short press is by default defined as less than 250 mSec, you can look through the plugin code and the button timeout definition within the plugin to see how this is defined.
Like the light, make sure at the bottom of your callbacks page you have the “Generate project-specific callbacks file” box checked. This will ensure your new callbacks file is generated for your application. You can then save your .ISC file and hit generate to add this new callback. You will get a box that talks about overwriting files. Make sure your Project_callsbacks.c file is checked, you should also create backups, just in case. Then hit OK.
When you see the Generation Successful window, you’re ready to move to the next step.
Locate your project callbacks file on the left view titled Project Explorer and open the file in your editor. You will see that your callbacks file now includes a new, blank function named emberAfPluginButtonInterfaceButton0PressedShortCallback(). This function is called anytime the button is pressed for a short time.
Now we need to take our CLI calls and use this function to make these calls happen within this function. Looking back at our configuration, we send two commands via the CLI to send a message:
and then either
which sent our message outright to a node and endpoint we specified, or
which used a binding table entry to remove our need to know the exact device we were sending a message to.
First let’s look at zcl on-off toggle. To do this, we need something that will construct our message for us. We can look in the Application Framework reference guide and then refer to the Ember Application Framework API Reference and then the Application Framework Command Buffer Loading Interface. In here you will find a number of commands that will help load command or response buffers which can be sent out with some form of a send command.
If you search for the word ‘toggle’ through this document, it should find the function
which is a basic command which constructs our command buffer for us automatically. The benefit of this command is that it handled much of the overhead by utilizing the command buffer, making sending the message much easier later. So, add a call to this function to your button callback function.
Now we need to find a command to send our buffer over the air for us. So let’s return to the Application Framework and click over to the General Application Framework Interface and search for functions that deal with sending messages. On this page, you can search for the word messaging, which locates the function that deal with sending messages within the application framework. If you look through this section, there are a lot of functions which you can call.
You could use a function like emberAfSendUnicast. But this has a lot of parameters. And as we noted, the benefit we had about using the a FillCommand function is that the command buffer overhead has been handled for us. If you look down the list, you will find a number of functions that start out emberAfSendCommand… these are the functions we want to look at. Since this is a specific command send directly to a single node, you can use emberAfSendCommandUnicast(). This takes two options, the first is a messages type and the second is some sort of integer argument that differs based on what your message type is.
If you follow the link for the EmberOutgoingMessageType, you will see a number of different message types. EMBER_OUTGOING_DIRECT would allow you to send a message directly to a node id. Alternatively, a few lines down, you will find EMBER_OUTGOING_VIA_BINDING, which would allow you to leverage a previously made binding to send your message. Let’s take a look at each of these and you can pick the way you want to send your toggle.
EMBER_OUTGOING_DIRECT
If you choose to send a direct unicast to your node ID, this is the same operation as using the command send 0 1 1 to send your message. If you take a look at the send command’s help you will see the pieces you are providing with the numbers:
Looking at the emberAfSendCommandUnicast function, your two options are a type and destination. In the case of using type EMBER_OUTGOING_DIRECT, the destination is our short ID of our target. As we noted before, you can use 0x0000 since this is a short id.
This takes care of your node address. But we set our endpoints in the send command, and these are not yet handled. We need some function to configure the endpoints. And we need to configure this before we send our message otherwise it will be too late. Let’s return to the top level of the application framework and look around at operations that manipulate endpoints. If you search for the word endpoints, you will eventually come across the command emberAfSetCommandEndpoints(), which requires a source and destination endpoint. In our case we know both end points are 1, so you can hard code that if you would like, If you want, you can use emberAfPrimaryEndpoint() as the first argument because it’s the only endpoint of our device. However, in the case of the destination endpoint, you can only specify 1 as you need to hard code this.
Now you can test this out. Save your callbacks file and compile your code. Put this new application on your “switch” Thunderboard and press button 0, you should see your light turn on and off.
EMBER_OUTGOING_VIA_BINDING
Alternative to sending a direct message to your node, you can leverage the fact that you have already created a binding and send directly to that. The advantage of this is that it already takes care of all of your settings like node address and endpoints. However, now you must know your binding entry to where you can send this to the on/off cluster.
So go to your console and enter the command ‘option binding-table print’ to display your binding table.
The on-off cluster is 0x0006, so we want to send this to binding table entry 1. You can place this in as the second argument to your function:
emberAfSendCommandUnicast (EMBER_OUTGOING_VIA_BINDING, 1);
Like in _DIRECT format, now test this out. Save your callbacks file and compile your code. Put this new application on your “switch” Thunderboard and press button 0, you should see your light turn on and off.
Follow up
In the end, this isn’t the cleanest code possible. Because this function is hard coded on the button, we are always sending our message. In the included MySwitch_callbacks.c file we have included some code that you can use to check that your network is currently up. We also have print statements to display sensible messages when your light or switch are operating.
Project Overview
Previous Step
ZigBee 3.0 Tutorial - Light and Switch from Scratch - Step 5
Communications
Project Overview | Previous Step | Next Step
Now that we have formed a network, it’s time to verify that we can successfully send messages between our light and switch. To do this will be using simple ZCL commands to start and
First click on the serial console of the switch. At the prompt enter:
This builds a Zigbee Clusters Library command frame. You can tell it was constructed correctly because of the output:
Cluster 0x0006 corresponds to the on-off cluster.
Command 0x02 is the toggle command and length 3 corresponds to the length of the command buffer.
The buffer is 01 for the frame control, 00 for the sequence number and 02 for the command id for toggle.
Now we want to send this command to our light. Because our light is the coordinator, we know it’s Zigbee node ID is 0x0000. Because we want to send these commands from end point 1 on the switch and to endpoint 1 on the light our command to send this would be:
Hitting enter you will see on the light that it received a message for it’s 0x0006 cluster with command 02.
On the switch, you will see it received a message as well.
This is a default response as it is sent back from the light to the switch.
If we look at App Builder, you can see these messages sent in the transaction view, a ZCL: Toggle followed by a ZCL: DefaultResponse. You can look at details of each message as they are sent on the side panel. For example, if you look within the event details of the the DefaultResponse, you can see that the response is Status: SUCCESS, meaning that the message was sent and properly handled.
Because our light is our network coordinator, we know that it’s address is 0x0000. However, most of the time we can’t trust that this will be the case. We need some sort of functionality to get our switch to look for and find our light and then join with the light so that it can easily send messages to the light instead of needing to know the address of the light. Additionally, the switch and light need some means of discovering if they share common clusters, like the off-off cluster. To assist with this, Zigbee provides finding & binding as a standard means of performing just this action.
If you remember back when we created our light and switch, we added a Find and Bind plugin to each device. The Light utilized the Find and Bind Target plugin while the Switch utilized the Find and Bind Initiator plugin. With these plugins, it makes finding and binding easy. Instead of having our light looking for ZCL messages doing endpoint discovery and having to manually construct a full set of ZCL messages to be sent across our network, asking for nodes to identify themselves as well as their endpoints and clusters and then binding like clusters, the plugins will take care of it all for us.
What we will first do is make the light a find and bind target for its endpoints. This will make it monitor network traffic and look for devices which are doing Find and Bind Initiation. To do this we will enter the following command:
This tells endpoint 1 to act as an endpoint target. You will know the command works because you will see:
Now on the switch we must start it as an initiator. This is a similar function, but instead of target, we use:
When you enter on this, you will see traffic in both the serial window as well as the network capture window as well. The process will be complete when you see
In the serial console.
Looking at the network traffic, you can see:
1. Our switch sends out a broadcast ZCL: IdentifyQuery. This is responded to by our light.
2. Then the switch asks the light for its full EUI64 address, the light responds to this with its EUI64.
3. Then finally the switch sends a simple descriptor request to get cluster information from the light. The light responds with 5 clusters which it is server: 0, 3, 4, 5 and 6 and no clusters which it is a client.
From this information our switch with then creates binding with clusters that it matches. For the 5 server clusters on the light, it looks to see if it is a client cluster on any of those, for the switch those are clusters 3 (identify) and 6 (on-off). So if you go to the CLI of the switch and print the binding table, you will see these new bindings, which are bound to the EUI64, not just the short ID. To print the binding table, use the following command:
The output will look like this:
With these bindings we can then use a bsend command to tell our device to send commands to a binding for a particular endpoint.
This sends a command to our bindings on endpoint 1.
With this information, we can get to the step of making our light and switch act like a light and switch. The light will turn on or off LEDs based on attribute state, while our switch will respond to a button press instead of sending commands due to CLI entries.
Project Overview
Previous Step
Next Step
ZigBee 3.0 Tutorial - Light and Switch from Scratch - Step 0
Preparing for this lab
Project Overview | Next Step
First dock the Mini-Simplicity connectors onto your WSTKs are shown here:
Also connect your ribbon cable as shown. Then connect your Thunderboards on their corresponding 10 pin header. If your mini simplicity connectors do not have keyed headers, make sure to match your pin 1s of both 10 pin headers.
Since we are using Thurnderboards connected externally to our WSTKs, we must make sure our WSTKs are set to debug mode OUT. This can be done via commander. For each WSTK run the following command
where XXXXXXX is the serial number of your WSTK.
This can also be performed within Studio from the Launcher perspective. Under the Debug Adapters pane near the top left, you should see the two boards/adapters show up as “J-Link Silicon Labs (4400xxxxx). Highlight each adapter and change the Debug Mode to “OUT”. If you are prompted to update the board firmware, please proceed with the update. Note that when the Debug Mode is OUT, Simplicity Studio does not know about the Thunderboard Sense 2 board anymore and this is expected. (WSTK main board is still recognized.)
Creating bootloaders
Because neither of our applications will run without a bootloader, we want to create a bootloader for each. Fortunately, a default Gecko application bootloader will work for each board in this example.
To generate this bootloader:
Once your App Builder project opens, click the generate button to generate your project without any changes. Once the Generation successful window appears, you are done. Then use the Hammer icon on the toolbar to invoke your compiler and build your project. This will give you the binaries to flash onto your board. You will need to locate the file named -combined.s37, it should be located in your projects binary folder.
You should flash this application to each of your Thunderboards, making sure to erase each board as you do this. Because you are flashing an external part, it will ask you to use the device option (-d) to identify the part connected to your board, using EFR32 will be enough to proceed.
Once you have completed this, you will be ready to begin creating your projects.
Project Overview
Next Step
ZigBee 3.0 Tutorial - Light and Switch from Scratch - Step 3
Flashing and testing the application
Project Overview | Previous Step | Next Step
Locate your files in the binary folder within Studio and select either the .GBL .EBL or .S37 files for your project.
Flash each binary to a separate Thunderboard, making one Thunderboard the light and one the switch.
We need to verify that each application is properly flashed and running. We will check them from the CLI. To connect to the serial terminals, enter either the Simplicity IDE or Network Analyzer view in Studio. Find your WSTKs under Debug Adapters. Right click on each of them and select “Launch Console.” This will bring up your console window. Switch to the Serial 1 header and press enter a few times, this should cause your Project name to appear as your application prompt.
Ensure that both your Light and Switch are working.
Next, we will step through joining each device onto a network and adding the pieces to each so that you can activate the LEDs of your light and the buttons of your switch.
Project Overview
Previous Step
Next Step
ZigBee 3.0 Tutorial - Light and Switch from Scratch - Step 4
Forming and joining the network
Project Overview | Previous Step | Next Step
Now we will form our network with the light and use a Zigbee installation code to join the switch to the network. This will be handled via the CLI, so we will need to connect to the CLI on both devices, this can be done just like in the prior step, right clicking on each WSTK in the Debug Adapter View and select “Launch Console.”
Setting up the network
First, we will form the network on the Light. Go to the CLI for the light and enter the command:
This tells the light to invoke the network-creator plugin to start network formation. The 1 option tells the plugin to form the network centralized, this makes the light a trust center as well as a router.
You should see output similar to the following:
If you see the EMBER_NETWORK_UP, you can check the network settings with the command:
This will output network information. They key thing is that your device should have a panID and its nodeID should be 0x0000.
If this is all set, we can move over to the switch.
Putting the install code on the switch
As noted before, for the switch we are going to use an installation code (also known as an install code) to join our switch to our network. An install code is a means for a device to join a Zigbee network in a reasonably secure fashion. For a complete description of install codes, read AN1089.
The install code itself is a random value installed on the joining device at manufacturing time and is used to encrypt the initial network key transport from the coordinator to the joining device, via a unique link key. To emulate this, we are going to use commander to flash the install code onto our Thunderboard. We have included a file install.txt on this page to give you an install code to work with for this example. While you can use any code you want, this code matches the commands you will see in this example and will allow you to easily follow along with our example. To install this via commander, use this command:
Make sure to flash this onto your Thunderboard that is acting as your switch, it won’t hurt to have the install code on the light, but it has to be on the switch for this join process to work.
The output from commander will look very similar to when you flashed your application to the Thunderboard, but shorter. If you don’t see this output, make sure your Thunderboard is attached to your WSTK and that your WSTK is attached to your computer correctly. Once you have flashed the install code, you can check that it was stored correctly with the following command:
What you are looking for are two sections, at the top that you can see your EUI 64 and near the bottom, that the install code is stored on your device:
If you see this, the install code was correctly installed. You should run this command on your part as you will need your EUI64 for the next steps. NOTE: using the command, the EUI64 and CRC you see there are both in little endian format. Looking at this, the EUI64 is actually: 000B57FFFEDEA4C3 and our CRC is 0x31CE.
Joining the switch to the network
With this information, we will now return to our light. Our light is acting as the coordinator for our network, so It will need to know this information from our joining device. Specifically, it needs to the link key of the joining device. We are going to do a two-step process to get the link key and they move this key to the transient link key table of the light so that the information is changed after the switch joins.
From the light’s CLI, we are going to tell the light the EUI64, the install code and the CRC of the switch, from this information it will hash out the switch’s link key. To do this, enter the following on the light’s CLI:
Let’s look at this command a little closer, because there are a few things to note:
option install-code – this is simply the command which we are running, telling the coordinator we are adding an install-code based link key.
0 – This is the key table entry to add the entry to
{00 0B 57 FF FE DE A4 C3} – this is the EUI64 of the joining device. It is in big endian format. Note, this is the EUI64 of my joining device, you want to make sure to put your EUI64 here.
{31 41 59 26 53 58 97 93 31 CE} – this is our install code (the first 8 bytes) and the CRC (last 4 bytes) we are using. Note that our CRC is in big endian format.
If this command works correctly, you should see the following:
From this we will then get our new link key from the key table. This is done from the CLI entering:
This command displays most of the security information for our network. What you are looking for on this display is the key table, which should display information like this:
This is the link key that was derived from the install code. Take note of this new link key, we are going to use it in a future step. With this, you want to delete the key from the permanent key table. To do this enter:
Which tells the coordinator to delete our 0th entry from the key table.
Now we are going to join the switch to the network. We are also going to watch the process take place on network analyzer, so we can get a graphical representation of the joining process. So first, let’s start our capture. Because we are using an install code, Studio can’t natively see the joining process, so we need to put our install code into Studio. To do this, we need to open Studio’s preference, find the gear icon in Debug Adapter and click it.
This will launch the Preferences window. In the search window enter Security Keys, which should located it under Network Analyzer > Decoding. In that window click New and with the New security Key, enter your link key to allow Studio to be able to decode with it. Hit Apply and then OK to save this information.
Once the link key is added, we can start our capture. From Studio select our two WSTKs again like we did to launch the CLI. We are going to right click on them again, but instead select Start capture (if your environment is particularly noisy, you can select Start capture with options … and only capture off your particular pan ID). This will launch Network Analyzer, Silicon Labs network decryption tool. We won’t dive too deeply into the tool, but we will cover some parts as we work through this example.
At this point you might find it useful to organize Studio to allow you to see more of your windows than you had before. To move around views within Studio, you can drag them around by grabbing their tabs moving them to other areas. When they find a new location, you will see them leave an outline on the window. Since we want to see our network trace as well as both serial windows, you might find an arrangement like this better:
Now we want to return to the CLI of the light. Find the tab that contains the CLI for the light. We are going to open the network for joining and provide the link key of the joining device. We do this with a command from one of our plugins:
The first set of hex digits is the EUI64 of our joining device, the second is the link key that device will use when joinng. As before, make sure you put your own EUI64 in here. This command will add these keys and open our network for 255 seconds as well.
Now let’s go to the switch CLI. We need to start joining the network. In Zigbee 3.0 this is done by network steering, a plugin we added to our switch. So, in the CLI enter the following:
Just like the name says, this starts the network steering process. The 0 option tells the switch to join with no additional options. The primary thing that this does is tell the joining device to change its install code after joining.
If you have arranged your windows as noted, you can watch the process take place in both CLIs and network analyzer. The key step is to watch the transport of the network key. Because have told our device to join with a particular link key, you can watch this key be used to transfer the network key to our device. You can follow other steps graphically, like the device announce of the switch to the network and the request and transport of a new link key.
Now that we have formed our network, it is time for us to start sending communications between our light and switch.
Project Overview
Previous Step
Next Step
ZigBee 3.0 Tutorial - Light and Switch from Scratch
In this tutorial we are going to be demonstrating how to build two simple Zigbee 3.0 applications for a light and a switch using Simplicity Studio on the Thunderboard Sense 2.
This project will start by building up a basic set of applications using AppBuilder which will start out as the framework for our light and switch. Then we will add some custom hardware definitions as well as some custom code and expand the base projects provided to tie the software in with the hardware.
When you are finished you will have a light application that controls the states of LEDs based on software attributes and you will have a switch which reacts to a button to send ZCL messages over the air to update the attributes of the light. Below you will find some basic instructions which walk you along the next few lessons as well as code examples and hardware configuration files to get you started.
Some prerequisites you will need for this tutorial:
NOTE: Version 2.6 of the Gecko SDK introduced EmberZNet 6.6.0. This version of the SDK made fundamental changes in the looks and behaviour of the Application Framework. This Tutorial has been updated to accommodate these changes. The new default wording of the tutorial represents the state of EmberZnet 6.6.0 but for users of the older versions the previous instructions were left in with the following note: "Pre Znet 6.6.0:"
Simplicity Studio 4 with the latest updates
EmberZNet 6.6.3 or later
Pre Znet 6.6.0: EmberZnet 6.4.0 or later (earlier than 6.6.0)
Two Thunderboard Sense 2 boards (BRD4166A)
Two WSTKs (BRD4001A)
Two Mini-Simplicity connectors (BRD8010A) and the included 10 pin ribbon cable
You will also need easy access to Simplicity Commander's CLI interface. While it isn't the only way to program your chips, there are a few steps, like token programming, that require Commander.
Tutorial Steps
ZigBee 3.0 Tutorial - Step 0: Preparation and bootloaders
ZigBee 3.0 Tutorial - Step 1: Creating the projects
ZigBee 3.0 Tutorial - Step 2: Configuring the projects
ZigBee 3.0 Tutorial - Step 3: Flashing and testing our application
ZigBee 3.0 Tutorial - Step 4: Forming and joining the network
ZigBee 3.0 Tutorial - Step 5: Communications
ZigBee 3.0 Tutorial - Step 6: Physical interface - light
ZigBee 3.0 Tutorial - Step 7: Physical interface - switch
Older Tutorial
The videos that went with the older lesson can be found here:
ZigBee Home Automation Developer Tutorial: Light and Switch Overview
ZigBee Home Automation - Light and Switch - part 1
ZigBee Home Automation - Light and Switch - part 2
ZigBee Home Automation - Light and Switch - part 3
ZigBee Home Automation - Light and Switch - part 4
ZigBee Home Automation - Light and Switch - part 5
ZigBee Home Automation - Light and Switch - part 6
ZigBee Home Automation - Light and Switch - part 7
ZigBee Home Automation - Light and Switch - part 8
ZigBee Home Automation - Light and Switch - part 9
ZigBee Home Automation - Light and Switch - part 10
ZigBee Home Automation - Light and Switch - part 11
ZigBee Home Automation - Light and Switch - part 12
ZigBee 3.0 Tutorial - Light and Switch from Scratch - Step 6
Physical interface - Light
Project Overview | Previous Step | Next Step
So now it’s time to make the physical interface for our light and switch. While being able to send and see messages go across the network is fun, since we are making a light and a switch, we should expect them to act like a light, turning a light source on and off and a switch, taking an input from a button press or similar signal.
First let’s turn our attention to the light, since a light turning on and off is an easier goal to observe. As we have noticed on our last step, we have been toggling one of our cluster attributes, specifically an on-off attribute. What we want is to have our device change based on this attribute’s value. One mechanism that we can use to handle this is through a callback.
A callback is a way that EmberZNet handles events throughout the stack code and application layer as well. If you click on the callbacks tab, you will see a number of calls that can be used throughout your code. These are generally broken down into application callbacks, plugin callbacks, stack callbacks, API callback and cluster callbacks. An in depth look at the callbacks is beyond the scope of this lesson.
For our light code, we are going to need to handle two events. First, at startup we need to enable our lights and configure them. Once that’s done we need to handle the toggling of the light based on the On/Off attribute.
To setup our light, we need to look at the section called “Non-cluster related.” All of these callbacks are in order. As you look down the list you will come across two callbacks Main Init and Main Start, both of these callbacks run at the start of our main() function. Main Init runs right after main executes, but before the network is setup, while Main Start runs right before our main loop executes, after the HAL is done configuring the hardware. In most cases it won’t matter where we set up our LED interface, so for this we will use Main Start, check the box for it.
Next, we need to figure out how to toggle our light on and off. Because this is tied to the on/off cluster, you want to go to the On/Off cluster under the General. Looking through the list, we can find the Server Attribute Changed callback. Since we are operating on the attribute value setting, this is perfect for our needs, check its box as well.
Before we leave this page, make sure at the bottom of your callbacks page you have the “Generate project-specific callbacks file” box checked. This will ensure your new callbacks file is generated for your application.
Before we click generate, we also need to configure all of our GPIOs to work as LEDs. The Thunderboard has 1 green LED, 1 red LED and 4 full color LEDs, for this project we are going to use the full color LEDs. If you read UG309 section 3.4.8, you will see all of the pin definitions, as well as an explanation of how the LEDs are setup.
Next, we need to launch Hardware Configurator (HWConf for short). If you look in your light project, you should see a file named brd4166a_efr32mg12p332f1024gl125.hwconf, this is your header file for your project. Double click on it and it should open in HWConf in the DefaultMode Port I/O. If it isn’t in that format, click that tab at the bottom of the DefaultMode Peripherals window. This view brings us to a graphical representation of the pins, it is where we will set our GPIOs to be available to us within our software.
Setting the GPIOs from within HWConf is fairly straight forward. First you need to go to the Outline view on the top right corner of Studio and open the Port I/O tree. Then click on the Port (A-K) you want to set, this will make those GPIOs become active on the graphical pin grid. Locate the pin you want to setup on the grid (be careful, the pin letters are easy to get confused with their grid identifiers) and click on them. You will then see the Properties of this pin on the middle right of Studio. If you click on the value area within Custom pin name, you will be able to give the pins a name, this will be how you identify the pin in your program.
For example: PJ14 is RGB_LED_ENABLE (note this is configured by default)
Do the same for the following pins – locations provided for easy locating:
Remember all of the names you give these pins.
Once this is done, save your HWConf file, this might take some time as it will generate some new hardware configurations. Then return to Simplicity IDE view and click on your MyLight.isc file. Click the Generate button. After some time you will get a validation window to appear. Make sure that all files on this window are checked, Studio will many times leave the *_callbacks.c file unchecked to not overwrite this. Once all the boxes are checked, click OK to continue.
Finally, it is time to put in some code to make our lights turn on and off. First, locate the callbacks file in your project list. It will be called PROJECTNAME_callbacks.c, in our case, this will be MyLight_callbacks.c, double click on it and the code in this file will appear. You will note that you should have 2 additional functions in the project: emberAfMainStartCallback and emberAfOnOffClusterServerAttributeChangedCallback.
First let's enable our lights. Since we need to enable our LEDs as our code starts, we will focus our attention to the emberAfMainStartCallback() function. As noted, this function is called right before our program initiates it's loop while it is running.
Now we will need a fuction to initialize our GPIOs, configuring them as output pins. You can look through docs.silabs.com and find the EMLIB section to discover a function to run this setup. To save you some time, the function you are looking for is:
The function call for this is defined fully here. But we will step you through the function calls for easy reference.
The first two arguments are the port and pin that we want to configure. Because we have defined our pins in HWConf, you can use those names you assigned these pins in the GUI. They will be something like PIN_NAME_PORT and PIN_NAME_PIN, which correspond do the port letter and port number respectively. If you look in your project tree there is a folder called hal-config and in that folder you will find a file hal-config.h, this file contains the names of the ports and pins for easy reference, locate the section
The next argument is how the pin is configured. Fortunately all of our GPIOs are set as outputs and our GPIO mode is going to be gpioModePushPull. A full list of pin options can be found here.
Finally because we are using these as output pins, the last argument is the desired initial state of the pin, either 0: off or 1: on.
So to set up RGB_LED_ENABLE, use the following:
Do the same for all of your ports and pins. You should certainly make sure that RGB_LED_ENABLE is on at startup. If you want a particular color, the colored LEDs should be enabled as you want for the color you want to output, red, green or blue, or some combination of them all. LEDs 0-3 can be disabled or enabled, they are what we are going to use to turn on the LEDs.
One final warning the LEDs are quite bright, especially if you turn on all four for white, so be careful when looking at them. After doing so, you might decide you want to start with them off.
At this point you can re-compile your code and test to see if your lights come on. Once you have verified that your LEDs are working, you can then implement the on/off feature.
So now we will move down to the function emberAfOnOffClusterServerAttributeChangedCallback. This function is called anytime a server sided attribute on the light changes. It has two variables in its definition which are the endpoint that is being operated on by the change and the attribute itself which is being changed. In our case we want to change anytime we are seeing a call on our defined endpoint on the on/off attribute and change to the state which is set in that attribute. Despite only having a single endpoint in our project, you should wrap this call to make sure you are calling it on a particular endpoint, because you can then expand it to work for additional endpoint. Since our light functionality is our primary endpoint, you should compare the endpoint passed to this function against this. EmberZnet provides a means of getting this with the function emberAfPrimaryEndpoint(), this means we know that we are getting this called against the main light endpoint.
Once we have done that, we need to make sure we are operating on the on/off attribute. First you should look at the file attribute-id.h. This file lists all of the attributes in your project and sets a number of defines for these attributes, using these your code will be much more readable. If you go to the section with the On/off cluster, you will see the ZCL_ON_OFF_ATTRIBUTE_ID, which matches that attribute ID. You can then do some comparison or switch statement and use that as the entry into your function.
Now, we need a means of reading our attribute and turning the light on or off based on this attribute. Because this callback is made after the attribute has changed, we can read this attribute to get its state. To do this we will need to look through the documentation of EmberZNet. If you go to Docs.silabs.com, you can find the Ember Application framework API
On the left, if you click Ember Application Framework API Reference it will show you the sections of the top-level API. At this point we just want the General Application Framework Interface. When you get this page, you will find the Attribute storage section listed at the very top. We are looking for some function to read an attribute, a little searching will find the function emberAfReadServerAttribute, a function that is doing exactly what we want, reading a server attribute, so copy that whole definition and paste it into your code.
Because the function returns an EmberAfStatus, create one to catch the return value. We should only change our LED if the read was successful. You can return to the API guide and look up EmberAfStatus, you will find this is EMBER_ZCL_STATUS_SUCCESS.
Finally we need to make sure we properly read our attribute and change our LED, so go back to emberAfReadServerAttribute function call and let’s set it up properly. We know that our endpoint is the endpoint passed to our callback, so make sure this matches. The cluster ID is that for the on/off cluster. If you look at cluster-id.h, you will see that it is enumerated as ZCL_ON_OFF_CLUSTER_ID, so put that as the 2nd variable in the call. The attribute ID is again ZCL_ON_OFF_ATTRIBUTE_ID, so use that. Finally, we need something to catch the value of the data. I created a boolean type named onOff to catch this, the last two variables of the signature are a pointer to this variable and the size of that variable. In the end our full call looks something like this:
Now we can just use an if-else called against onOff to turn on or turn off our LED. The checking EMLIB again, we see that the function calls for this are:
Make the appropriate calls to the LEDs you want on and off within your code block, save and recompile your code. You can then reflash it to your “light” Thunderboard and use the switch to toggle it from the CLI. If you are able to turn the lights on and off, it’s time to move on to our switch to get it to toggle from the buttons.
Project Overview
Previous Step
Next Step