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.

CC2652R: Occupancy sensor and lighting

Part Number: CC2652R
Other Parts Discussed in Thread: SIMPLELINK-CC13X2-26X2-SDK, SYSCONFIG

Hello TI!

I have a sensor that I want to use as an occupancy sensor, which is neither PIR nor ultrasonic.

I have written the program for the sensor on my LP-CC2652R and want to use it with the Zigbee stack (as an end device) to communicate "occupied" / "not occupied" state to a coordinator on another LP-CC2652R.

As the current setup I have used the zc_sampleapp and zed_sampleapp as a starting point and added the clusters with the .syscf according to the ZHA and ZCL specifications for Occupancy Sensor. Coordinator is On/Off Light with Occupancy Sensing, and End Device is Occupancy Sensor. This is where I am stuck. The devices are in the network, but how should my working occupancy sensor application manage to communicate "Occupied" / "Not occupied"?

  1. Is it the WEAK map8 sampleApp_OccupancySensing_Occupancy; that needs to be copied into sampleapp.c?
  2. Is it possible fuse the zstack application code with my own for the occupancy sensor with thread synchronization and semaphores? Is it as simple as telling the zstack application to wait until the occupancy sensor notices a change in presence and posts?
  • Hi christng,

    Have you followed the Designing a Certifiable Product SimpleLink Academy Lab?  Referring to the ZigBee Lighting & Occupancy Device Specification, you should make sure that your ZC has Occupancy sensing (0x0406) defined as a client cluster while defined as a server cluster on your ZED.  Occupancy sensing is a reportable attribute, so if a bind is correctly formed then reports should be capable of sending automatically.  You can review the temperature sensor/thermostat application examples for a model of this functionality.  Otherwise, you should be able to use zcl_SendCommand from the ZED occupancy sensor.  The ZC can register a callback to receive and process the data accordingly.  Also, please be aware of the following SampleApp issues in SIMPLELINK-CC13X2-26X2-SDK v5.10 which will be resolved for v5.20:

    https://e2e.ti.com/f/1/t/1005968 
    https://e2e.ti.com/f/1/t/996443 
    https://e2e.ti.com/f/1/t/1015341 

    Regards,
    Ryan

  • Hey Ryan,

    I have followed that lab but will read through the last part again. The temperature sensor/thermostat example helped me out!

    How am I supposed to handle the mandatory attributes "OccupancySensorType" and "OccupancySensorTypeBitmap"? Should I ignore them?

    Thanks

  • Those attributes are not a concern if you do not need to use them for your application.

    Regards,
    Ryan

  • Hello Ryan,

    I have looked at the temperature sensor/thermostat example and need some clarifications:

    1. On my ZED I have used one of the buttons as a "presence" toggle (to test) and changed the attribute value as done in the temperature sensor example; How is the ZC supposed to handle the incoming bdb report? I noticed that the ZCL_CMD_REPORT case in my sampleapp.c was empty and added a function for processing similar to the one in the thermostat example. Is this where the reported occupancy change ends up at the ZC?

    2. How do I know if a bind is correctly formed? I have followed the lab and the Zigbee Cluster Library Specifications where my On/Off light is ZC and Occupancy Sensor is ZED. They successfully join the same network; Can I assume that it is then correctly formed?

    Thanks in advance.

  • 1. You can once again refer to the thermostat example, where zclSampleThermostat_ProcessInReportCmd is used to process incoming attribute reports.

    2. Please reference the zstackmsg_CmdIDs_BDB_BIND_NOTIFICATION_CB from *_processZStackMsgs, for example zstackmsg_CmdIDs_BDB_BIND_NOTIFICATION_CB which performs uiProcessBindNotification for the UI.

    I recommend you set up a sniffer device to monitor your network's over-the-air packets.

    Regards,
    Ryan

  • Hello,

    I managed to make the ZED bind to ZC properly once by commisioning. The Bind Info on ZED referred to the ZC IEEE Addr, cluster ID: 0x0406 and endpoint 0x08. I tried to monitor the over-the-air packets and confirmed that the ZED was sending packets when I pressed the button.

    I tried to recreate the binding by commisioning, but haven't succeeded since. I'm not sure what I did different when the bind succeeded.

    Any suggestions on what might be the reason for this?

  • If you are using BDB Finding & Binding, zstack_bdbStartCommissioningReq.commissioning_mode |= BDB_COMMISSIONING_MODE_FINDING_BINDING;, the bind should be formed automatically on commissioning so long as the Identify Time has not expired.  If you are using a manual bind (Zstackapi_ZdoBindReq) keep in mind that the bind source and destination IEEE address/endpoints must be used along with the packet destination's short address (see the Zigbee Fundamentals SLA).  Perhaps you could consider factor resetting both devices to determine whether behavior changes.  Please provide a sniffer log and/or debug information for further assistance.

    Regards,
    Ryan

  • Dear Ryan,

    Factor resetting both devices and commisioning successfully formed a binding again, thank you. Do you happen to know why the sampleApp example has two processKey functions, zclSampleApp_processKey() and sampleApp_processKey()? They are both key event handler functions, should I omit one?

    static void zclSampleApp_processKey(uint8_t key, Button_EventMask buttonEvents)
    {
        if (buttonEvents & Button_EV_CLICKED)
        {
            if(key == CONFIG_BTN_LEFT)
            {
                zstack_bdbStartCommissioningReq_t zstack_bdbStartCommissioningReq;
    
                zstack_bdbStartCommissioningReq.commissioning_mode = zclSampleApp_BdbCommissioningModes;
                Zstackapi_bdbStartCommissioningReq(sampleApp_serviceTaskId,&zstack_bdbStartCommissioningReq);
            }
            if(key == CONFIG_BTN_RIGHT)
            {
    
            }
        }
    }
    
    static void sampleApp_processKey(Button_Handle _btn)
    {
        zstack_bdbStartCommissioningReq_t zstack_bdbStartCommissioningReq;
        //Button 1
        if(_btn == gLeftButtonHandle)
        {
            if(ZG_BUILD_COORDINATOR_TYPE && ZG_DEVICE_COORDINATOR_TYPE)
            {
    
                zstack_bdbStartCommissioningReq.commissioning_mode = BDB_COMMISSIONING_MODE_NWK_FORMATION | BDB_COMMISSIONING_MODE_NWK_STEERING | BDB_COMMISSIONING_MODE_FINDING_BINDING;
                Zstackapi_bdbStartCommissioningReq(sampleApp_serviceTaskId,&zstack_bdbStartCommissioningReq);
            }
            else if (ZG_BUILD_JOINING_TYPE && ZG_DEVICE_JOINING_TYPE)
            {
                zstack_bdbStartCommissioningReq.commissioning_mode = BDB_COMMISSIONING_MODE_NWK_STEERING | BDB_COMMISSIONING_MODE_FINDING_BINDING;
                Zstackapi_bdbStartCommissioningReq(sampleApp_serviceTaskId,&zstack_bdbStartCommissioningReq);
            }
        }
        //Button 2
        if(_btn == gRightButtonHandle)
        {
            Zstackapi_bdbResetLocalActionReq(sampleApp_serviceTaskId);
        }
    }

  • zclSampleApp_processKey is used by the UI in a callback context, sampleApp_processKey is seemingly unused unless SAMPLEAPP_KEY_EVT is used by your application.  I will submit this feedback to the Software Development Team for further clarification.

    Regards,
    Ryan

  • Hello,

    I have a question regarding handling the occupancy report. Right now, for my ZC, I have the sampleapp running on the device with all the mandatory clusters for an On/Off Light including the optional cluster Occupancy Sensing. The binding is being formed with a ZED with occupancy sensing reportings, but I have no idea how to receive the attribute change on the ZC side.

    I see that the Occupancy Attribute is of type map8 where Bit 0 is the only one being used as the others are reserved. I looked at the thermostat example, but didn't quite get what BUILD_UINT16 in zclSampleThermostat_ProcessInReportCmd() does.

    • How do I process the reported attribute from inside my ZC sampleApp_ProcessInReportCmd()?
    • Can I give the sampleApp_OccupancySensing_Occupancy attribute a bool as input in my ZED?
  • If you can confirm that the ZED is sending occupancy sensing reports, and you've created and are actively entering your sampleApp_ProcessInReportRspCmd function, the some custom zclSampleApp_OccupancySensor variable should be set as pInOccupancySensorReport->attrList[0].attrData[0] since MAP8 is only 8 bits long.  This attribute type is defined by the Zigbee Cluster Library Specification so I would not recommend changing it.

    Regards,
    Ryan

  • Is there any other way to confirm that ZED is sending occupancy sensing reports other than checking on AF_DATA_CONFIRM_IND?

    From the AF_DATA_CONFIRM_IND I get a send status of 0, which is success. I have tried to use the packet sniffer, but have no way to interpret the capture as my trial period of Ubiqua is over.

    Below is the code for processing reports on my ZC. The sampleApp_UpdateLedState() just toggles a LED.

    /*********************************************************************
     * @fn      sampleApp_ProcessInReportCmd
     *
     * @brief   Process the "Profile" Report Command
     *
     * @param   pInMsg - incoming message to process
     *
     * @return  none
     */
    static void sampleApp_ProcessInReportCmd( zclIncoming_t *pInMsg )
    {
      zclReportCmd_t *pInOccupancyReport;
    
      pInOccupancyReport = (zclReportCmd_t *)pInMsg->attrCmd;
    
      if ( pInOccupancyReport->attrList[0].attrID != ATTRID_OCCUPANCY_SENSING_OCCUPANCY )
      {
        return;
      }
      // store the current occupancy state sent over the air from occupancy sensor
      sampleApp_remoteOccupancy = pInOccupancyReport->attrList[0].attrData[0];
      sampleApp_UpdateLedState();
    }

    Below is the code for sending a report on changed attribute:

        if(prevPresence != presence)
        {
    
            sampleApp_OccupancySensing_Occupancy = presence ? ((sampleApp_OccupancySensing_Occupancy & ~7) | 1) : ((sampleApp_OccupancySensing_Occupancy & ~7) | 0);
            Display_printf(display, 0, 0, "sampleApp_OccupancySensing_Occupancy value: %d", sampleApp_OccupancySensing_Occupancy);
    
            Req.attrID = ATTRID_OCCUPANCY_SENSING_OCCUPANCY;
            Req.cluster = ZCL_CLUSTER_ID_MS_OCCUPANCY_SENSING;
            Req.endpoint = SAMPLEAPP_ENDPOINT;
    
            Zstackapi_bdbRepChangedAttrValueReq(sampleApp_serviceTaskId,&Req);
    
            prevPresence = presence;
            Display_printf(display, 0, 0, "%s", presence ? "Presence: TRUE\n" : "Presence: FALSE\n");
        }

  • Also, in the thermostat example, one of the cluster attributes is:

      {
        ZCL_CLUSTER_ID_MS_TEMPERATURE_MEASUREMENT,
        {  // Attribute record
          ATTRID_CLUSTER_REVISION,
          ZCL_DATATYPE_UINT16,
          ACCESS_CONTROL_READ | ACCESS_CLIENT,
          (void *)&zclSampleThermostat_temperaturems_clusterRevision
        }
      }

    While in the ZC_SampleApp there is no mention regarding the Occupancy Sensing cluster except for the sampleApp_OutClusterList[]

    const zclAttrRec_t sampleApp_Attrs[] =
    {
    #ifdef ZCL_BASIC
    	{
    		ZCL_CLUSTER_ID_GENERAL_BASIC,
    			{
    				ATTRID_BASIC_ZCL_VERSION ,
    				ZCL_DATATYPE_UINT8,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Basic_ZCLVersion
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_BASIC,
    			{
    				ATTRID_BASIC_POWER_SOURCE ,
    				ZCL_DATATYPE_ENUM8,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Basic_PowerSource
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_BASIC,
    			{
    				ATTRID_CLUSTER_REVISION,
    				ZCL_DATATYPE_UINT16,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Basic_ClusterRevision
    			}
    	},
    #endif
    #ifdef ZCL_IDENTIFY
    	{
    		ZCL_CLUSTER_ID_GENERAL_IDENTIFY,
    			{
    				ATTRID_IDENTIFY_IDENTIFY_TIME ,
    				ZCL_DATATYPE_UINT16,
    				ACCESS_CONTROL_WRITE | ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Identify_IdentifyTime
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_IDENTIFY,
    			{
    				ATTRID_CLUSTER_REVISION,
    				ZCL_DATATYPE_UINT16,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Identify_ClusterRevision
    			}
    	},
    #endif
    #ifdef ZCL_GROUPS
    	{
    		ZCL_CLUSTER_ID_GENERAL_GROUPS,
    			{
    				ATTRID_GROUPS_NAME_SUPPORT ,
    				ZCL_DATATYPE_BITMAP8,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Groups_NameSupport
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_GROUPS,
    			{
    				ATTRID_CLUSTER_REVISION,
    				ZCL_DATATYPE_UINT16,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Groups_ClusterRevision
    			}
    	},
    #endif
    #ifdef ZCL_SCENES
    	{
    		ZCL_CLUSTER_ID_GENERAL_SCENES,
    			{
    				ATTRID_SCENES_SCENE_COUNT ,
    				ZCL_DATATYPE_UINT8,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Scenes_SceneCount
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_SCENES,
    			{
    				ATTRID_SCENES_CURRENT_SCENE ,
    				ZCL_DATATYPE_UINT8,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Scenes_CurrentScene
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_SCENES,
    			{
    				ATTRID_SCENES_CURRENT_GROUP ,
    				ZCL_DATATYPE_UINT16,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Scenes_CurrentGroup
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_SCENES,
    			{
    				ATTRID_SCENES_SCENE_VALID ,
    				ZCL_DATATYPE_BOOLEAN,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Scenes_SceneValid
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_SCENES,
    			{
    				ATTRID_SCENES_NAME_SUPPORT ,
    				ZCL_DATATYPE_BITMAP8,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Scenes_NameSupport
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_SCENES,
    			{
    				ATTRID_CLUSTER_REVISION,
    				ZCL_DATATYPE_UINT16,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_Scenes_ClusterRevision
    			}
    	},
    #endif
    #ifdef ZCL_ON_OFF
    	{
    		ZCL_CLUSTER_ID_GENERAL_ON_OFF,
    			{
    				ATTRID_ON_OFF_ON_OFF ,
    				ZCL_DATATYPE_BOOLEAN,
    				ACCESS_REPORTABLE | ACCESS_CONTROL_READ,
    				(void *)&sampleApp_OnOff_OnOff
    			}
    	},
    	{
    		ZCL_CLUSTER_ID_GENERAL_ON_OFF,
    			{
    				ATTRID_CLUSTER_REVISION,
    				ZCL_DATATYPE_UINT16,
    				ACCESS_CONTROL_READ,
    				(void *)&sampleApp_OnOff_ClusterRevision
    			}
    	},
    #endif
    #ifdef ZCL_MS   <<<<----- 
    #endif

  • I suggest you to setup packet sniffer 2 and wireshark to make sure occupancy cluster report is sent out.

  • Hello Yikai,

    Do you have any links or references on how to interpret the data from the packet sniffing?

    I have attached my file and see from the info line that the two are sending zigbee-related stuff when I activate the occupancy sensor.

    zed_sampleapp.zip

  • You need to do sniffer when a device joins Zibgee network from scratch so your sniffer log can get correct network key to decrypt data.

  • zed_sampleapp_trimmed.zip

    Thank you for the assistance, Yikai.

    I am able to read the information from the devices and can see that the occupancy cluster report is indeed sent out (frame number 216 and 253), but doesn't seem to be received correctly (frame number 222 and 257)?

    What am I missing on the ZC side?

  • The report is sent to endpoint 8. Does your coordinator support occupancy cluster on endpoint 8?

  • Where do I check if my coordinator supports occupancy cluster on endpoint 8?

    On my zc_sampleapp I have followed the ZHA device specification for an On/Off Light with the optional Occupation Sensing cluster on the client side. According to the specs I have added the mandatory and optional attributes through the sysconfig and written a report handler shared in a previous reply.

  • The endpoint is defined on the Advanced Settings of the SysConfig Zigbee Application Endpoint module.   ZCL_STATUS_UNSUP_GENERAL_COMMAND only occurs if zclCmdTable[inMsg.hdr.commandID].pfnParseInProfile is NULL so please make sure that you have Occupancy Sensing listed as Client Cluster and ZCL_REPORT_DESTINATION_DEVICE defined.

    Regards,
    Ryan

  • Occupancy Sensing is indeed listed as a Client Cluster in the Sysconfig and I have now defined ZCL_REPORT_DESTINATION_DEVICE and gotten Status: Success, thanks!

    occupancyWithSuccess.zip

    However, the ZCL_CMD_REPORT case isn't processed.

    Also, are you suggesting that Occupancy Sensing should be listed somewhere else other than what I've done in the SysConfig as shown below?

    Thanks

  • Please try to copy zcl_config.c from default/syscfg directly into your Application folder and disable zcl_config.c from being included in the build files generated by SysConfig, then add the following to sampleApp_Attrs:

    	{
    		ZCL_CLUSTER_ID_MS_OCCUPANCY_SENSING,
    			{
    				ATTRID_CLUSTER_REVISION,
    				ZCL_DATATYPE_UINT16,
    				ACCESS_CONTROL_READ | ACCESS_CLIENT,
    				(void *)&sampleApp_OccupancySensing_ClusterRevision
    			}
    	},

    If this does not improve behavior then please try further debugging zclProcessCmd -> zclParseInReportCmd/zcl_HandleExternal to help further identify the issue.

    Regards,
    Ryan

  • I would suggest you to set breakpoint in your xxx_processAfIncomingMsgInd and check if it triggers when occupancy report it sent.

  • Hey Ryan,

    This was exactly what I was pondering about and it solved my problem. Wouldn't it make sense to include these clusters into sampleApp_Attrs if the optional clusters are included through Sysconfig?

    Thanks Yikai and Ryan

  • Hey christng,

    I've identified this as a bug within the SampleApp example project's Zigbee Application Builder where cluster attributes (at the very least ATTRID_CLUSTER_REVISION) is not generated for Recommended Optional or Additional Client Clusters.  This could be due to missing client attribute entries in ZCL.js as I've noticed that it does work as expected when it comes to Server Clusters.  I have submitted a ticket with the Software Development Team so that this can be resolved in a future SDK release.

    Regards,
    Ryan