Bitcloud data exchange using ZCL

Go To Last Post
18 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, since I finally succeed to send data using the APS component. I'm trying now to send data through the ZCL layer of Bitcloud, in order to respect the Zigbee HA standard. But I have to admit that it is much harder.

The aim of my program is to simply send a temperature to my coordinator.

So in order to get this work, i have used the ZCL section of the Bitcloud API reference and the Bitcloud Profile suite developer guide.

First I have configured the cluster and the endpoint but I'm not sure what i have to do with the ZCL_DEFINE_TEMPERATURE_MEASUREMENT_CLUSTER_SERVER macro's argument (TempIdClusterServeurAttributes)


ZCL_Cluster_t TempServerCluster[DS_SERVER_CLUSTERS_COUNT]=
{
	ZCL_DEFINE_TEMPERATURE_MEASUREMENT_CLUSTER_SERVER(&TempIdClusterServeurAttributes)
};

ClusterId_t TempServerClusterIds[DS_SERVER_CLUSTERS_COUNT]=
{
	TEMPERATURE_MEASUREMENT_CLUSTER_ID
};

static ZCL_DeviceEndpoint_t TempEndpoint =
{
	.simpleDescriptor =
	{
		.endpoint            = APP_SRC_ENDPOINT_ID,
		.AppProfileId        = PROFILE_ID_HOME_AUTOMATION,
		.AppDeviceId         = HA_COMBINED_INTERFACE_ID,
		.AppInClustersCount  = 0,
		.AppInClustersList   = 0,
		.AppOutClustersCount = ARRAY_SIZE(TempServerClusterIds),
		.AppOutClustersList  =TempServerClusterIds,
	},
	.serverCluster = 0,
	.clientCluster = TempServerCluster,
};


void configurTempEndpoint(void)
{
	appEndpoint.simpleDescriptor.endpoint = APP_SRC_ENDPOINT_ID;
	appEndpoint.simpleDescriptor.AppProfileId = PROFILE_ID_HOME_AUTOMATION;
	appEndpoint.simpleDescriptor.AppDeviceId=HA_DIMMER_SWITCH_DEVICE_ID;
	appEndpoint.simpleDescriptor.AppInClustersCount = 0;
	appEndpoint.simpleDescriptor.AppInClustersList =0;
	appEndpoint.simpleDescriptor.AppOutClustersCount = ARRAY_SIZE(TempServerClusterIds);
	appEndpoint.simpleDescriptor.AppOutClustersList = TempServerClusterIds;
	appEndpoint.serverCluster= NULL;
	appEndpoint.clientCluster = TempServerCluster;
	
};


Then in my appDeviceTaskHandler I configured and tried to sent a request to write a test value(16) in the temperature attribute

 typedef struct PACK
  {
	  ZCL_AttributeId_t id;
	  uint8_t type;
	  uint8_t value;
  } APP_Write8BitAttributeReq_t;

void appDeviceTaskHandler(void)
{
	
	switch (appDeviceState)
	{
		case DEVICE_INITIAL_STATE :
		{
			appSnprintf("appinit\n\r");
			
			ZCL_Notify_t notify;
			
			
			
			configurTempEndpoint();
			ZCL_RegisterEndpoint(&appEndpoint);
			req.id=ZCL_WRITE_ATTRIBUTES_COMMAND_ID;
		
			ZCL_AttributeReq(&req);
		
		
			ZCL_NextElement_t element;
			APP_Write8BitAttributeReq_t writeAttrReqElement;
		
			uint8_t* buffer[128];
		
		
	
		
			element.payloadLength = buffer;
			element.id = ZCL_WRITE_ATTRIBUTES_COMMAND_ID;
			element.content = &writeAttrReqElement;
		
			writeAttrReqElement.id = ZCL_TEMPERATURE_MEASUREMENT_CLUSTER_SERVER_MEASURED_VALUE_ATTRIBUTE_ID;
			writeAttrReqElement.type = ZCL_8BIT_DATA_TYPE_ID;
			writeAttrReqElement.value = 16;
		
			ZCL_PutNextElement(&element);
		
		
	
		
			req.id=ZCL_WRITE_ATTRIBUTES_COMMAND_ID;
			req.defaultResponse=NULL;
			req.responseWaitTimeout=0;
			req.dstAddressing.addrMode=APS_SHORT_ADDRESS;
			req.dstAddressing.addr.shortAddress=0x0000;
			req.endpointId=APP_SRC_ENDPOINT_ID;
			req.dstAddressing.clusterId=CCPU_TO_LE16(0x0402);
			req.dstAddressing.profileId=PROFILE_ID_HOME_AUTOMATION;
			req.dstAddressing.clusterSide=ZCL_CLUSTER_SIDE_SERVER;
			req.requestLength=element.payloadLength;
			req.requestPayload=buffer;
			req.defaultResponse=ZCL_FRAME_CONTROL_ENABLE_DEFAULT_RESPONSE;
		
			ZCL_AttributeReq(&req);
		
		}
	break;
	}
	
	
}

But no packets are going out of the transceiver. The program seems to be block because I only see one time the "appinit" which I send at the first line the appDeviceTaskHandler.

What am I doing wrong? What am I missing?
Is anyone have a clear example of How to write one attribute with the ZCL layer?

Also
Is it possible to create a new device with Bitlcoud? How to proceed? Because i'm actually writting my code in the dimmerSwitch files.

Thank you for your time

Quentin

Last Edited: Fri. Oct 16, 2015 - 01:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First of all, you don't send updates from the device, server reads them. You can also setup automatic periodic reporting.

Then, why you call "ZCL_AttributeReq()" two times in the same function with the same parameter?

You also defining the server side of the cluster, and device will likely to be a client.

ZCL is way way more complicated. You better start with stock applications.

Do you have a target device you want to work with?

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Then, why you call "ZCL_AttributeReq()" two times in the same function with the same parameter?

My mistake , I have read so many things on developer guide and the internet.

Quote:
Do you have a target device you want to work with?

Yes I'working with a coordinator which is a prototype that another company sent me. I don't have the source code of the coordinator yet so I can't edit the program.

This a screen of my end device and the coordinator communicating together. The coordinator seems to work pretty well.I made the Temperature measurement frame myself with the buffer right after I wrote this topic.

So if I understand correctly , I have to write a local attribute on my end device and the server have to read it.
Do I need to send a request to my coordinator to warn it that he must read the attribute on the end device? Or do I need to edit the code of my coordinator to read the attribute on the end device?

Or I could set up attribute reporting.

What is the easiest solution?

Do you have a clear and complete example that showing a complete implementation of the ZCL Layer?

Thank you for your time

Quentin

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

QuentinBBP wrote:
This a screen of my end device and the coordinator communicating together. The coordinator seems to work pretty well.
Well, you've sent a frame that could be parsed by the sniffer. A are you sure this frame was actually interpreted by the coordinator? What sort of reaction do you expect on the other end.

In HA behavior of the system is defined by the coordinator/central device. Other devices in the network must follow along. Usually, if coordinator wants to get your temperature it will read it on his own. Or configure reporting remotely.

QuentinBBP wrote:
So if I understand correctly , I have to write a local attribute on my end device and the server have to read it.

QuentinBBP wrote:
Do I need to send a request to my coordinator to warn it that he must read the attribute on the end device?
No, there is no such request.

QuentinBBP wrote:
Or do I need to edit the code of my coordinator to read the attribute on the end device?
If you have access to the code and that's your target application, then yes.

QuentinBBP wrote:
Or I could set up attribute reporting.
You can do that, but coordinator must be able to receive and process those reports in a meaningful way.

QuentinBBP wrote:
Do you have a clear and complete example that showing a complete implementation of the ZCL Layer?
ZCL layer is part of the stack and it is as small as it gets. What you are writing is an application on top of ZCL layer. And although hard to understand, standard application is a good starting point.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you for you quick answer. You are saving me a lot of time.

I have a couple of other question:

What are you meaning by standard application? Do you have a complete example of attribute reporting? Is it possible to configure attribute reporting without using ZCL function?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I mean HADevice from the SDK. HADevice does much more than simple reporting.

"Reporting" and "attributes" are part of ZCL, so it meaningless to talk about them outside of the context of ZCL.

But ZCL commands are specially formatted standard ZigBee frames, so you can format your request accordingly. But that is not recommended because ZCL does a lot of other things in the background.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes I started with the HADevice but I didn't understand very well at first. But now that I take a second look at it, it make more sense to me. I think programmed my own function helped me to understood.

So if I take the occupancy sensor of the combined interface as an example.

Where do I need to put my data and in which order to I need to call the function in my AppTaskhandler?

1-occupancySensingClusterInit();
2-occupancySensingConfigureReporting();
3-ciOccupancySensorReportInd();
4-ZCL_startreporting();

/**************************************************************************//**
\file ciOccupancySensingCluster.c

\brief
Combined Interface Occupancy Sensing cluster implementation.

\author
Atmel Corporation: http://www.atmel.com \n
Support email: avr@atmel.com

Copyright (c) 2008-2013, Atmel Corporation. All rights reserved.
Licensed under Atmel's Limited License Agreement (BitCloudTM).

\internal
History:
13.09.13 N. Fomin - Created.
******************************************************************************/
#ifdef APP_DEVICE_TYPE_COMBINED_INTERFACE

/******************************************************************************
Includes section
******************************************************************************/
#include <ciOccupancySensingCluster.h>
#include <uartManager.h>
#include <commandManager.h>
#include <haClusters.h>

#include <zclOnOffCluster.h>
#include <zclLevelControlCluster.h>

/******************************************************************************
Prototypes section
******************************************************************************/
static void ciOccupancySensorReportInd(ZCL_Addressing_t *addressing, uint8_t reportLength, uint8_t *reportPayload);
static void ZCL_ConfigureReportingResp(ZCL_Notify_t *ntfy);

/******************************************************************************
Implementation section
******************************************************************************/
/**************************************************************************//**
\brief Initializes OccupancySensing cluster
******************************************************************************/
void occupancySensingClusterInit(void)
{
ZCL_Cluster_t *cluster = ZCL_GetCluster(APP_SRC_ENDPOINT_ID, OCCUPANCY_SENSING_CLUSTER_ID, ZCL_CLUSTER_SIDE_CLIENT);

if (cluster)
cluster->ZCL_ReportInd = ciOccupancySensorReportInd;
}

/**************************************************************************//**
\brief Initializes Occupancy Sensing cluster

\param[in] mode - address mode;
\param[in] addr - short address of destination node;
\param[in] ep - destination endpoint;
\param[in] min - the minimum reporting interval;
\param[in] max - the maximum reporting interval
******************************************************************************/
void occupancySensingConfigureReporting(APS_AddrMode_t mode, ShortAddr_t addr, Endpoint_t ep,
ZCL_ReportTime_t min, ZCL_ReportTime_t max)
{
ZCL_Request_t *req;
ZCL_NextElement_t element;
ZCL_ConfigureReportingReq_t configureReportingReq;

if (!(req = getFreeCommand()))
return;

configureReportingReq.direction = ZCL_FRAME_CONTROL_DIRECTION_CLIENT_TO_SERVER;
configureReportingReq.attributeId = ZCL_OCCUPANCY_SENSING_CLUSTER_OCCUPANCY_SERVER_ATTRIBUTE_ID;
configureReportingReq.attributeType = ZCL_8BIT_BITMAP_DATA_TYPE_ID;
configureReportingReq.minReportingInterval = min;
configureReportingReq.maxReportingInterval = max;

element.payloadLength = 0;
element.payload = req->requestPayload;
element.id = ZCL_CONFIGURE_REPORTING_COMMAND_ID;
element.content = &configureReportingReq;
ZCL_PutNextElement(&element);

fillCommandRequest(req, ZCL_CONFIGURE_REPORTING_COMMAND_ID, element.payloadLength);
fillDstAddressing(&req->dstAddressing, mode, addr, ep, OCCUPANCY_SENSING_CLUSTER_ID);
req->ZCL_Notify = ZCL_ConfigureReportingResp;

commandManagerSendAttribute(req);
}

/**************************************************************************//**
\brief Report attribute indication handler

\param[in] addressing - pointer to addressing information;
\param[in] reportLength - data payload length;
\param[in] reportPayload - data pointer
******************************************************************************/
static void ciOccupancySensorReportInd(ZCL_Addressing_t *addressing, uint8_t reportLength, uint8_t *reportPayload)
{
ZCL_Report_t *rep = (ZCL_Report_t *)reportPayload;

LOG_STRING(reportAttrIndStr, "<-Occupancy Sensor Attr Report: t = % d\r\n");
appSnprintf(reportAttrIndStr, (int)rep->value[0]);

(void)addressing, (void)reportLength, (void)rep;
}

/**************************************************************************//**
\brief Indication of configure reporting response

\param[in] resp - pointer to response
******************************************************************************/
static void ZCL_ConfigureReportingResp(ZCL_Notify_t *ntfy)
{
(void)ntfy;
}

#endif // APP_DEVICE_TYPE_COMBINED_INTERFACE

// eof ciOccupancySensingCluster.c

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So I followed the occupancy sensor example to make my own application. The "Configure Reporting" packet is going out well. Then I have 0xc3 ZCL Response and 0xad ZCL confirm which is a security fail status. So I changed my short address to a Broadcast one but the 0xAD status remain.


ZCL_DeviceEndpoint_t appEndpoint;

------------------------cluster--------------------------

ZCL_Cluster_t TempClientCluster[DS_SERVER_CLUSTERS_COUNT]=
{
ZCL_DEFINE_TEMPERATURE_MEASUREMENT_CLUSTER_SERVER(&TempIdClusterClientAttributes)
};

ClusterId_t TempClientClusterIds[DS_SERVER_CLUSTERS_COUNT]=
{
TEMPERATURE_MEASUREMENT_CLUSTER_ID
};
void temperature_clusterinit()
{
ZCL_Cluster_t *cluster = ZCL_GetCluster(APP_SRC_ENDPOINT_ID,TEMPERATURE_MEASUREMENT_CLUSTER_ID,ZCL_CLUSTER_SIDE_CLIENT);

if(cluster)
cluster->ZCL_ReportInd = temperature_ReportInd;

}

------------------------End point--------------------------

void configurTempEndpoint(void)
{
appEndpoint.simpleDescriptor.endpoint = APP_SRC_ENDPOINT_ID;
appEndpoint.simpleDescriptor.AppProfileId = PROFILE_ID_HOME_AUTOMATION;
appEndpoint.simpleDescriptor.AppDeviceId=HA_DIMMER_SWITCH_DEVICE_ID;
appEndpoint.simpleDescriptor.AppInClustersCount = 0;
appEndpoint.simpleDescriptor.AppInClustersList =0;
appEndpoint.simpleDescriptor.AppOutClustersCount = ARRAY_SIZE(TempClientClusterIds);
appEndpoint.simpleDescriptor.AppOutClustersList = TempClientClusterIds;
appEndpoint.serverCluster= NULL;
appEndpoint.clientCluster = TempClientCluster;

}

-------------------------Reporting function--------------------

void temperature_send(APS_AddrMode_t mode, ShortAddr_t addr, Endpoint_t ep,ZCL_ReportTime_t min,ZCL_ReportTime_t max, int16_t reportchange, ZCL_ReportTime_t timeo)
{

ZCL_Request_t *req;
ZCL_NextElement_t element;
ZCL_ConfigureReportingReq_t configureReportingReq;
ZCL_TemperatureMeasurementClusterAttributes_t temperature;

if (!(req = getFreeCommand()))
{
return;
}

configureReportingReq.direction = ZCL_FRAME_CONTROL_DIRECTION_CLIENT_TO_SERVER;
configureReportingReq.attributeId = ZCL_TEMPERATURE_MEASUREMENT_CLUSTER_SERVER_MEASURED_VALUE_ATTRIBUTE_ID;
configureReportingReq.attributeType = ZCL_8BIT_BITMAP_DATA_TYPE_ID;
configureReportingReq.minReportingInterval = min;
configureReportingReq.maxReportingInterval = max;

element.payloadLength = 0;
element.payload = req->requestPayload;
element.id = ZCL_CONFIGURE_REPORTING_COMMAND_ID;
element.content = &configureReportingReq;
ZCL_PutNextElement(&element);

fillCommandRequest(req, ZCL_CONFIGURE_REPORTING_COMMAND_ID,element.payloadLength);
fillDstAddressing(&req->dstAddressing, mode, addr, ep, TEMPERATURE_MEASUREMENT_CLUSTER_ID);
req->ZCL_Notify = ZCL_ConfigureReportingResp;

commandManagerSendAttribute(req);

}

static void ZCL_ConfigureReportingResp(ZCL_Notify_t *ntfy)
{
(void)ntfy;
}

static void temperature_ReportInd(ZCL_Addressing_t *addressing, uint8_t reportLength, uint8_t *reportPayload)
{
ZCL_Report_t *rep = (ZCL_Report_t *)reportPayload;

LOG_STRING(reportAttrIndStr, "<-température: t = % d\r\n");
appSnprintf(reportAttrIndStr, (int)rep->value[0]);

(void)addressing, (void)reportLength, (void)rep;
}

----------------------------Apptaskhandler---------------------------------

void appDeviceTaskHandler(void)
{

switch (appDeviceState)
{
case DEVICE_INITIAL_STATE :
{
appSnprintf("appinit\n\r");
configurTempEndpoint();
ZCL_RegisterEndpoint(&appEndpoint);
temperature_clusterinit();

appDeviceState = DEVICE_ACTIVE_IDLE_STATE;
}
break;

case DEVICE_ACTIVE_IDLE_STATE:
{

};break;
}
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ewrtrtertert

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Configure reporting should be send by the coordinator, not your device.

Are you sure that existing coordinator can receive this temperature data and knows what to do with it?

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't have access to the program of the coordinator. So I don't think the coordinator know what to do with it. But I have bought some end devices in order to study them. These end device are able to report attribute every X second and I don't have to modify anything to my coordinator to makes these end device start reporting their attribute. That's what I want to do .

Is it possible with the standard application?

http://www.nhr.com.tw/product-1....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

QuentinBBPBis wrote:
I don't have access to the program of the coordinator. So I don't think the coordinator know what to do with it.
Then it is useless to send it anything. To begin with, send Match Descriptor Request to the coordinator and see if it even implements server side of the temperature measurement cluster. Otherwise it will just ignore your commands.

QuentinBBPBis wrote:
These end device are able to report attribute every X second and I don't have to modify anything to my coordinator to makes these end device start reporting their attribute.
You need to look at what exactly they are sending.

QuentinBBPBis wrote:
Is it possible with the standard application?
Most likely, yes, if you would know what to send.

Universality, portability and interoperability of HA (and ZigBee ZCL in general) is a myth. Unless devices are designed to work with each other, chances are that they won't.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Also, quote from your link

Quote:
Compliant with ZigBee HA profile Digital Output.

Why do you think that you need to sent temperature measurement commands? I don't have ZCL spec handy, but I'd check if there is Digital Output cluster there.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You need to look at what exactly they are sending.

They are sending reporting attribute packet. You can see the details of the packet in the two picture below.

I want to make a temperature sensor end device which works like the two pictures above. The coordinator's program will be complete in the futur.
The first part of the project consist of evaluating the consommation of the device in order to make it works with solar panel. So right now I don't care if my coordinator doesn't understand anything of what I'm sending to it. I just want to make a first program that is able to send the temperature and sleep to save energy.

So is it possible with standard application to make report attribute packet without sending a configure reporting attribute request from my coordinator?

Tank you again for you interest, this is very helpful.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, so that's a real HA device. Sorry, I don't have much time right now to test this myself. You should have a look at ZCL_DEFINE_TEMPERATURE_MEASUREMENT_CLUSTER_SERVER_ATTRIBUTES(reportMin, reportMax). reportMin and reportMax define reporting intervals.

For example, see dlOnOffCluster.c.

In theory, if you define your server attributed like that, they will be automatically reported.

Another alternative, if you don't care about full-blown HA implementation and certification, just create a regular APS frame with the same payload and specify the same Cluster Id and Profile Id.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So today I have tried to follow the dlOnOffCluster.c example and I can see Identify query packet going out of my device.Then I tried to run the OccupancySensors application and I can see Identify query packet going out again.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, I can't really help with broad questions. I only know one way of dealing with ZCL - try to find examples and dig through the code. So you will have to experiment yourself. Thankfully, ZCL code is not that big and it is open.

ZCL is way to complex to remember what goes where.

NOTE: I no longer actively read this forum. Please ask your question on www.eevblog.com/forum if you want my answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is there a full working version of your program? I would like to see it since im working on something similar at the moment.