#define ZB_CURRENT_LEVEL_ATTRIBUTE_READONLY "0000"
#define ZB_ON_LEVEL_ATTRIBUTE "0011"
#define ZB_LEVEL_CONTROL_CLUSTER "0008"
-#define ZB_CONTACT_CLUSTER "0500"
-#define ZB_CONTACT_ATTRIBUTE_ID "0002"
+#define ZB_IAS_ZONE_CLUSTER "0500"
+#define ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID "0002"
#define ZB_INDICATOR_CLUSTER "0003"
#define ZB_INDICATOR_ATTRIBUTE_ID "0000"
#define ZB_ON_OFF_CLUSTER "0006"
#define ZB_ON_OFF_ATTRIBUTE_ID "0000"
+#define ZB_IAS_ZONE_TYPE_ATTRIBUTE_ID "0001"
+
+#define IAS_ZONE_TYPE_MOTION_SENSOR "000d"
+#define IAS_ZONE_TYPE_CONTACT_SENSOR "0015"
+#define IAS_ZONE_TYPE_WATER_SENSOR "002a"
#define ZB_DATA_TYPE_NULL "00"
#define ZB_DATA_TYPE_1_BYTE "08"
static const char* OIC_TEMPERATURE_SENSOR = "oic.r.temperature";
static const char* OIC_DIMMABLE_LIGHT = "oic.r.light.dimming";
static const char* OIC_CONTACT_SENSOR = "oic.r.sensor.contact";
+static const char* OIC_MOTION_SENSOR = "oic.r.sensor.motion";
+static const char* OIC_WATER_SENSOR = "oic.r.sensor.water";
static const char* OIC_BINARY_SWITCH = "oic.r.switch.binary";
static const char* OIC_TEMPERATURE_ATTRIBUTE = "temperature";
} ZigBeeAttributeDataType;
char * getZBDataTypeString(ZigBeeAttributeDataType attrType);
-OCEntityHandlerResult ProcessEHRequest (PIPluginBase * plugin, OCEntityHandlerRequest *ehRequest,
+OCEntityHandlerResult ProcessEHRequest(PIPluginBase * plugin, OCEntityHandlerRequest *ehRequest,
OCRepPayload **payload);
typedef enum
OICZigBeeAttributePair list[MAX_ATTRIBUTES];
} AttributeList;
-const char* ZigBeeClusterIDToOICResourceType (const char * clusterID);
+const char* ZigBeeClusterIDToOICResourceType(const char * clusterID);
-OCStackResult getZigBeeAttributesForOICResource (char * OICResourceType,
+OCStackResult getZigBeeAttributesForOICResource(const char * OICResourceType,
AttributeList *attributeList);
-bool getZigBeeAttributesIfValid (char * OICResourceType,
+bool getZigBeeAttributesIfValid(const char * OICResourceType,
AttributeList *attributeList,
OCRepPayload *payload);
+const char * getResourceTypeForIASZoneType(TWDevice *device)
+{
+ if(!device)
+ {
+ return NULL;
+ }
+ char *IASZoneType = NULL;
+ const char *resourceType = NULL;
+ uint8_t length = 0;
+
+ OCStackResult ret = TWGetAttribute(
+ NULL,
+ device->nodeId,
+ device->endpointOfInterest->endpointId,
+ ZB_IAS_ZONE_CLUSTER,
+ ZB_IAS_ZONE_TYPE_ATTRIBUTE_ID,
+ &IASZoneType,
+ &length
+ );
+
+ if (ret != OC_STACK_OK || !IASZoneType)
+ {
+ OC_LOG_V (ERROR, TAG, "Error %u getting IAS Zone Type", ret);
+ return NULL;
+ }
+
+ if (strcmp (IASZoneType, IAS_ZONE_TYPE_CONTACT_SENSOR) == 0)
+ {
+ resourceType = OIC_CONTACT_SENSOR;
+ }
+ else if (strcmp (IASZoneType, IAS_ZONE_TYPE_MOTION_SENSOR) == 0)
+ {
+ resourceType = OIC_MOTION_SENSOR;
+ }
+ else if (strcmp (IASZoneType, IAS_ZONE_TYPE_WATER_SENSOR) == 0)
+ {
+ resourceType = OIC_WATER_SENSOR;
+ }
+ else
+ {
+ OC_LOG_V (ERROR, TAG, "Unsupported Zone Type %s", IASZoneType);
+ resourceType = NULL;
+ }
+
+ OICFree(IASZoneType);
+
+ return resourceType;
+}
+
+OCStackResult buildURI(char ** output,
+ const char * prefix,
+ const char * nodeId,
+ const char * endpointId,
+ const char * clusterId)
+{
+ if(!output || !prefix || !nodeId || !endpointId || !clusterId)
+ {
+ return OC_STACK_INVALID_PARAM;
+ }
+ const char LEN_SEPARATOR[] = "/";
+ size_t lenSeparatorSize = sizeof(LEN_SEPARATOR) - 1;
+ size_t newUriSize = strlen(prefix) + lenSeparatorSize +
+ strlen(nodeId) + lenSeparatorSize +
+ strlen(endpointId) + lenSeparatorSize +
+ strlen(clusterId)
+ + 1; // NULL Terminator
+ *output = (char *) OICCalloc(1, newUriSize);
+
+ if (!*output)
+ {
+ OC_LOG (ERROR, TAG, "Out of memory");
+ return OC_STACK_NO_MEMORY;
+ }
+
+ char * temp = OICStrcpy(*output, newUriSize, prefix);
+ if(temp != *output)
+ {
+ goto exit;
+ }
+ temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
+ if(temp != *output)
+ {
+ goto exit;
+ }
+ temp = OICStrcat(*output, newUriSize, nodeId);
+ if(temp != *output)
+ {
+ goto exit;
+ }
+ temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
+ if(temp != *output)
+ {
+ goto exit;
+ }
+ temp = OICStrcat(*output, newUriSize, endpointId);
+ if(temp != *output)
+ {
+ goto exit;
+ }
+ temp = OICStrcat(*output, newUriSize, LEN_SEPARATOR);
+ if(temp != *output)
+ {
+ goto exit;
+ }
+ temp = OICStrcat(*output, newUriSize, clusterId);
+ if(temp != *output)
+ {
+ goto exit;
+ }
+
+ return OC_STACK_OK;
+
+exit:
+ OICFree(*output);
+ *output = NULL;
+ return OC_STACK_NO_MEMORY;
+}
+
void foundZigbeeCallback(TWDevice *device)
{
+ if(!device)
+ {
+ OC_LOG(ERROR, TAG, "foundZigbeeCallback: Invalid parameter.");
+ return;
+ }
int count = device->endpointOfInterest->clusterList->count;
- size_t lenSeparator = strlen ("/");
- int ret = 0;
for(int i=0; i < count; i++)
{
PIResource_Zigbee *piResource = (PIResource_Zigbee *) OICMalloc(sizeof(*piResource));
return;
}
piResource->header.plugin = (PIPluginBase *)gPlugin;
- size_t newUriSize = strlen(PI_ZIGBEE_PREFIX) + lenSeparator +
- sizeof(device->nodeId) + lenSeparator +
- sizeof(device->endpointOfInterest->endpointId) + lenSeparator +
- sizeof(device->endpointOfInterest->clusterList->clusterIds[i].clusterId)
- + 1; // NULL Terminator
- char * newUri = (char *) OICCalloc(newUriSize, 1);
- if (!newUri)
+ OCStackResult result = buildURI(&piResource->header.piResource.uri,
+ PI_ZIGBEE_PREFIX,
+ device->nodeId,
+ device->endpointOfInterest->endpointId,
+ device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
+
+ if(result != OC_STACK_OK)
{
- OC_LOG (ERROR, TAG, "Out of memory");
+ OICFree(piResource);
return;
}
- ret = snprintf(newUri, newUriSize, "%s/%s/%s/%s",
- PI_ZIGBEE_PREFIX,
- device->nodeId,
- device->endpointOfInterest->endpointId,
- device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
- if(ret < 0)
+ char * foundClusterID =
+ device->endpointOfInterest->clusterList->clusterIds[i].clusterId;
+
+ if (strcmp (foundClusterID, ZB_IAS_ZONE_CLUSTER) == 0)
{
- OC_LOG (ERROR, TAG, "Encoding error occurred trying to build Zigbee URI.");
+ piResource->header.piResource.resourceTypeName
+ = getResourceTypeForIASZoneType (device);
+
+ OCStackResult ret = TWListenForStatusUpdates (device->nodeId,
+ device->endpointOfInterest->endpointId);
+
+ if (ret != OC_STACK_OK)
+ {
+ // Just log it and move on if this fails?
+ // or not create this resource at all?
+ OC_LOG (ERROR, TAG, "Command to listen for status updates failed");
+ }
}
- else if(ret > newUriSize)
+ else
{
- OC_LOG_V (ERROR, TAG, "Did not allocate enough memory to build URI. Required Size: %d",
- ret);
+ piResource->header.piResource.resourceTypeName =
+ (char *) ZigBeeClusterIDToOICResourceType(foundClusterID);
}
- piResource->header.piResource.uri = newUri;
- piResource->header.piResource.resourceTypeName =
-
- (char *) ZigBeeClusterIDToOICResourceType(
- device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
-
if(piResource->header.piResource.resourceTypeName == NULL)
{
- OC_LOG_V (ERROR, TAG, "unsupported clusterId : %d",
+ OC_LOG_V (ERROR, TAG, "unsupported clusterId : %s",
device->endpointOfInterest->clusterList->clusterIds[i].clusterId);
OICFree(piResource->header.piResource.uri);
OICFree(piResource);
}
}
+void zigbeeZoneStatusUpdate(TWUpdate * update)
+{
+ if(!update)
+ {
+ return;
+ }
+
+ char * uri = NULL;
+ OCStackResult result = buildURI(&uri,
+ PI_ZIGBEE_PREFIX,
+ update->nodeId,
+ update->endpoint,
+ ZB_IAS_ZONE_CLUSTER);
+ if(result != OC_STACK_OK || !uri)
+ {
+ OC_LOG_V(ERROR, TAG, "Failed to build URI with result: %d", result);
+ return;
+ }
+
+ (*gPlugin)->header.ObserveNotificationUpdate((PIPluginBase *)*gPlugin, uri);
+ OICFree(uri);
+}
+
OCStackResult ZigbeeInit(const char * comPort, PIPlugin_Zigbee ** plugin,
- PINewResourceFound newResourceCB)
+ PINewResourceFound newResourceCB,
+ PIObserveNotificationUpdate observeNotificationUpdate)
{
if(!plugin)
{
return OC_STACK_NO_MEMORY;
}
((*plugin)->header).type = PLUGIN_ZIGBEE;
- ((*plugin)->header).comPort = OICStrdup(comPort);
+ ((*plugin)->header).comPort = comPort;
((*plugin)->header).NewResourceFoundCB = newResourceCB;
+ ((*plugin)->header).ObserveNotificationUpdate = observeNotificationUpdate;
((*plugin)->header).next = NULL;
((*plugin)->header).resourceList = NULL;
((*plugin)->header).processEHRequest = ProcessEHRequest;
gPlugin = plugin;
- return TWInitialize(comPort);
+ OCStackResult result = TWInitialize(comPort);
+ if(result != OC_STACK_OK)
+ {
+ return result;
+ }
+
+ return TWSetStatusUpdateCallback(zigbeeZoneStatusUpdate);
}
OCStackResult ZigbeeDiscover(PIPlugin_Zigbee * plugin)
OCStackResult ZigbeeStop(PIPlugin_Zigbee * plugin)
{
- free((plugin->header).comPort);
free(plugin);
return TWUninitialize();
}
// from the cluster ID. If the cluster is not supported, null is
// returned.
// NOTE: The returned string is NOT malloc'ed.
-const char* ZigBeeClusterIDToOICResourceType (const char * clusterID) //Discovery/CreateResource
+const char* ZigBeeClusterIDToOICResourceType(const char * clusterID) //Discovery/CreateResource
{
if (strcmp(clusterID, ZB_TEMPERATURE_CLUSTER) == 0)
{
{
return OIC_DIMMABLE_LIGHT;
}
- else if (strcmp(clusterID, ZB_CONTACT_CLUSTER) == 0)
+ else if (strcmp(clusterID, ZB_IAS_ZONE_CLUSTER) == 0)
{
return OIC_CONTACT_SENSOR;
}
}
}
-const char* OICResourceToZigBeeClusterID (char *oicResourceType)
+const char* OICResourceToZigBeeClusterID(char *oicResourceType)
{
if (strcmp(oicResourceType, OIC_TEMPERATURE_SENSOR) == 0)
{
}
else if (strcmp(oicResourceType, OIC_CONTACT_SENSOR) == 0)
{
- return ZB_CONTACT_CLUSTER;
+ return ZB_IAS_ZONE_CLUSTER;
}
else if (strcmp(oicResourceType, OIC_BINARY_SWITCH) == 0)
{
}
}
-OCStackResult getZigBeeAttributesForOICResource (char * OICResourceType,
+OCStackResult getZigBeeAttributesForOICResource(const char * OICResourceType,
AttributeList *attributeList) // GET
{
if (strcmp (OICResourceType, OIC_TEMPERATURE_SENSOR) == 0)
{
attributeList->count = 1;
attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
- attributeList->list[0].zigBeeAttribute = ZB_CONTACT_ATTRIBUTE_ID;
+ attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
attributeList->list[0].oicType = OIC_ATTR_BOOL;
attributeList->list[0].zigbeeType = ZB_BOOL;
return OC_STACK_OK;
return OC_STACK_ERROR;
}
-bool getZigBeeAttributesIfValid (char * OICResourceType,
+bool getZigBeeAttributesIfValid(const char * OICResourceType,
AttributeList *attributeList,
OCRepPayload *payload) // Put
{
{
attributeList->count = 1;
attributeList->list[0].oicAttribute = OICStrdup(OIC_CONTACT_ATTRIBUTE);
- attributeList->list[0].zigBeeAttribute = ZB_CONTACT_ATTRIBUTE_ID;
+ attributeList->list[0].zigBeeAttribute = ZB_IAS_ZONE_STATUS_ATTRIBUTE_ID;
attributeList->list[0].oicType = OIC_ATTR_BOOL;
attributeList->list[0].val.i = value;
attributeList->list[0].zigbeeType = ZB_BOOL;
return stackResult;
}
-OCEntityHandlerResult processPutRequest (PIPluginBase * plugin,
+OCEntityHandlerResult processPutRequest(PIPluginBase * plugin,
OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
{
if (!plugin || !ehRequest || !payload)
return processGetRequest(plugin, ehRequest, payload);
}
-OCEntityHandlerResult ProcessEHRequest (PIPluginBase * plugin,
+OCEntityHandlerResult ProcessEHRequest(PIPluginBase * plugin,
OCEntityHandlerRequest *ehRequest, OCRepPayload **payload)
{
if(!ehRequest || !payload)