This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

LP-CC2652RB: How to implement ZHA "Smart Plug" device in SampleApp project

Part Number: LP-CC2652RB

Hello, i'm trying to create a custom firmware starting by zr_sampleapp by this tutorial, but i have some troubles defining the device type of the device and its clusters in the .syscfg file in CCS.

The device type that seems correct for my project is the ZHA "Smart Plug" (device_id = 0x0051) found in section 7.4.16 of the ZHA spec, in particular i'd like to have a single endpoint with "metering" and "on/off" clusters (possibly suitable for different energy meters and outputs lines by the same endpoint).

As you can see, "Smart Plug" is not an option in the Zigbee Device Type menu. I tried to choose another one like ''On/Off Output" in order to manually add the missing "metering" cluster as an optional one but it does not appear in the cluster options.

Any advice? Is it possible?

If it is, will it be possible to monitor multiple energy meter and multiple outputs with the same endpoint or will i have to register multiple "Smart Plug" (or similar) endpoint? And in that case, how to add multiple endpoint?

Thank you for any help

Roberto

  • Hello Roberto,

    Metering and ZCL Smart Energy (zcl_se.c/h) are not included in SampleApp capabilities.  You can follow the original SLA development using genericapp instead, or add on to zr_light ZCL data. There are similar E2E threads for a guide on adding multiple endpoints.

    zigbee_02_custom_devices.html
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Designing a Custom Zigbee 3.0-Certifiable Product Using GenericApp</title>
    </head>
    
    <!-- START PRE -->
    <link rel="stylesheet" href="../../../web_support/strapdown/v/0.2/fonts/ubuntu-regular-woff.css"/>
    <link rel="stylesheet" href="../../../web_support/strapdown/v/0.2/fonts/glyphicons-halflings-regular.css"/>
    <link rel="stylesheet" href="../../../web_support/strapdown/v/0.2/themes/united2.min.css"/>
    <link rel="stylesheet" href="../../../web_support/strapdown/v/0.2/themes/bootstrap-responsive.min.css"/>
    <link rel="stylesheet" href="../../../web_support/strapdown/v/0.2/strapdown.css"/>
    <link rel="shortcut icon" type="image/x-icon" href="../../../.metadata/favicon.ico" />
    <!-- END PRE -->
    
    <xmp style="display:none;" class="col-xs-6">
    
    Introduction
    ==================================
    Z-Stack is a component of the SimpleLink CC13x2 / CC26x2 Software Development Kit and is a complete Zigbee 3.0 software solution.
    
    The intention of this lab is to help developers create their own custom Zigbee devices using Z-Stack. Topics that we will cover in this lab include:
    
    1. Choosing a certifiable Zigbee device type from the Zigbee device type specifications
    *  Gathering the required information about your chosen Zigbee device from the Zigbee documentation
    *  Modifying the sample applications provided in the SimpleLink SDK to suit the needs of your chosen Zigbee device
    
    Note: This lab is intended to be a starting point for development, it does not go into details about how to test and verify the final product.
    
    [[b! Technical support
    For any questions you may have, please refer to the [TI Zigbee & Thread E2E Forum](https://e2e.ti.com/support/wireless-connectivity/zigbee-and-thread/).
    ]]
    
    Prerequisites
    ==================================
    
    ### Background
    
    * Familiarity with the Zigbee 3.0 specification
      * More information about the changes in Zigbee 3.0 compared to older specifications can be found in [SWRA615](http://ti.com/lit/pdf/swra615)
    * Basic CCS knowledge
    * Some basic familiarity with embedded programming
    
    ### Software
    
    * [Code Composer Studio](http://www.ti.com/tool/ccstudio) v10.1 or later<br>
    * [SimpleLink CC13x2 / CC26x2 SDK](http://www.ti.com/tool/SIMPLELINK-CC13X2-26X2-SDK) (4.30.xx)
    
    ### Recommended Reading
    
    * [Z-Stack Quick Start Guide](https://dev.ti.com/tirex/explore/node?node=AMej5hnaXjx3i7-NiUkabw__pTTHBmu__LATEST)
    * [TI Z-Stack User's Guide](https://dev.ti.com/tirex/explore/node?node=ANbR0LtTwkMnDCiEhygF7A__pTTHBmu__LATEST)
    
    Zigbee Documentation
    -----------------------
    * Zigbee Cluster Library v7 Specification (**ZCL spec**) - Zigbee Document number **07-5123-07**
    * Zigbee Lighting and Occupancy Device Specification (**ZLO spec**) - Zigbee Document number **15-0014-05**
    * Zigbee Home Automation Public Application Profile  (**ZHA spec**) - Zigbee Document number **05-3520-29**
    
    [[b! Note
    * Zigbee documentation can be obtained from the [Zigbee Alliance website](https://zigbeealliance.org/)
    ]]
    
    Gathering information from Zigbee documentation
    ======================================================
    Before we jump into the software, our first task is to determine which type of Zigbee device we wish to create. Then we must determine which clusters that device must support and which attributes those clusters must support.
    
    1. Choosing a Zigbee device type
    --------------------------------
    There are currently two specifications we can refer to for choosing a Zigbee device type, the Zigbee Lighting and Occupancy Device Specification (**ZLO spec**) and the Zigbee Home Automation Public Application Profile (**ZHA spec**).
    
    The first thing I would recommend doing is going to the "Device Descriptions" sections of both documents, Section 5 in the ZLO spec and Section 5.7 in the ZHA spec. At first glance you will notice that there is some overlap between these two specifications, namely Device ID 0x0100 through 0x0107. If you are creating one of these Zigbee Lighting devices, refer to the information in the ZLO spec instead of the ZHA spec. The ZLO spec is the newest device specification document that has been released by the [Zigbee Alliance website](https://zigbeealliance.org/), so the information in this document is newer and supersedes anything regarding these devices types in the ZHA spec. For all other non-overlapping device types between these two documents, the current instructions from the Zigbee Alliance website are to follow the guidelines in each corresponding document for each device type.
    
    So, let's say we want to create a **Smart Plug** as our Zigbee device. In Section 5.7 of the ZHA spec, we can see in Table 5.1 below that this device has Device ID **0x0051**.
    
    [[+g ZHA Spec: **Table 5.1**  Devices Specified in the HA Profile
    ![Table 5.1](resources/ZHA_Table_5_1.png)
    +]]
    
    2. Determining which clusters our device support
    ----------------------------------------------------
    In the same document that we chose our Zigbee device out of, we can navigate to the section that defines what clusters our device supports. In our case, we need go to Section 7.4.16 of the ZHA spec for Smart Plug. From here we can determine which clusters our device supports under the subsection 'Supported Clusters'.
    
    Here are all the important points from the images below:
    * **Mandatory** and **Optional** Clusters
      * All Zigbee devices must implement their mandatory clusters to pass Zigbee device certification. Zigbee device manufacturers may choose to implement certain optional clusters for their own application needs.
    
      [[b! Note 
      * If you choose to implement an optional cluster, even though it is marked as *optional*, you must still pass certification for that cluster if you wish to include it with your device.
      ]]
    * **Server Side** and **Client Side** cluster implementation
      * Implementing the Server vs. the Client side of a cluster is very important because it determines which attributes you support. <br><br>
    * **Common Clusters** for all Zigbee devices
      * All Zigbee devices support a common set of mandatory and optional clusters, listed below in table 7.1. We can see in section 7.4.16.1 below that it mentions "In addition to those specified in Table 7.1"
    
    [[+g ZHA Spec: **Section 7.4.16.1**  Supported Clusters for Smart Plug
    ![Section 7.4.16.1](resources/ZHA_Section_7_4_16_1.png)
    +]]
    [[+g ZHA Spec: **Table 7.1**  Clusters Common to All Devices
    ![Table 7.1](resources/ZHA_Table_7_1.png)
    +]]
    
    Now, using the information from the tables above, let's make new table that shows what clusters our Smart Plug device is going to support. I will only select the mandatory clusters for this example.
    
    [[+g SLA Table 1: Cluster table for Smart Plug device
    Cluster ID|Cluster Name| Client/Server Side 
    ----------|------------|--------------------
    0x0000    |Basic       |Server              
    0x0003    |Identify    |Client + Server     
    0x0702    |Metering    |Server              
    0x0006    |On/Off      |Server              
    +]]
    
    3. Determining which attributes our clusters support
    ----------------------------------------------------
    Now that we have a list of clusters, we can refer to the Zigbee Cluster Library v7 Specification (**ZCL spec**). The ZCL spec will tell us which attributes our selected clusters support. Each section of the ZCL spec will give us a cluster and tell us which attributes the Server Side and Client Side implementations of that cluster support.
    
    As of the ZCL v6 spec, it is mandatory for every cluster to support the ClusterRevision attribute.
    
    [[+g ZCL Spec: **Table 2-1**  Global attributes for every cluster
    ![Table 2-1](resources/ZCL_Table_2-1.png)
    +]]
    
    Let's start with the **Basic Cluster**. From the table we made in the previous section, we must support the Basic Cluster **Server**. Table 3-7 in Section 3.2.2.2 of the ZCL spec tells us which attributes the Basic Cluster Server supports.
    
    [[+g ZCL Spec: **Table 3-7**  Attributes supported by Basic Cluster Server
    ![Table 3-7_1](resources/ZCL_Table_3-7_1.png)
    ![Table 3-7_2](resources/ZCL_Table_3-7_2.png)
    +]]
    
    Next we can find the **Identify Cluster**, for which we must support both **Client** and **Server**. Table 3-28 in section 3.5.2.2 of the ZCL spec tells us which attributes the Identify Cluster Server supports. Section 3.5.2.1 of the ZCL spec tells us that the Identify Cluster Client does not support any cluster specific attributes.
    
    [[+g ZCL Spec: **Table 3-31**  Attributes supported by Identify Cluster Server
    ![Table 3-31](resources/ZCL_Table_3-31.png)
    +]]
    
    Next is the **Metering Cluster**, for which we must support the Metering Cluster **Server**. The Metering Cluster Server has a very elaborate list of attributes. In fact, so elaborate that it is broken up into 9 different attribute sets, which you can see in section 10.4.2.2 of the ZCL spec. For the purpose of this exercise, I am only going to include snippits from the tables in this section that include mandatory attributes for the Metering Cluster Server.
    
    [[+g ZCL Spec: **Table 10-30**  Attributes in the Reading Information Attribute set of the Metering Cluster Server
    ![Table 10-30](resources/ZCL_Table_10-30.png)
    +]]
    [[+g ZCL Spec: **Table 10-34**  Attributes in the Meter Attribute set of the Metering Cluster Server
    ![Table 10-34](resources/ZCL_Table_10-34.png)
    +]]
    [[+g ZCL Spec: **Table 10-40**  Attributes in the Formatting Attribute set of the Metering Cluster Server
    ![Table 10-40_1](resources/ZCL_Table_10-40_1.png)
    ![Table 10-40_2a](resources/ZCL_Table_10-40_2a.png)
    +]]
    
    Lastly is the **On/Off Cluster**, for which we must support the On/Off Cluster **Server**. Table 3-45 in section 3.8.2.2 of the ZCL spec tells us which attributes the On/Off Cluster Server supports.
    
    [[+g ZCL Spec: **Table 3-45**  Attributes supported by On/Off Cluster Server
    ![Table 3-45](resources/ZCL_Table_3-45.png)
    +]]
    
    Once again, I will create a new table using the information from the tables above that shows us which attributes our Smart Plug device is going to support. I will only select mandatory attributes for this example.
    
    [[+g SLA Table 2: Attribute table for Smart Plug device
    Attribute                 | Cluster    | Data Type | Access             | Default Value
    --------------------------|------------|-----------|--------------------|------------------
    ZCLVersion                |Basic       |uint8      |Read                |2
    PowerSource               |Basic       |enum8      |Read                |0
    ClusterRevision           |Basic       |uint16     |Read                |1
    IdentifyTime              |Identify    |uint16     |Read/Write          |0
    ClusterRevision           |Identify    |uint16     |Read                |1
    CurrentSummationDelivered |Metering    |uint48     |Read                |0
    Status                    |Metering    |map8       |Read                |0
    UnitofMeasure             |Metering    |enum8      |Read                |0
    SummationFormatting       |Metering    |map8       |Read                |0
    MeteringDeviceType        |Metering    |map8       |Read                |0
    ClusterRevision           |Metering    |uint16     |Read                |1
    OnOff                     |On/Off      |bool       |Read/**Reportable** |0
    ClusterRevision           |On/Off      |uint16     |Read                |1
    +]]
    
    [[y! Reportable Attributes
    * If any of the attributes you are supporting have an access type of **Reportable**, it is mandatory for your device to support ZCL reporting which means your device will need to include the compile flag **BDB_REPORTING** which enables ZCL report sending capabilities. We will revisit this again later on in the lab.
    ]]
    
    Modifying the GenericApp project 
    =================================
    It's finally time to start modifying the software to suit our needs. The first thing you will want to do is make a copy of the GenericApp project so we can preserve the original project. You can choose to do this with either a Coordinator, Router, or End Device project. For my example I will use a Router. You can do this by simply making a copy of the the project folder at this path:
    
    `C:\ti\simplelink_cc13x2_26x2_sdk_<version>\examples\rtos\<LaunchPad>\zstack\zr_genericapp`
    
    1. Importing the project into Code Composer Studio
    ------------------------------------------------------
    Now we are ready to import the project into Code Composer Studio (CCS). Open CCS and go to `File > Import > C/C++ Project > CCS Project` and then browse for the zr_genericapp project path under `Select search-directory`:
    
    [[+g Import our modified GenericApp into CCS
    <center>
    ![Project Import](resources/CCS_Project_Import.png)
    </center>
    +]]
    
    At this point it is a good idea to try building the project just to make sure all the file paths resolve correctly, this will verify that we have a good starting point for our incoming code modifications.
    
    2. Add new compile flags to the project
    -----------------------------------------------
    All of the ZCL source code files are included in the GenericApp project by default, but the functionality contained in each file is compiled out via compile flags. Using the table below, determine which compile flags you must add to your project based on the clusters listed in SLA Table 1.
    
    [[+g SLA Table 3: Compile Flag to Cluster correspondence
    Cluster ID | Cluster Name                                        | Compile Flags
    -----------|-----------------------------------------------------|--------------------------
    0x0000     |ZCL_CLUSTER_ID_GEN_BASIC                             |ZCL_BASIC
    0x0001     |ZCL_CLUSTER_ID_GEN_POWER_CFG                         |N/A
    0x0002     |ZCL_CLUSTER_ID_GEN_DEVICE_TEMP_CONFIG                |N/A
    0x0003     |ZCL_CLUSTER_ID_GEN_IDENTIFY                          |ZCL_IDENTIFY
    0x0004     |ZCL_CLUSTER_ID_GEN_GROUPS                            |ZCL_GROUPS
    0x0005     |ZCL_CLUSTER_ID_GEN_SCENES                            |ZCL_SCENES
    0x0006     |ZCL_CLUSTER_ID_GEN_ON_OFF                            |ZCL_ON_OFF
    0x0007     |ZCL_CLUSTER_ID_GEN_ON_OFF_SWITCH_CONFIG              |N/A
    0x0008     |ZCL_CLUSTER_ID_GEN_LEVEL_CONTROL                     |ZCL_LEVEL_CTRL
    0x0009     |ZCL_CLUSTER_ID_GEN_ALARMS                            |ZCL_ALARMS
    0x000A     |ZCL_CLUSTER_ID_GEN_TIME                              |N/A
    0x000B     |ZCL_CLUSTER_ID_GEN_LOCATION                          |ZCL_LOCATION
    0x000C     |ZCL_CLUSTER_ID_GEN_ANALOG_INPUT_BASIC                |N/A
    0x000D     |ZCL_CLUSTER_ID_GEN_ANALOG_OUTPUT_BASIC               |N/A
    0x000E     |ZCL_CLUSTER_ID_GEN_ANALOG_VALUE_BASIC                |N/A
    0x000F     |ZCL_CLUSTER_ID_GEN_BINARY_INPUT_BASIC                |N/A
    0x0010     |ZCL_CLUSTER_ID_GEN_BINARY_OUTPUT_BASIC               |N/A
    0x0011     |ZCL_CLUSTER_ID_GEN_BINARY_VALUE_BASIC                |N/A
    0x0012     |ZCL_CLUSTER_ID_GEN_MULTISTATE_INPUT_BASIC            |N/A
    0x0013     |ZCL_CLUSTER_ID_GEN_MULTISTATE_OUTPUT_BASIC           |N/A
    0x0014     |ZCL_CLUSTER_ID_GEN_MULTISTATE_VALUE_BASIC            |N/A
    0x0015     |ZCL_CLUSTER_ID_GEN_COMMISSIONING                     |N/A
    0x0016     |ZCL_CLUSTER_ID_GEN_PARTITION                         |N/A
    0x0019     |ZCL_CLUSTER_ID_OTA                                   |OTA_CLIENT_CC26XX
    0x001A     |ZCL_CLUSTER_ID_GEN_POWER_PROFILE                     |N/A
    0x001B     |ZCL_CLUSTER_ID_GEN_APPLIANCE_CONTROL                 |N/A
    0x0020     |ZCL_CLUSTER_ID_GEN_POLL_CONTROL                      |N/A
    0x0021     |ZCL_CLUSTER_ID_GREEN_POWER                           |N/A
    0x0022     |ZCL_CLUSTER_ID_MOBILE_DEVICE_CONFIGURATION           |N/A
    0x0023     |ZCL_CLUSTER_ID_NEIGHBOR_CLEANING                     |N/A
    0x0024     |ZCL_CLUSTER_ID_NEAREST_GATEWAY                       |N/A
    0x0100     |ZCL_CLUSTER_ID_CLOSURES_SHADE_CONFIG                 |N/A
    0x0101     |ZCL_CLUSTER_ID_CLOSURES_DOOR_LOCK                    |ZCL_DOORLOCK
    0x0102     |ZCL_CLUSTER_ID_CLOSURES_WINDOW_COVERING              |ZCL_WINDOWCOVERING
    0x0200     |ZCL_CLUSTER_ID_HVAC_PUMP_CONFIG_CONTROL              |ZCL_HVAC_CLUSTER
    0x0201     |ZCL_CLUSTER_ID_HVAC_THERMOSTAT                       |ZCL_HVAC_CLUSTER
    0x0202     |ZCL_CLUSTER_ID_HVAC_FAN_CONTROL                      |ZCL_HVAC_CLUSTER
    0x0203     |ZCL_CLUSTER_ID_HVAC_DIHUMIDIFICATION_CONTROL         |ZCL_HVAC_CLUSTER
    0x0204     |ZCL_CLUSTER_ID_HVAC_USER_INTERFACE_CONFIG            |ZCL_HVAC_CLUSTER
    0x0300     |ZCL_CLUSTER_ID_LIGHTING_COLOR_CONTROL                |ZCL_LIGHT_LINK_ENHANCE
    0x0301     |ZCL_CLUSTER_ID_LIGHTING_BALLAST_CONFIG               |ZCL_LIGHT_LINK_ENHANCE
    0x0400     |ZCL_CLUSTER_ID_MS_ILLUMINANCE_MEASUREMENT            |N/A
    0x0401     |ZCL_CLUSTER_ID_MS_ILLUMINANCE_LEVEL_SENSING_CONFIG   |N/A
    0x0402     |ZCL_CLUSTER_ID_MS_TEMPERATURE_MEASUREMENT            |N/A
    0x0403     |ZCL_CLUSTER_ID_MS_PRESSURE_MEASUREMENT               |N/A
    0x0404     |ZCL_CLUSTER_ID_MS_FLOW_MEASUREMENT                   |N/A
    0x0405     |ZCL_CLUSTER_ID_MS_RELATIVE_HUMIDITY                  |N/A
    0x0406     |ZCL_CLUSTER_ID_MS_OCCUPANCY_SENSING                  |N/A
    0x0500     |ZCL_CLUSTER_ID_SS_IAS_ZONE                           |ZCL_ZONE
    0x0501     |ZCL_CLUSTER_ID_SS_IAS_ACE                            |ZCL_ACE
    0x0502     |ZCL_CLUSTER_ID_SS_IAS_WD                             |ZCL_WD
    0x0600     |ZCL_CLUSTER_ID_PI_GENERIC_TUNNEL                     |N/A
    0x0601     |ZCL_CLUSTER_ID_PI_BACNET_PROTOCOL_TUNNEL             |N/A
    0x0602     |ZCL_CLUSTER_ID_PI_ANALOG_INPUT_BACNET_REG            |N/A
    0x0603     |ZCL_CLUSTER_ID_PI_ANALOG_INPUT_BACNET_EXT            |N/A
    0x0604     |ZCL_CLUSTER_ID_PI_ANALOG_OUTPUT_BACNET_REG           |N/A
    0x0605     |ZCL_CLUSTER_ID_PI_ANALOG_OUTPUT_BACNET_EXT           |N/A
    0x0606     |ZCL_CLUSTER_ID_PI_ANALOG_VALUE_BACNET_REG            |N/A
    0x0607     |ZCL_CLUSTER_ID_PI_ANALOG_VALUE_BACNET_EXT            |N/A
    0x0608     |ZCL_CLUSTER_ID_PI_BINARY_INPUT_BACNET_REG            |N/A
    0x0609     |ZCL_CLUSTER_ID_PI_BINARY_INPUT_BACNET_EXT            |N/A
    0x060A     |ZCL_CLUSTER_ID_PI_BINARY_OUTPUT_BACNET_REG           |N/A
    0x060B     |ZCL_CLUSTER_ID_PI_BINARY_OUTPUT_BACNET_EXT           |N/A
    0x060C     |ZCL_CLUSTER_ID_PI_BINARY_VALUE_BACNET_REG            |N/A
    0x060D     |ZCL_CLUSTER_ID_PI_BINARY_VALUE_BACNET_EXT            |N/A
    0x060E     |ZCL_CLUSTER_ID_PI_MULTISTATE_INPUT_BACNET_REG        |N/A
    0x060F     |ZCL_CLUSTER_ID_PI_MULTISTATE_INPUT_BACNET_EXT        |N/A
    0x0610     |ZCL_CLUSTER_ID_PI_MULTISTATE_OUTPUT_BACNET_REG       |N/A
    0x0611     |ZCL_CLUSTER_ID_PI_MULTISTATE_OUTPUT_BACNET_EXT       |N/A
    0x0612     |ZCL_CLUSTER_ID_PI_MULTISTATE_VALUE_BACNET_REG        |N/A
    0x0613     |ZCL_CLUSTER_ID_PI_MULTISTATE_VALUE_BACNET_EXT        |N/A
    0x0614     |ZCL_CLUSTER_ID_PI_11073_PROTOCOL_TUNNEL              |N/A
    0x0615     |ZCL_CLUSTER_ID_PI_ISO7818_PROTOCOL_TUNNEL            |N/A
    0x0617     |ZCL_CLUSTER_ID_PI_RETAIL_TUNNEL                      |N/A
    0x0700     |ZCL_CLUSTER_ID_SE_PRICE                              |ZCL_SE_PRICE_SERVER, ZCL_SE_PRICE_CLIENT
    0x0701     |ZCL_CLUSTER_ID_SE_DRLC                               |ZCL_SE_DRLC_SERVER, ZCL_SE_DRLC_CLIENT
    0x0702     |ZCL_CLUSTER_ID_SE_METERING                           |ZCL_SE_METERING_SERVER, ZCL_SE_METERING_CLIENT
    0x0703     |ZCL_CLUSTER_ID_SE_MESSAGING                          |ZCL_SE_MESSAGING_SERVER, ZCL_SE_MESSAGING_CLIENT
    0x0704     |ZCL_CLUSTER_ID_SE_TUNNELING                          |ZCL_SE_TUNNELING_SERVER, ZCL_SE_TUNNELING_CLIENT
    0x0705     |ZCL_CLUSTER_ID_SE_PREPAYMENT                         |ZCL_SE_PREPAYMENT_SERVER, ZCL_SE_PREPAYMENT_CLIENT
    0x0706     |ZCL_CLUSTER_ID_SE_ENERGY_MGMT                        |ZCL_SE_ENERGY_MGMT_SERVER, ZCL_SE_ENERGY_MGMT_CLIENT
    0x0707     |ZCL_CLUSTER_ID_SE_CALENDAR                           |ZCL_SE_CALENDAR_SERVER, ZCL_SE_CALENDAR_CLIENT
    0x0708     |ZCL_CLUSTER_ID_SE_DEVICE_MGMT                        |ZCL_SE_DEVICE_MGMT_SERVER, ZCL_SE_DEVICE_MGMT_CLIENT
    0x0709     |ZCL_CLUSTER_ID_SE_EVENTS                             |ZCL_SE_EVENTS_SERVER, ZCL_SE_EVENTS_CLIENT
    0x070A     |ZCL_CLUSTER_ID_SE_MDU_PAIRING                        |ZCL_SE_MDU_PAIRING_SERVER, ZCL_SE_MDU_PAIRING_CLIENT
    0x0800     |ZCL_CLUSTER_ID_SE_KEY_ESTABLISHMENT                  |ZCL_KEY_ESTABLISH
    0x0900     |ZCL_CLUSTER_ID_TELECOMMUNICATIONS_INFORMATION        |N/A
    0x0904     |ZCL_CLUSTER_ID_TELECOMMUNICATIONS_CHATTING           |N/A
    0x0905     |ZCL_CLUSTER_ID_TELECOMMUNICATIONS_VOICE_OVER_ZIGBEE  |N/A
    0x0B00     |ZCL_CLUSTER_ID_HA_APPLIANCE_IDENTIFICATION           |ZCL_APPLIANCE_IDENTIFICATION
    0x0B01     |ZCL_CLUSTER_ID_HA_METER_IDENTIFICATION               |ZCL_METER_IDENTIFICATION
    0x0B02     |ZCL_CLUSTER_ID_HA_APPLIANCE_EVENTS_ALERTS            |ZCL_APPLIANCE_EVENTS_ALERTS
    0x0B03     |ZCL_CLUSTER_ID_HA_APPLIANCE_STATISTICS               |ZCL_APPLIANCE_STATISTICS
    0x0B04     |ZCL_CLUSTER_ID_HA_ELECTRICAL_MEASUREMENT             |ZCL_ELECTRICAL_MEASUREMENT
    0x0B05     |ZCL_CLUSTER_ID_HA_DIAGNOSTIC                         |ZCL_DIAGNOSTIC
    0x1000     |ZCL_CLUSTER_ID_TOUCHLINK                             |N/A
    +]]
    
    In addition to the compile flags in the table above, we must also consider if any of our attributes have an access type of 'Reportable', which is information that we recorded in SLA Table 2. If we have an attribute that is 'Reportable', we must include the compile flag **BDB_REPORTING** in our project.
    
    For our Smart Plug device, we will need to add the compile flags ZCL_ON_OFF, ZCL_SE, ZCL_SE_METERING_SERVER, and BDB_REPORTING. We can add them to the compilation by selecting our project in CCS and going to `Project > Properties > Build > ARM Compiler > Predefined Symbols > Pre-define NAME` and adding the the flags, like in the image below:
    
    [[+g Compile Flags in Project Properties
    ![Compile Flags](resources/ZCL_Compile_Flags.png)
    ```xml
    ZCL_ON_OFF
    ZCL_SE
    ZCL_SE_METERING_SERVER
    BDB_REPORTING
    ```zr_genericapp_[DEVICE]_LAUNCHXL_tirtos_ccs.projectspec
    +]]
    
    3. Making code changes to suit our selected Zigbee device
    -------------------------------------------------------------
    Here is a summarized list of code changes that we need to make to GenericApp to have it suit our needs:
    1. Add ZCL header file(s) to `zcl_genericapp_data.c` and `zcl_genericapp.c`
    
    * Include ZCL Smart Energy files in the project
    
    * Add attributes to `zclGenericApp_Attrs` in `zcl_genericapp_data.c`
    
    * Add Server Side clusters to `zclGenericApp_InClusterList` in `zcl_genericapp_data.c`
    
    * Add Client Side clusters to `zclGenericApp_OutClusterList` in `zcl_genericapp_data.c`
    
    * Update the Simple Descriptor with the appropriate Zigbee device type in `zcl_genericapp_data.c`
    
    * Update the attribute reset function `zclGenericApp_ResetAttributesToDefaultValues` to include the new attributes in `zcl_genericapp_data.c`
    
    * Register for, declare, and implement ZCL command callback functions in `zcl_genericapp.c`
    
    ### Add ZCL header files
    Add the header files for the ZCL files that we added in the step 1 of this section to both `zcl_genericapp_data.c` and `zcl_genericapp.c`
    
    [[+g Add ZCL header files to our application code
    ```c
    #include "zcl_se.h"
    ```zcl_genericapp_data.c and zcl_genericapp.c
    +]]
    
    ### Include ZCL Smart Energy files
    Inside the `Common/zcl` folder, right-click on `zcl_se.c/h` and uncheck the `Exclude from build` option to add the Smart Energy Zigbee Cluster Library to your project.
    
    ### Add attributes
    By default, all of the mandatory attributes for the Basic Server and Identify Server are included, and a number of optional attributes for the Basic Server are included as well. In this section we will only need to address the attributes for the **Metering Server** and **On/Off Server**.
    
    First we will want to make new global variables for each of our attributes. Using **SLA Table 2**, we can make a new global variable in `zcl_genericapp_data.c` for each of these attributes. Use your best judgement for the data types of each variable. For instance, if an attribute is a ZCL uint48, obviously this is not a real data type on our embedded system so we will need to round up to a `uint64_t`.
    
    [[b! Note
    * Since `ClusterRevision` is a global cluster attribute, we only need one instance of the global attribute variable that every cluster can share.
    ]]
    
    [[+g Add global variables to `zcl_genericapp_data.c` to store each of our attributes
    ```c
    #ifdef ZCL_SE_METERING_SERVER
    uint64_t zclGenericApp_CurrentSummationDelivered;
    uint8_t zclGenericApp_Metering_Status;
    uint8_t zclGenericApp_UnitofMeasure;
    uint8_t zclGenericApp_SummationFormatting;
    uint8_t zclGenericApp_MeteringDeviceType;
    #endif // ZCL_SE_METERING_SERVER
    #ifdef ZCL_ON_OFF
    uint8_t zclGenericApp_OnOff;
    #endif // ZCL_ON_OFF
    
    ```
    +]]
    
    The attribute table `zclGenericApp_Attrs` is located in `zcl_genericapp_data.c`. Each attribute entry in `zclGenericApp_Attrs` is formatted as such:
    
    ```c
      {
        ZCL_CLUSTER_ID_GEN_BASIC,             // Cluster IDs - defined in the foundation (ie. zcl.h)
        {  // Attribute record
          ATTRID_BASIC_HW_VERSION,            // Attribute ID - Found in Cluster Library header (ie. zcl_general.h)
          ZCL_DATATYPE_UINT8,                 // Data Type - found in zcl.h
          ACCESS_CONTROL_READ,                // Variable access control - found in zcl.h
          (void *)&zclGenericApp_HWRevision   // Pointer to attribute variable
        }
      },
    ```zclGenericApp_Attrs[]
    
    Using the information in **SLA Table 2**, we can create our own attribute entries in the attribute table. For this step, you will need to look through all the corresponding ZCL header files to locate the correct Cluster ID, Attribute ID, Data Type, and Variable Access Control Type for each attribute. The ZCL header files should already have all of this information defined, you just need to find it and utilize it.
    
    [[+g Add our own attributes to `zclGenericApp_Attrs`
    ```c
    const uint16_t zclSampleLight_metering_clusterRevision = 0x0001;
    const uint16_t zclSampleLight_onoff_clusterRevision = 0x0001;
    
    CONST zclAttrRec_t zclGenericApp_Attrs[] =
    {
      ...
      // new clusters go after what's already on the list
    #ifdef ZCL_SE_METERING_SERVER
      // *** Smart Energy Metering Server Cluster Attributes ***
      {
       ZCL_CLUSTER_ID_SE_METERING,
        { // Attribute record
          ATTRID_SE_METERING_CURR_SUMM_DLVD,
          ZCL_DATATYPE_UINT48,
          ACCESS_CONTROL_READ,
          (void *)&zclGenericApp_CurrentSummationDelivered
        }
      },
      {
       ZCL_CLUSTER_ID_SE_METERING,
        { // Attribute record
          ATTRID_SE_METERING_STATUS,
          ZCL_DATATYPE_BITMAP8,
          ACCESS_CONTROL_READ,
          (void *)&zclGenericApp_Metering_Status
        }
      },
      {
       ZCL_CLUSTER_ID_SE_METERING,
        { // Attribute record
          ATTRID_SE_METERING_UOM,
          ZCL_DATATYPE_ENUM8,
          ACCESS_CONTROL_READ,
          (void *)&zclGenericApp_UnitofMeasure
        }
      },
      {
       ZCL_CLUSTER_ID_SE_METERING,
        { // Attribute record
          ATTRID_SE_METERING_SUMM_FMTG,
          ZCL_DATATYPE_BITMAP8,
          ACCESS_CONTROL_READ,
          (void *)&zclGenericApp_SummationFormatting
        }
      },
      {
       ZCL_CLUSTER_ID_SE_METERING,
        { // Attribute record
          ATTRID_SE_METERING_DEVICE_TYPE,
          ZCL_DATATYPE_BITMAP8,
          ACCESS_CONTROL_READ,
          (void *)&zclGenericApp_MeteringDeviceType
        }
      },
      {
       ZCL_CLUSTER_ID_SE_METERING,
        {  // Attribute record
          ATTRID_CLUSTER_REVISION,
          ZCL_DATATYPE_UINT16,
          ACCESS_CONTROL_READ,
          (void *)&zclSampleLight_metering_clusterRevision
        }
      },
    #endif // ZCL_SE_METERING_SERVER
    #ifdef ZCL_ON_OFF
      // *** On/Off Cluster Attributes ***
      {
        ZCL_CLUSTER_ID_GEN_ON_OFF,
        { // Attribute record
          ATTRID_ON_OFF,
          ZCL_DATATYPE_BOOLEAN,
          ACCESS_CONTROL_READ | ACCESS_REPORTABLE,
          (void *)&zclGenericApp_OnOff
        }
      },
      {
        ZCL_CLUSTER_ID_GEN_ON_OFF,
        {  // Attribute record
          ATTRID_CLUSTER_REVISION,
          ZCL_DATATYPE_UINT16,
          ACCESS_CONTROL_READ,
          (void *)&zclSampleLight_onoff_clusterRevision
        }
      },
    #endif // ZCL_ON_OFF
    };
    ```zcl_genericapp_data.c
    +]]
    
    ### Add Server Side clusters
    Next we must add the Server Side clusters we are implementing to the list `zclGenericApp_InClusterList`. For our Smart Plug example, we must add the Metering cluster and the On/Off cluster.
    
    [[+g Add Server Side Clusters to `zclGenericApp_InClusterList`
    ```c
    const cId_t zclGenericApp_InClusterList[] =
    {
      ZCL_CLUSTER_ID_GEN_BASIC,
      ZCL_CLUSTER_ID_GEN_IDENTIFY,
      ZCL_CLUSTER_ID_SE_METERING,
      ZCL_CLUSTER_ID_GEN_ON_OFF
    };
    ```zclGenericApp_InClusterList[]
    +]]
    
    ### Add Client Side clusters
    Next we must add the Client Side clusters we are implementing to the list `zclGenericApp_OutClusterList`. For our Smart Plug example, we will not need to add anything to this list since Basic and Identify are populated by default.
    
    [[+g Add Server Side Clusters to `zclGenericApp_OutClusterList`
    ```c
    const cId_t zclGenericApp_OutClusterList[] =
    {
      ZCL_CLUSTER_ID_GEN_BASIC,
      ZCL_CLUSTER_ID_GEN_IDENTIFY,
    };
    ```zclGenericApp_OutClusterList[]
    +]]
    
    ### Update the Simple Descriptor
    The Simple Descriptor is used during network device commissioning to let other devices know what type of Zigbee device you are. You will need to update the Simple Descriptor `zclGenericApp_SimpleDesc` in `zcl_genericapp_data.c` with the appropriate Zigbee Device type.
    
    [[+g Update `zclGenericApp_SimpleDesc`
    ```c
    SimpleDescriptionFormat_t zclGenericApp_SimpleDesc =
    {
      GENERICAPP_ENDPOINT,                  //  int Endpoint;
      ZCL_HA_PROFILE_ID,                    //  uint16_t AppProfId;
      // Replaced ZCL_HA_DEVICEID_TEST_DEVICE with application specific device ID
      ZCL_HA_DEVICEID_SMART_PLUG,           //  uint16_t AppDeviceId; 
      GENERICAPP_DEVICE_VERSION,            //  int   AppDevVer:4;
      GENERICAPP_FLAGS,                     //  int   AppFlags:4;
      ZCLGENERICAPP_MAX_INCLUSTERS,         //  byte  AppNumInClusters;
      (cId_t *)zclGenericApp_InClusterList, //  byte *pAppInClusterList;
      ZCLGENERICAPP_MAX_OUTCLUSTERS,        //  byte  AppNumInClusters;
      (cId_t *)zclGenericApp_OutClusterList //  byte *pAppInClusterList;
    };
    ```zclGenericApp_SimpleDesc
    +]]
    
    ### Update the attribute reset function to include the new attributes
    `zclGenericApp_ResetAttributesToDefaultValues` is responsible for initializing and resetting all the applications attributes to their default values. The default values can be obtained from **SLA Table 2**.
    
    [[+g Update `zclGenericApp_ResetAttributesToDefaultValues` with the new attributes
    ```c
    #define DEFAULT_ON_OFF_STATE           0x00
    #define DEFAULT_CURR_SUMM_DLVD_VALUE   0
    #define DEFAULT_METERING_STATUS        0
    #define DEFAULT_UOM_VALUE              0
    #define DEFAULT_SUMM_FMTG_VALUE        0
    #define DEFAULT_METERING_DEVICE_TYPE   0
    
    void zclGenericApp_ResetAttributesToDefaultValues(void)
    {
      ...
    #ifdef ZCL_SE_METERING_SERVER
      zclGenericApp_CurrentSummationDelivered = DEFAULT_CURR_SUMM_DLVD_VALUE;
      zclGenericApp_Metering_Status = DEFAULT_METERING_STATUS;
      zclGenericApp_UnitofMeasure = DEFAULT_UOM_VALUE;
      zclGenericApp_SummationFormatting = DEFAULT_SUMM_FMTG_VALUE;
      zclGenericApp_MeteringDeviceType = DEFAULT_METERING_DEVICE_TYPE;
    #endif
    #ifdef ZCL_ON_OFF
      zclGenericApp_OnOff = DEFAULT_ON_OFF_STATE;
    #endif
    }
    ```zclGenericApp_ResetAttributesToDefaultValues()
    +]]
    
    ### Register for ZCL command callback functions
    
    ZCL command callback functions are where your hardware-specific actions are performed in relation to the state of your cluster attributes. For instance, if you receive a Zigbee command from another device that changes the state of your On/Off Cluster "OnOff" attribute, you can receive a callback to your application saying that something happened, and at this point you would update your global attribute variable with the value passed into the callback function as a parameter and perform your hardware-specific action such as toggling a GPIO pin to reflect the new state of your attribute.
    
    To receive these callback functions in your application, you must register a list of function pointers with each corresponding ZCL module. By default, we already do this with the ZCL General module in zclGenericApp_Init of `zcl_genericapp.c`, as shown below:
    
    [[+g ZCL General cluster command callback registration
    ```c
    static void zclGenericApp_Init( void )
    {
      ...
    
      // Register the ZCL General Cluster Library callback functions
      zclGeneral_RegisterCmdCallbacks( GENERICAPP_ENDPOINT, &zclGenericApp_CmdCallbacks );
      
      ...
    }
    ```zclGenericApp_Init()
    +]]
    
    The second parameter we pass into this function is the list of function pointers that we wish to register with the ZCL general module. For every function present on this list we will receive a callback in our application when the corresponding action has been triggered, and we can set any callback we do not wish to receive to `NULL`. By default, the Basic Cluster Reset callback function is registered with the ZCL general module with the function `zclGenericApp_BasicResetCB`. 
    
    To know which callback functions are available, you must look into the corresponding `zcl<module>_AppCallbacks_t` struct in the ZCL header files. Since the Basic, Identify, and On/Off clusters are all part of the ZCL General group (i.e. check Chapter 3 of the ZCL spec), all of their callback function descriptions are in the struct `zclGeneral_AppCallbacks_t` in `zcl_general.h`. For the Metering cluster, this is part of the ZCL Smart Energy group, so it is in the struct `zclSE_AppCallbacks_t` in `zcl_se.h`. Each function in these structs has a `typedef` associated with it so you can know how to implement the function prototype and definition in your application. For instance, for the Basic Cluster Reset callback, it has the type `zclGCB_BasicReset_t` in the struct `zclGeneral_AppCallbacks_t`, and we can see the `typedef` definition is as below:
    
    ```c
    typedef void (*zclGCB_BasicReset_t)( void );
    ```
    
    And the in our application we can implement this function as such:
    
    ```c
    void zclGenericApp_BasicResetCB( void )
    ```
    
    For the purpose of this lab, I am going to implement two callback functions in my application to show an example of how to do it. I will implement the On/Off cluster "OnOff" callback function and the Metering cluster "Get Profile" callback function.
    
    As stated before, the On/Off cluster is part of the ZCL General group, so its callback is part of the `zclGeneral_AppCallbacks_t zclGenericApp_CmdCallbacks`, which I mentioned before is already defined in our application for the Basic Cluster Reset callback.
    To support the On/Off cluster "OnOff" callback:
    
    [[+g Modify `zclGenericApp_CmdCallbacks` to support another callback function
    ```c
    #ifdef ZCL_ON_OFF
    static void zclGenericApp_OnOffCB( uint8_t cmd );
    #endif
    
    static zclGeneral_AppCallbacks_t zclGenericApp_CmdCallbacks =
    {
      zclGenericApp_BasicResetCB,             // Basic Cluster Reset command
      NULL,                                   // Identfiy cmd
      NULL,                                   // Identify Query command
      NULL,                                   // Identify Query Response command
      NULL,                                   // Identify Trigger Effect command
    #ifdef ZCL_ON_OFF
      zclGenericApp_OnOffCB,                  // On/Off cluster commands
      NULL,                                   // On/Off cluster enhanced command Off with Effect
      NULL,                                   // On/Off cluster enhanced command On with Recall Global Scene
      NULL,                                   // On/Off cluster enhanced command On with Timed Off
    #endif
    #ifdef ZCL_LEVEL_CTRL
      NULL,                                   // Level Control Move to Level command
      NULL,                                   // Level Control Move command
      NULL,                                   // Level Control Step command
      NULL,                                   // Level Control Stop command
    #endif
    #ifdef ZCL_GROUPS
      NULL,                                   // Group Response commands
    #endif
    #ifdef ZCL_SCENES
      NULL,                                  // Scene Store Request command
      NULL,                                  // Scene Recall Request command
      NULL,                                  // Scene Response command
    #endif
    #ifdef ZCL_ALARMS
      NULL,                                  // Alarm (Response) commands
    #endif
    #ifdef SE_UK_EXT
      NULL,                                  // Get Event Log command
      NULL,                                  // Publish Event Log command
    #endif
      NULL,                                  // RSSI Location command
      NULL                                   // RSSI Location Response command
    };
    
    #ifdef ZCL_ON_OFF
    static void zclGenericApp_OnOffCB( uint8_t cmd )
    {
      // do some stuff
    }
    #endif // ZCL_ON_OFF
    ```
    +]]
    
    The Metering cluster is part of the ZCL Smart Energy group, so we must define a new callback struct in our application with the type of `zclSE_AppCallbacks_t`. The ZCL Smart Energy cluster group is extremely elaborate, and because of this the `zclSE_AppCallbacks_t` is a bit different than the other "AppCallbacks" structs. Looking at its implementation, it is actually a struct of more structs, and each one of those other structs is full of callback functions for which we can register for. In addition to implementing these new structs, we must also register with the ZCL Smart Energy module in our initialization function (as we did with the ZCL General module). So, to do all of this, complete the following:
    
    [[+g Add new code to implement the Metering cluster "Get Profile" callback function
    ```c
    #ifdef ZCL_SE_METERING_SERVER
    static void zclGenericApp_MeteringGetProfileCB( zclIncoming_t *pInMsg,
                                        zclSE_MeteringGetProfile_t *pCmd );
    #endif
    
    static const zclSE_MeteringServerCBs_t zclGenericApp_MeteringServerCBs =
    {
      zclGenericApp_MeteringGetProfileCB,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL,
      NULL
    };
    
    static zclSE_AppCallbacks_t zclGenericApp_SECmdCallbacks =
    {
      NULL,               // zclSE_DRLC_ServerCBs_t
      NULL,               // zclSE_DRLC_ClientCBs_t
      &zclGenericApp_MeteringServerCBs,               // zclSE_MeteringServerCBs_t
      NULL,               // zclSE_MeteringClientCBs_t
      NULL,               // zclSE_PriceServerCBs_t
      NULL,               // zclSE_PriceClientCBs_t
      NULL,               // zclSE_MessagingServerCBs_t
      NULL,               // zclSE_MessagingClientCBs_t
      NULL,               // zclSE_TunnelingServerCBs_t
      NULL,               // zclSE_TunnelingClientCBs_t
      NULL,               // zclSE_PrepaymentServerCBs_t
      NULL,               // zclSE_PrepaymentClientCBs_t
      NULL,               // zclSE_EnergyMgmtServerCBs_t
      NULL,               // zclSE_EnergyMgmtClientCBs_t
      NULL,               // zclSE_CalendarServerCBs_t
      NULL,               // zclSE_CalendarClientCBs_t
      NULL,               // zclSE_DeviceMgmtServerCBs_t
      NULL,               // zclSE_DeviceMgmtClientCBs_t
      NULL,               // zclSE_EventsServerCBs_t
      NULL,               // zclSE_EventsClientCBs_t
      NULL,               // zclSE_MDUPairingServerCBs_t
      NULL                // zclSE_MDUPairingClientCBs_t
    };
    
    static void zclGenericApp_Init( void )
    {
     ...
    
    #ifdef ZCL_SE_METERING_SERVER
      zclSE_RegisterCmdCallbacks( GENERICAPP_ENDPOINT, &zclGenericApp_SECmdCallbacks );
    #endif
    
     ...
    }
    
    #ifdef ZCL_SE_METERING_SERVER
    static void zclGenericApp_MeteringGetProfileCB( zclIncoming_t *pInMsg,
                                          zclSE_MeteringGetProfile_t *pCmd )
    {
      // do some stuff
    }
    #endif // ZCL_SE_METERING_SERVER
    ```
    +]]
    
    ### Implement the ZCL command callback functions
    
    As mentioned before, the ZCL command callback functions are where you, the developer, must implement your hardware-specific functionality in your application code based on the high-level intended action of each ZCL command. This is the part of the code where, aside from provided HAL drivers, there is no specific framework for how you should implement your actions since it is highly dependent on your custom hardware design. One thing you must do, however, is update the state of your global attribute(s) in these callback functions (if applicable).
    
    As an example, in the On/Off cluster "OnOff" Callback, you would do at least 2 things: 
    
    1. Update the state of your global "OnOff" attribute based on the function parameter of the callback function.
    *  Perform a hardware-specific action that actually changes the state of your hardware light, such as toggling a GPIO pin.
    
    ### Next Recommended Zigbee SimpleLink Academy Labs
    
    * [Zigbee Fundamental Project Development](../zigbee_03_fundamentals/zigbee_03_fundamentals.html)
    * [Zigbee Security Features](../zigbee_04_security/zigbee_04_security.html)
    * [Zigbee ZCL: Keepalive Poll Control Cluster and Groups/Scenes](../zigbee_06_zcl/zigbee_06_zcl.html)
    
    <div align="center" style="margin-top: 4em; font-size: smaller;">
    <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Creative Commons License" style="border-width:0" src="../../../web_support/cc_license_icon.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License</a>.</div>
    
    </xmp>
    
    <link rel="stylesheet" href="../../../web_support/highlight/styles/zenburn.css"/>
    <script src="../../../web_support/strapdown/vendor/jquery-1.11.2.min.js"></script>
    <script src="../../../web_support/strapdown/vendor/bootstrap.min.js"></script>
    <script src="../../../web_support/highlight/highlight.pack.js"></script>
    <script src="../../../web_support/strapdown/v/0.2/strapdown.js"></script>
    
    </html>
    

    View the html as source in a code or text editor, not as a webpage, and the PNG images have not been provided.  

    Regards,
    Ryan