WISE-Agent Sample Handler

From ESS-WIKI
Jump to: navigation, search

In WISE Agent, we implement several Software Modules to access sensor data or control target device, we called Plugins (or Handlers we called before).

Each plugin is designed to handle specific jobs, such as:

  • Sensor Plugin: the plugin access sensor data through Sensor driver or 3rd party library, or
  • Remote Control Plugin:  the plugin execute remote command on target device.

To support customized plugins, we also defined a set of APIs, called Plugin (Handler) APIs. 

User can implement their own Handler with these Plugin (Handler) APIs to access their sensor data or control their devices and plugged by WISE Agent to communicate with RMM Server.

Architecture

RTENOTITLE

In Plugin (Handler) Architecture, the Plugin (Handler) APIs is the skin of Plugin. Developer need to implement the APIs defined in the Plugin APIs, then the WISE Agent Handler loader will link the pre-defined APIs dynamically.

The Handler Kernel Library is the bone of the Plugin. This library will handle most of the functions in a Plugin, Such as: Gat Capability, Auto Report Start/Stop, Get/Set Sensor Data and basic Threshold Rule support.

The Message Structure is the main structure to describe the sensor data and interact between Handler Kernel and Custom Data Access. In Handler Kernel, the library will generate the handshake message based on the Message Structure.

The Message Generator library provides several APIs to describe the custom sensor data in a Message Structure.

In the Custom Data Access block, user needs to implement the function to access data from 3rd party library or drivers in platform. And update the sensor data in Message Structure to report those data to the RMM Server through Handler Kernel.

Developer only need to concerned about how to get the sensor data and generate theMessage Structure by Message Generator in Custom Data Access block.

Plugin (Handler) APIs

List

int Handler_Initialize( HANDLER_INFO *handler );
Description
  • This function initializes any objects or variables of this handler

Parameters

  • handler [POINTER]
    • the structure to exchange the handler information between WISE Agent and Handler.

Return Values

  • [-1|0] Error or Success.


int Handler_Get_Status( HANDLER_THREAD_STATUS * pOutStatus );
Description
  • This function will retrieve Handler Threads Status. Agent will restart current Handler or restart Agent self if busy.

Parameters

  • pOutStatus [POINTER]
    • the return status of handerl, the enumerate: 
      • handler_status_no_init = -1,
      • handler_status_init,
      • handler_status_start, 
      • handler_status_stop, 
      • handler_status_busy

Return Values

  • [-1|0] Error or Success.


void Handler_OnStatusChange( HANDLER_INFO *handler );
Description
  • This function will be called while CAgent connection status updated.

Parameters

  • handler [POINTER]
    • the pointer of Handler Info structure.

Return Values

  • None.


int Handler_Start( void );
Description
  • Start handler thread.

Parameters

  • None.

Return Values

  • [-1|0] Error or Success.


int Handler_Stop( void );
Description
  • Stop handler thread.

Parameters

  • None.

Return Values

  • [-1|0] Error or Success.


void Handler_Recv( char * const topic, void* const data, const size_t datalen, void *pRev1, void* pRev2  );
Description
  • Received Packet from Server.

Parameters

  • topic[POINTER]
    • MQTT topic string
  • data[POINTER]
    • pointer of received payload.
  • datalen[NUMBER]
    • received payload size
  • pRev1[POINTER]
    • preserved pointer.
  • pRev2[POINTER]
    • preserved pointer.

Return Values

  • None.


int Handler_Get_Capability( char ** pOutReply );
Description
  • Get Handler Information specification. 
  • Release allocated mamory by calling Handler_MemoryFree.

Parameters

  • pOutReply [POINTER]
    • double-pointer of capability string memory.

Return Values

  • [-1|0] Error or Success.




void Handler_MemoryFree(char *pInData);
Description
  • Free the mamory allocated for Handler_Get_Capability

Parameters

  • pInData[POINTER]
    • pointer of capability string memory.

Return Values

  • None.


void Handler_AutoReportStart(char *pInQuery);
Description
  • Start Auto Report

Parameters

  • pInQuery[POINTER]
    • pointer of  request string.

Return Values

  • None.


void Handler_AutoReportStop(char *pInQuery);
Description
  • Stop Auto Report

Parameters

  • pInQuery[POINTER]
    • pointer of  request string.

Return Values

  • None.

Handler Info Structure

typedef struct HANDLER_INFO
{
    char Name[MAX_TOPIC_LEN]; // The handler name
    char ServerIP[DEF_MAX_STRING_LENGTH];
    int ServerPort;
    char WorkDir[DEF_MAX_STRING_LENGTH];
    int RequestID;
    int ActionID;
 
    void* loghandle; // log file handler
 
    cagent_agent_info_body_t * agentInfo; // Info of the Agent
    HandlerSendCbf sendcbf; // Client Send information (in JSON format) to Cloud Server
    HandlerSendCustCbf sendcustcbf; // Client Send information (in JSON format) to Cloud Server with custom topic
    HandlerSubscribeCustCbf subscribecustcbf; // Client subscribe the custom topic to receive message from Cloud Server
    HandlerSendCapabilityCbf sendcapabilitycbf; // Client Send Spec.Info (in JSON format) to Cloud Server with SpecInfo topic
    HandlerAutoReportCbf sendreportcbf; // Client Send report (in JSON format) to Cloud Server with AutoReport topic
    HandlerSendEventCbf sendeventcbf; // Client Send Event Notify (in JSON format) to Cloud Server with EventNotify topic
}HANDLER_INFO, Handler_info;
Description
  • The structure for Handler Information, defined in susiaccess_handler_api.h.

Parameters

  • Name[POINTER]
    • handler name
  • ServerIP[POINTER]
    • Server URL or IP Address.
  • ServerPort[NUMBER]
    • Server (MQTT broker) listen port. 
  • WorkDir[POINTER]
    • current executable binary file location.
  • RequestID[NUMBER]
    • Unique Handler command resuest ID.
    • Not used in V3.1 or later version, preserved for V3.0
  • ActionID[NUMBER]
    • Unique Handler command responseID.
    • Not used in V3.1 or later version, preserved for V3.0
  • loghandle[POINTER]
    • the file handle of Log library
  • agentInfo[POINTER]
    • the pointer of agent information.
  • sendcbf[POINTER]
    • the function pointer to send common message on topic: "/cagent/admin/<ID>/agentactionreq".
  • sendcustcbf[POINTER]
    • the function pointer to send custom message on customized topic.
  • subscribecustcbf[POINTER]
    • the function pointer to subscribe a callback function to receive message from customized topic.
  • sendcapabilitycbf[POINTER]
    • the function pointer to send handler capability on topic: "/cagent/admin/<ID>/agentactionreq".
  • sendreportcbf[POINTER]
    • the function pointer to send sensor data report on topic: "/cagent/admin/<ID>/deviceinfo".
  • sendeventcbf[POINTER]
    • the function pointer to send event notify on topic: "/cagent/admin/<ID>/eventnotify".

Callback Function

typedef AGENT_SEND_STATUS  (*HandlerSendCbf) ( HANDLE const handler, int enum_act, void const * const requestData, unsigned int const requestLen, void *pRev1, void* pRev2 );
Description
  • define the function to send common message on topic: "/cagent/admin/<ID>/agentactionreq".

Parameters

  • handler [POINTER]
    • the structure to exchange the handler information between WISE Agent and Handler.
  • enum_act[NUMBER]
    • the custom command ID defined in Handler.
  • requestData [POINTER]
    • the content string in JSON format.
  • requestLen[NUMBER]
    • the content size.
  • pRev1 [POINTER]
    • preserved pointer.
  • pRev2 [POINTER]
    • preserved pointer.

Return Values

  • AGENT_SEND_STATUS
    • cagent_success
    • cagent_no_init,
    • cagent_callback_null,
    • cagent_callback_error,
    • cagent_no_connnect,
    • cagent_connect_error,
    • cagent_init_error,
    • cagent_network_sock_timeout,
    • cagent_network_sock_error,
    • cagent_send_data_error,


typedef AGENT_SEND_STATUS  (*HandlerSendCustCbf) ( HANDLE const handler, int enum_act, char const * const topic, void const * const requestData, unsigned int const requestLen, void *pRev1, void* pRev2 ); 
Description
  • define the function to send custom message on custom topic.

Parameters

  • handler [POINTER]
    • the structure to exchange the handler information between WISE Agent and Handler.
  • enum_act[NUMBER]
    • the custom command ID defined in Handler.
  • topic[POINTER]
    • the custom topic
  • requestData [POINTER]
    • the content string in JSON format.
  • requestLen[NUMBER]
    • the content size.
  • pRev1 [POINTER]
    • preserved pointer.
  • pRev2 [POINTER]
    • preserved pointer.

Return Values

  • AGENT_SEND_STATUS


typedef AGENT_SEND_STATUS  (*HandlerSubscribeCustCbf) ( char const * const topic, HandlerCustMessageRecvCbf recvCbf); 
Description
  • define the function to subscribe a callback function to receive the message from custom topic.

Parameters

  • handler [POINTER]
    • the structure to exchange the handler information between WISE Agent and Handler.
  • recvCbf[POINTER]
    • the callback function pointer to receive message.

Return Values

  • AGENT_SEND_STATUS


typedef void (*HandlerCustMessageRecvCbf)(char * const topic, void* const data, const size_t datalen, void *pRev1, void* pRev2);
Description
  • define the function to handle the received message from custom topic.

Parameters

  • topic[POINTER]
    • the custom topic
  • data[POINTER]
    • the content string in JSON format.
  • datalen[NUMBER]
    • the content size.
  • pRev1 [POINTER]
    • preserved pointer.
  • pRev2 [POINTER]
    • preserved pointer.

Return Values

  • None


typedef AGENT_SEND_STATUS  (*HandlerSendCapabilityCbf) ( HANDLE const handler, void const * const requestData, unsigned int const requestLen, void *pRev1, void* pRev2 ); 
Description
  • define the function to send handler capability message on topic: "/cagent/admin/<ID>/agentactionreq".

Parameters

  • handler [POINTER]
    • the structure to exchange the handler information between WISE Agent and Handler.
  • requestData [POINTER]
    • the content string in JSON format.
  • requestLen[NUMBER]
    • the content size.
  • pRev1 [POINTER]
    • preserved pointer.
  • pRev2 [POINTER]
    • preserved pointer.

Return Values

  • AGENT_SEND_STATUS


 typedef AGENT_SEND_STATUS  (*HandlerAutoReportCbf) ( HANDLE const handler, void const * const requestData, unsigned int const requestLen, void *pRev1, void* pRev2 );
Description
  • define the function to send sensor data report on topic: "/cagent/admin/<ID>/deviceinfo".

Parameters

  • handler [POINTER]
    • the structure to exchange the handler information between WISE Agent and Handler.
  • requestData [POINTER]
    • the content string in JSON format.
  • requestLen[NUMBER]
    • the content size.
  • pRev1 [POINTER]
    • preserved pointer.
  • pRev2 [POINTER]
    • preserved pointer.

Return Values

  • AGENT_SEND_STATUS


 typedef AGENT_SEND_STATUS  (*HandlerSendEventCbf) ( HANDLE const handler, HANDLER_NOTIFY_SEVERITY severity, void const * const requestData, unsigned int const requestLen, void *pRev1, void* pRev2 );
Description
  • define the function to send event notify on topic: "/cagent/admin/<ID>/eventnotify".

Parameters

  • handler [POINTER]
    • the structure to exchange the handler information between WISE Agent and Handler.
  • severity
    • the event severity:
      • Severity_Emergency
      • Severity_Alert
      • Severity_Critical
      • Severity_Error
      • Severity_Warning
      • Severity_Informational
      • Severity_Debug,
  • requestData [POINTER]
    • the content string in JSON format.
  • requestLen[NUMBER]
    • the content size.
  • pRev1 [POINTER]
    • preserved pointer.
  • pRev2 [POINTER]
    • preserved pointer.

Return Values

  • AGENT_SEND_STATUS

Agent Information Structure

typedef struct {
    char hostname[DEF_HOSTNAME_LENGTH]; /**< Agent host name */
    char devId[DEF_DEVID_LENGTH]; /**< Agent device id */
    char sn[DEF_SN_LENGTH]; /**< Agent mac */
    char mac[DEF_MAC_LENGTH]; /**< Agent sn */
    char version[DEF_VERSION_LENGTH]; /**< Agent version */
    char type[DEF_MAX_STRING_LENGTH];
    char product[DEF_MAX_STRING_LENGTH];
    char manufacture[DEF_MAX_STRING_LENGTH];
    int status; /**< Agent device status */
}cagent_agent_info_body_t;
Description
  • The structure for Agent Information, defined in susiaccess_handler_api.h.

Parameters

  • hostname[POINTER]
    • target device or agent name.
  • devId[POINTER]
    • unique device ID.
  • sn[POINTER]
    • device serial number
  • mac[POINTER]
    • device first MAC address.
  • version[POINTER]
    • Agent application version.
  • type[POINTER]
    • the agent type, defualt is IPC.
    • User can define their own type for customization.
  • product[POINTER]
    • product name.
  • manufacture[POINTER]
    • manufacture name.
  • status[NUMBER]
    • [0|1] disconnect or connected.

Mesage Generator APIs

List

MSG_CLASSIFY_T* IoT_CreateRoot(char* handlerName);
Description
  • Create the Root Node.

Parameters

  • handlerName[POINTER]
    • the name root node.

Return Values

  • (MSG_CLASSIFY_T*)
    • result pointer

Example


#include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
	char *result = NULL; 
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	result = IoT_PrintCapability(root );
 
	printf("%s", root );
 
	free(result);
 
	IoT_ReleaseAll(root);
 
	return iRet;
}
Result
{"test":{}}


MSG_CLASSIFY_T* IoT_AddGroup(MSG_CLASSIFY_T* pNode, char* groupName);
Description
  • Add a group node in another group node.

Parameters

  • pNode[POINTER]
    • parent node
  • handlerName[POINTER]
    • name of group node.

Return Values

  • (MSG_CLASSIFY_T*)
    • result pointer

Example


#include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
	char *result = NULL; 
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	IoT_AddGroup(root, "group");
 
	result = IoT_PrintCapability(root );
 
	printf("%s", root );
 
	free(result);
 
	IoT_ReleaseAll(root);
 
	return iRet;
}
Result
{"test":{"group":{"bn":"group"}}}


MSG_ATTRIBUTE_T* IoT_AddGroupAttribute(MSG_CLASSIFY_T* pNode, char* attrName);
Description
  • Add a attribute in a group node.

Parameters

  • pNode[POINTER]
    • parent node
  • attrName[POINTER]
    • name of attribute.

Return Values

  • (MSG_ATTRIBUTE_T*)
    • result pointer

Example


#include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
	char *result = NULL; 
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	MSG_CLASSIFY_T* group = IoT_AddGroup(root, "group");
 
	MSG_ATTRIBUTE_T* attr = IoT_AddGroupAttribute(group, "attribute");
 
	IoT_SetStringValue(attr, "My Attribute", IoT_READWRITE);
 
	result = IoT_PrintCapability(root );
 
	printf("%s", root );
 
	free(result);
 
	IoT_ReleaseAll(root);
 
	return iRet;
}
Result
{"test":{"group":{"bn":"group","attribute":"My Attribute"}}} 


MSG_ATTRIBUTE_T* IoT_AddSensorNode(MSG_CLASSIFY_T* pNode, char* senName);
Description
  • Add a sensor node in a group node.

Parameters

  • pNode[POINTER]
    • parent node
  • senName[POINTER]
    • name of attribute.

Return Values

  • (MSG_ATTRIBUTE_T*)
    • result pointer

Example


#include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
	char *result = NULL; 
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	MSG_CLASSIFY_T* group = IoT_AddGroup(root, "group");
 
	MSG_ATTRIBUTE_T* sensor = IoT_AddSensorNode(group, "sensor");
 
	IoT_SetDoubleValue(sensor, 24.5, IoT_READWRITE, "%");
 
	result = IoT_PrintCapability(root );
 
	printf("%s", root );
 
	free(result);
 
	IoT_ReleaseAll(root);
 
	return iRet;
}
Result
{"test":{"group":{"bn":"group","e":[{"n":"sensor","v":24.500000,"asm":"rw","u":"%"}]}}}


bool IoT_SetDoubleValue(MSG_ATTRIBUTE_T* attr, double value, IoT_READWRITE_MODE readwritemode, char *unit);
Description
  • assign a double value to the sensor or group attribute node.

Parameters

  • attr[POINTER]
    • target sensor or group attribute node.
  • value[NUMBER]
    • value in double.
  • readwritemode[NUMBER]
    • attribute read write mode
      • IoT_NODEFINE
      • IoT_READONLY
      • IoT_WRITEONLY
      • IoT_READWRITE
  • unit[POINTER]
    • data unit string

Return Values

  • [true | false] success or fail.

Example

Reference to IoT_AddSensorNode()



bool IoT_SetDoubleValueWithMaxMin(MSG_ATTRIBUTE_T* attr, double value, IoT_READWRITE_MODE readwritemode, double max, double min, char *unit);
Description
  • assign a double value with suggest max min range to the sensor or group attribute node.

Parameters

  • attr[POINTER]
    • target sensor or group attribute node.
  • value[NUMBER]
    • value in double.
  • readwritemode[NUMBER]
    • attribute read write mode
  • max[NUMBER]
    • maxium value in double.
  • min[NUMBER]
    • minimum value in double.
  • unit[POINTER]
    • data unit string

Return Values

  • [true | false] success or fail.

Example

#include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
	char *result = NULL; 
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	MSG_CLASSIFY_T* group = IoT_AddGroup(root, "group");
 
	MSG_ATTRIBUTE_T* sensor = IoT_AddSensorNode(group, "sensor");
 
	IoT_SetDoubleValueWithMaxMin(sensor, 24.5, IoT_READWRITE, 5, 1, "%");
 
	result = IoT_PrintCapability(root );
 
	printf("%s", root );
 
	free(result);
 
	IoT_ReleaseAll(root);
 
	return iRet;
}
Result
{"test":{"group":{"bn":"group","e":[{"n":"sensor","v":24.500000,"max":5,"min":1,"asm":"rw","u":"%"}]}}}


bool IoT_SetBoolValue(MSG_ATTRIBUTE_T* attr, bool bvalue,IoT_READWRITE_MODE readwritemode);
Description
  • assign a boolean value to the sensor or group attribute node.

Parameters

  • attr[POINTER]
    • target sensor or group attribute node.
  • bvalue[BOOLEAN]
    • boolean value.
  • readwritemode[NUMBER]
    • attribute read write mode

Return Values

  • [true | false] success or fail.

Example

#include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
	char *result = NULL; 
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	MSG_CLASSIFY_T* group = IoT_AddGroup(root, "group");
 
	MSG_ATTRIBUTE_T* sensor = IoT_AddSensorNode(group, "sensor");
 
	IoT_SetBoolValue(sensor, false, IoT_READONLY);
 
	result = IoT_PrintCapability(root );
 
	printf("%s", root );
 
	free(result);
 
	IoT_ReleaseAll(root);
 
	return iRet;
}
Result
{"test":{"group":{"bn":"group","e":[{"n":"sensor","bv":false,"asm":"r"}]}}}


bool IoT_SetStringValue(MSG_ATTRIBUTE_T* attr, char *svalue, IoT_READWRITE_MODE readwritemode);
Description
  • assign a string value to the sensor or group attribute node.

Parameters

  • attr[POINTER]
    • target sensor or group attribute node.
  • svalue[POINTER]
    • string value.
  • readwritemode[NUMBER]
    • attribute read write mode

Return Values

  • [true | false] success or fail.

Example

Reference to IoT_AddGroupAttribute().



MSG_ATTRIBUTE_T* IoT_FindSensorNodeWithPath(MSG_CLASSIFY_T *msg,char *path);
Description
  • Find sensor node with path in Message Structure.

Parameters

  • msg[POINTER]
    • root node of Message Structure.
  • path[POINTER]
    • sneosr node path

Return Values

  • (MSG_ATTRIBUTE_T*)
    • result pointer

Example

 #include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	MSG_CLASSIFY_T* group = IoT_AddGroup(root, "group");
 
	MSG_ATTRIBUTE_T* sensor = IoT_AddSensorNode(group, "sensor");
 
	IoT_SetBoolValue(sensor, false, IoT_READONLY);
 
	if(IoT_FindSensorNodeWithPath(root, "test/group/sensor") != NULL)
	{
		char *result = IoT_PrintCapability(root );
 
		printf("%s", result );
 
		free(result);
	}
	IoT_ReleaseAll(root);
 
	return iRet;
}



bool IoT_IsSensorExist(MSG_CLASSIFY_T *msg,char *path);
Description
  • check sensor node with path in Message Structure is exist or not.

Parameters

  • msg[POINTER]
    • root node of Message Structure.
  • path[POINTER]
    • sneosr node path

Return Values

  • [true | false] exist or not exist.

Example

 #include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	MSG_CLASSIFY_T* group = IoT_AddGroup(root, "group");
 
	MSG_ATTRIBUTE_T* sensor = IoT_AddSensorNode(group, "sensor");
 
	IoT_SetBoolValue(sensor, false, IoT_READONLY);
 
	if(IoT_IsSensorExist(root, "test/group/sensor"))
	{
		char *result = IoT_PrintCapability(root );
 
		printf("%s", result );
 
		free(result);
	}
	IoT_ReleaseAll(root);
 
	return iRet;
}


char *IoT_PrintCapability(MSG_CLASSIFY_T* pRoot);
Description
  • generate the Capability string in JSON format.

Parameters

  • pRoot[POINTER]
    • root node of Message Structure.

Return Values

  • pointer of string. 
    • calling free() to release the allocated memory.

Example

Reference to IoT_SetDoubleValueWithMaxMin().



char *IoT_PrintData(MSG_CLASSIFY_T* pRoot);
Description
  • generate the sensor data report string in JSON format.

Parameters

  • pRoot[POINTER]
    • root node of Message Structure.

Return Values

  • pointer of string. 
    • calling free() to release the allocated memory.

Example

#include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
	char *result = NULL; 
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	MSG_CLASSIFY_T* group = IoT_AddGroup(root, "group");
 
	MSG_ATTRIBUTE_T* sensor = IoT_AddSensorNode(group, "sensor");
 
	IoT_SetDoubleValueWithMaxMin(sensor, 24.5, IoT_READWRITE, 5, 1, "%");
 
	result = IoT_PrintData(root );
 
	printf("%s", root );
 
	free(result);
 
	IoT_ReleaseAll(root);
 
	return iRet;
}
Result
{"test":{"group":{"bn":"group","e":[{"n":"sensor","v":24.500000}]}}}


char *IoT_PrintSelectedData(MSG_CLASSIFY_T* pRoot, char* reqItems);
Description
  • generate the sensor data report string with filter.

Parameters

  • pRoot[POINTER]
    • root node of Message Structure.

Return Values

  • pointer of string. 
    • calling free() to release the allocated memory.

Example

#include "IoTMessageGenerate.h"
 
int main(int argc, char *argv[])
{
	int iRet = 0;
	char *result = NULL; 
 
	MSG_CLASSIFY_T* root = IoT_CreateRoot("test");
 
	MSG_CLASSIFY_T* group = IoT_AddGroup(root, "group");
 
	MSG_ATTRIBUTE_T* sensor = IoT_AddSensorNode(group, "sensor");
 
	IoT_SetDoubleValueWithMaxMin(sensor, 24.5, IoT_READWRITE, 5, 1, "%");
 
	sensor = IoT_AddSensorNode(group, "sensor2");
 
	IoT_SetDoubleValueWithMaxMin(sensor, 50.5, IoT_READWRITE, 5, 1, "%");
 
	result = IoT_PrintSelectedData(root, "{\"e\":[{\"n\":\"test/group/sensor2\"}]}");
 
	printf("%s", root );
 
	free(result);
 
	IoT_ReleaseAll(root);
 
	return iRet;
}
Result
{"test":{"group":{"bn":"group","e":[{"n":"sensor2","v":50.500000}]}}} 

void IoT_ReleaseAll(MSG_CLASSIFY_T* pRoot);

Description

  • free the resource of Message Structure.

Parameters

  • pRoot[POINTER]
    • root node of Message Structure.

Return Values

  • None.

Example

Reference to IoT_PrintSelectedData().

Handler Kernel APIs

List

int HandlerKernel_Initialize( HANDLER_INFO *handler );
Description
  • Init any objects or variables of this HandlerKernel.
  • In Sample Handler, implement the Handler_Initialize API and calling HandlerKernel_Initialize() to init the Handler Kernel.

Parameters

  • handler [POINTER]
    • the Handler Info structure pointer.

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
int Handler_Initialize( HANDLER_INFO *pluginfo )
{
    if( pluginfo == NULL )
        return handler_fail;
 
    return HandlerKernel_Initialize(pluginfo);
}


int HandlerKernel_Uninitialize();
Description
  • Uninit any objects or variables of this HandlerKernel
  • In Sample Handler, implement the Handler_Uninitialize and calling HandlerKernel_Uninitialize() to release the Handler Kernel.
  • The Handler_Uninitialize will be called while DLL release.

Parameters

  • None

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
void Handler_Uninitialize();
 
BOOL WINAPI DllMain(HINSTANCE module_handle, DWORD reason_for_call, LPVOID reserved)
{
	if (reason_for_call == DLL_PROCESS_ATTACH) // Self-explanatory
	{
		DisableThreadLibraryCalls(module_handle); // Disable DllMain calls for DLL_THREAD_*
		if (reserved == NULL) // Dynamic load
		{
			// Initialize your stuff or whatever
			// Return FALSE if you don't want your module to be dynamically loaded
		}
		else // Static load
		{
			// Return FALSE if you don't want your module to be statically loaded
			return FALSE;
		}
	}
 
	if (reason_for_call == DLL_PROCESS_DETACH) // Self-explanatory
	{
		if (reserved == NULL) // Either loading the DLL has failed or FreeLibrary was called
		{
			// Cleanup
			Handler_Uninitialize();
		}
		else // Process is terminating
		{
			// Cleanup
			Handler_Uninitialize();
		}
	}
	return TRUE;
}
 
void Handler_Uninitialize()
{
	HandlerKernel_Uninitialize();
}


int HandlerKernel_SetCapability( MSG_CLASSIFY_T* pCapability, bool bPublish );
Description
  • Assign the Capability structure and force to send or not.
  • In Sample Handler, implement the Handler_Get_Capability API and calling HandlerKernel_SetCapability() to setup without sending capability.

Parameters

  • pCapability[POINTER]
    • the pointer of Message Structure to describe the capability.
  • bPublish [BOOLEAN]
    • the flag force to send capability or not.

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
int Handler_Get_Capability( char ** pOutReply ) // JSON Format
{
	char* result = NULL;
	int len = 0;
 
	if(!pOutReply) return len;
 
	if(!g_Capability)
	{
		g_Capability = CreateCapability();
		HandlerKernel_SetCapability(g_Capability, false);
	}
 
	result = IoT_PrintCapability(g_Capability);
 
	len = strlen(result);
	*pOutReply = (char *)malloc(len + 1);
	memset(*pOutReply, 0, len + 1);
	strcpy(*pOutReply, result);
	free(result);
	return len;
}


int HandlerKernel_AutoReportStart(char *pInQuery);
Description
  • Start auto report repeatedly with a time interval.
  • In Sample Handler, implement the Handler_AutoReportStart API and calling HandlerKernel_AutoReportStart() to activate the auto report thread.

Parameters

  • pInQuery[POINTER]
    • the received auto report command.

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
void Handler_AutoReportStart(char *pInQuery)
{
	/*TODO: Parsing received command
	*input data format: 
	* {"susiCommData":{"catalogID":4,"autoUploadIntervalSec":30,"requestID":1001,"requestItems":["all"],"commCmd":2053}}
	*
	* "autoUploadIntervalSec":30 means report sensor data every 30 sec.
	* "requestItems":["all"] defined which handler or sensor data to report. 
	*/
 
	/*create thread to report sensor data*/
	HandlerKernel_AutoReportStart(pInQuery);
}


int HandlerKernel_AutoReportStop(char *pInQuery);
Description
  • StopAuto Report.
  • In Sample Handler, implement the Handler_AutoReportStop API and calling HandlerKernel_AutoReportStop() to stop the auto report thread.

Parameters

  • pInQuery[POINTER]
    • preserved for received command.

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
void HANDLER_API Handler_AutoReportStop(char *pInQuery)
{
 
	HandlerKernel_AutoReportStop(pInQuery);
}


int HandlerKernel_SetAutoReportFilter(char *pInQuery);
Description
  • Setup the auto report filter carried with input message.
  • In Sample Handler, implement the Handler_AutoReportStart API and calling HandlerKernel_SetAutoReportFilter() to setup the filter. If developer doesn't want the Handler send report data repeatedly but only send report data once by event triggered.

Parameters

  • pInQuery[POINTER]
    • the received auto report command.

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
void Handler_DataChangedCallback()
{
	HandlerKernel_SendAutoReportOnce();
}
 
void Handler_AutoReportStart(char *pInQuery)
{
	/*TODO: Parsing received command
	*input data format: 
	* {"susiCommData":{"catalogID":4,"autoUploadIntervalSec":30,"requestID":1001,"requestItems":["all"],"commCmd":2053}}
	*
	* "autoUploadIntervalSec":30 means report sensor data every 30 sec.
	* "requestItems":["all"] defined which handler or sensor data to report. 
	*/
	HandlerKernel_SetAutoReportFilter(pInQuery);
}


int HandlerKernel_SendAutoReportOnce();
Description
  • Send the auto report data once.
  • In Sample Handler, developer can implement the event triggered data report.

Parameters

  • None.

Return Values

  • [-1 | 0] fail or success.

Example Reference to HandlerKernel_SetAutoReportFilter().



int HandlerKernel_ParseRecvCMDWithSessionID(char *pInQuery, int * cmdID, char * sessionID);
Description
  • Parse the received message as Command ID and Session ID.

Parameters

  • pInQuery[POINTER]
    • the received command.
  • cmdID[POINTER]
    • output the parsed command ID in integer.
    • User can customize the Command ID
    • HandlerKernel pre-defined the Command ID.
      • unknown_cmd = 0,
      • hk_get_capability_req = 521,
      • hk_get_capability_rep = 522,
      • hk_get_sensors_data_req = 523,
      • hk_get_sensors_data_rep = 524,
      • hk_set_sensors_data_req = 525,
      • hk_set_sensors_data_rep = 526,
      • hk_set_thr_req = 527,
      • hk_set_thr_rep = 528,
      • hk_del_thr_req = 529,
      • hk_del_thr_rep = 530,
      • hk_thr_check_rep = 532,
      • hk_auto_upload_req = 533,
      • hk_auto_upload_rep = 534,
      • hk_get_sensors_data_error_rep = 598,
      • hk_error_rep = 600,
  • sessionID[POINTER]
    • output the parsed session ID string.

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
void Handler_Recv(char * const topic, void* const data, const size_t datalen, void *pRev1, void* pRev2  )
{
	int cmdID = 0;
	char sessionID[32] = {0};
	printf(" >Recv Topic [%s] Data %s\n", topic, (char*) data );
	/*Parse Received Command*/
	if(HandlerKernel_ParseRecvCMDWithSessionID((char*)data, &cmdID, sessionID) != handler_success)
		return;
	switch(cmdID)
	{
	case hk_auto_upload_req:
		/*start live report*/
		HandlerKernel_LiveReportStart(hk_auto_upload_rep, (char*)data);
		break;
	default:
		{
			/* Send command not support reply message*/
			char repMsg[32] = {0};
			int len = 0;
			sprintf( repMsg, "{\"errorRep\":\"Unknown cmd!\"}" );
			len= strlen( "{\"errorRep\":\"Unknown cmd!\"}" ) ;
			if ( g_sendcbf ) g_sendcbf( & g_HandlerInfo, hk_error_rep, repMsg, len, NULL, NULL );
		}
		break;
	}
}


int HandlerKernel_LiveReportStart(int replyID, char *pInQuery);
Description
  • Start Live Report with received command.

Parameters

  • replyID[NUMBER]
    • the message reply ID.
    • User can customize the reply ID
    • HandlerKernel also pre-defined the reply ID as Command ID.
  • pInQuery[POINTER]
    • the received command.

Return Values

  • [-1 | 0] fail or success.

Example

Reference to HandlerKernel_ParseRecvCMDWithSessionID().



int HandlerKernel_SetThreshold(int replyID, char *pInQuery);
Description
  • Setup threshold rule.

Parameters

  • replyID[NUMBER]
    • the message reply ID.
    • User can customize the reply ID
    • HandlerKernel also pre-defined the reply ID as Command ID.
  • pInQuery[POINTER]
    • the received command.

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
void on_threshold_triggered(threshold_event_type type, char* sensorname, double value, MSG_ATTRIBUTE_T* attr, void *pRev)
{
	printf(" %s> threshold triggered:[%d, %s, %f]", g_HandlerInfo.Name, type, sensorname, value);
}
 
void Handler_Recv(char * const topic, void* const data, const size_t datalen, void *pRev1, void* pRev2  )
{
	int cmdID = 0;
	char sessionID[32] = {0};
	printf(" >Recv Topic [%s] Data %s\n", topic, (char*) data );
	/*Parse Received Command*/
	if(HandlerKernel_ParseRecvCMDWithSessionID((char*)data, &cmdID, sessionID) != handler_success)
		return;
	switch(cmdID)
	{
	case hk_set_thr_req:
		/*Stop threshold check thread*/
		HandlerKernel_StopThresholdCheck();
		/*setup threshold rule*/
		HandlerKernel_SetThreshold(hk_set_thr_rep,(char*) data);
		/*register the threshold check callback function to handle trigger event*/
		HandlerKernel_SetThresholdTrigger(on_threshold_triggered);
		/*Restart threshold check thread*/
		HandlerKernel_StartThresholdCheck();
		break;
	case hk_del_thr_req:
		/*Stop threshold check thread*/
		HandlerKernel_StopThresholdCheck();
		/*clear threshold check callback function*/
		HandlerKernel_SetThresholdTrigger(NULL);
		/*Delete all threshold rules*/
		HandlerKernel_DeleteAllThreshold(hk_del_thr_rep);
		break;
	default:
		{
			/* Send command not support reply message*/
			char repMsg[32] = {0};
			int len = 0;
			sprintf( repMsg, "{\"errorRep\":\"Unknown cmd!\"}" );
			len= strlen( "{\"errorRep\":\"Unknown cmd!\"}" ) ;
			if ( g_sendcbf ) g_sendcbf( & g_HandlerInfo, hk_error_rep, repMsg, len, NULL, NULL );
		}
		break;
	}
}


 int HandlerKernel_DeleteAllThreshold(int replyID);
Description
  • Delete all threshold rules.

Parameters

  • replyID[NUMBER]
    • the message reply ID.
    • User can customize the reply ID
    • HandlerKernel also pre-defined the reply ID as Command ID.

Return Values

  • [-1 | 0] fail or success.

Example

Reference to HandlerKernel_SetThreshold().



int HandlerKernel_StartThresholdCheck();
Description
  • Start threshold rule check thread.

Parameters

  • None.

Return Values

  • [-1 | 0] fail or success.

Example

Reference to HandlerKernel_SetThreshold().



int HandlerKernel_StopThresholdCheck();
Description
  • Stop threshold rule check thread.

Parameters

  • None.

Return Values

  • [-1 | 0] fail or success.

Example

Reference to HandlerKernel_SetThreshold().



int HandlerKernel_SetThresholdTrigger(void (*on_triggered)(threshold_event_type type, char* sensorname, double value, MSG_ATTRIBUTE_T* attr, void *pRev));
Description
  • register the threshold check event callback function.

Parameters

  • on_triggered[POINTER].
    • callback function pointer
    • void (*on_triggered)(threshold_event_type type, char* sensorname, double value, MSG_ATTRIBUTE_T* attr, void *pRev);
      • type[NUMBER]
        • thrshold event type:
          • thr_normal = 0,
          • thr_out_of_range,
      • sensorname[POINTER]
        • sensor name
      • value[NUMBER]
        • sensor value
      • attr[POINTER]
        • sensor node in Message Structure.
      • pRev[POINTER]
        • Preserved pointer.
      • No Return Value

Return Values

  • [-1 | 0] fail or success.

Example

Reference to HandlerKernel_SetThreshold().



int HandlerKernel_GetSensorData(int replyID, char* sessionID, char *pInQuery, bool (*on_get_sensor)(get_data_t* getlist, void *pRev));
Description
  • Get Sensor Data.

Parameters

  • replyID[NUMBER]
    • the message reply ID.
    • User can customize the reply ID
    • HandlerKernel also pre-defined the reply ID as Command ID.
  • sessionID[POINTER]
    • the session ID string.
  • pInQuery[POINTER]
    • the received command.
  • on_get_sensor[POINTER]
    • callback function pointer
    • bool (*on_get_sensor)(get_data_t* getlist, void *pRev);
      • getlist[POINTER]
        • list of the target data structure
      • pRev[POINTER]
        • Preserved pointer.
      • Return values
        • [true|false] success or fail

Return Values

  • [-1 | 0] fail or success.

Example


#include "susiaccess_handler_api.h"
#include "HandlerKernel.h"
 
void on_threshold_triggered(threshold_event_type type, char* sensorname, double value, bool on_get_sensor(get_data_t* objlist, void *pRev)
{
	get_data_t *current = objlist;
	if(objlist == NULL) return false;
 
	while(current)
	{
		current->errcode = STATUSCODE_SUCCESS;
		strcpy(current->errstring, STATUS_SUCCESS);
 
		switch(current->attr->type)
		{
		case attr_type_numeric:
			printf(" %s> get: %s value:%d", g_HandlerInfo.Name, current->sensorname, current->attr->v);
		 break;
		case attr_type_boolean:
			printf(" %s> get: %s value:%s", g_HandlerInfo.Name, current->sensorname, current->attr->bv?"true":"false");
		 break;
		case attr_type_string:
			printf(" %s> get: %s value:%s", g_HandlerInfo.Name, current->sensorname, current->attr->sv);
		 break;
		case attr_type_date:
			printf(" %s> get: %s value:Date:%s", g_HandlerInfo.Name, current->sensorname, current->attr->sv);
		 break;
		case attr_type_timestamp:
		 printf(" %s> get: %s value:Timestamp:%d", g_HandlerInfo.Name, current->sensorname, current->attr->v);
		 break;
		}
 
		current = current->next;
	}
	return true;
}
 
bool on_set_sensor(set_data_t* objlist, void *pRev)
{
	set_data_t *current = objlist;
	if(objlist == NULL) return false;
	while(current)
	{
		current->errcode = STATUSCODE_SUCCESS;
		strcpy(current->errstring, STATUS_SUCCESS);
 
		switch(current->newtype)
		{
		case attr_type_numeric:
			printf(" %s> set: %s value:%d", g_HandlerInfo.Name, current->sensorname, current->v);
		 break;
		case attr_type_boolean:
			printf(" %s> set: %s value:%s", g_HandlerInfo.Name, current->sensorname, current->bv?"true":"false");
		 break;
		case attr_type_string:
			printf(" %s> set: %s value:%s", g_HandlerInfo.Name, current->sensorname, current->sv);
		 break;
		}
 
		current = current->next;
	}
 
	return true;
}
 
void Handler_Recv(char * const topic, void* const data, const size_t datalen, void *pRev1, void* pRev2  )
{
	int cmdID = 0;
	char sessionID[32] = {0};
	printf(" >Recv Topic [%s] Data %s\n", topic, (char*) data );
 
	/*Parse Received Command*/
	if(HandlerKernel_ParseRecvCMDWithSessionID((char*)data, &cmdID, sessionID) != handler_success)
		return;
	switch(cmdID)
	{
	case hk_get_sensors_data_req:
		/*Get Sensor Data with callback function*/
		HandlerKernel_GetSensorData(hk_get_sensors_data_rep, sessionID, (char*)data, on_get_sensor);
		break;
	case hk_set_sensors_data_req:
		/*Set Sensor Data with callback function*/
		HandlerKernel_SetSensorData(hk_set_sensors_data_rep, sessionID, (char*)data, on_set_sensor);
		break;
	default:
		{
			/* Send command not support reply message*/
			char repMsg[32] = {0};
			int len = 0;
			sprintf( repMsg, "{\"errorRep\":\"Unknown cmd!\"}" );
			len= strlen( "{\"errorRep\":\"Unknown cmd!\"}" ) ;
			if ( g_sendcbf ) g_sendcbf( & g_HandlerInfo, hk_error_rep, repMsg, len, NULL, NULL );
		}
		break;
	}}


int HandlerKernel_SetSensorData(int replyID, char* sessionID, char *pInQuery, bool (*on_set_sensor)(set_data_t* setlist, void *pRev));
Description
  • Set Sensor Data.

Parameters

  • replyID[NUMBER]
    • the message reply ID.
    • User can customize the reply ID
    • HandlerKernel also pre-defined the reply ID as Command ID.
  • sessionID[POINTER]
    • the session ID string.
  • pInQuery[POINTER]
    • the received command.
  • on_set_sensor[POINTER]
    • callback function pointer
    • bool (*on_set_sensor)(set_data_t* setlist, void *pRev));
      • setlist[POINTER]
        • list of the target data structure
      • pRev[POINTER]
        • Preserved pointer.
      • Return values
        • [true|false] success or fail

Return Values

  • [-1 | 0] fail or success.

Example

Reference to HandlerKernel_GetSensorData().

Handler Sample Code

#include "stdafx.h"
#include "susiaccess_handler_api.h"
#include "DeviceMessageGenerate.h"
#include "IoTMessageGenerate.h"
#include "FlatToIPSO.h"
#include <Log.h>
#include <stdio.h>
#include "cJSON.h"
#include "HandlerKernel.h"
 
//-----------------------------------------------------------------------------
// Logger defines:
//-----------------------------------------------------------------------------
#define SAMPLEHANDLER_LOG_ENABLE
//#define DEF_SAMPLEHANDLER_LOG_MODE    (LOG_MODE_NULL_OUT)
//#define DEF_SAMPLEHANDLER_LOG_MODE    (LOG_MODE_FILE_OUT)
#define DEF_SAMPLEHANDLER_LOG_MODE    (LOG_MODE_CONSOLE_OUT|LOG_MODE_FILE_OUT)
 
LOGHANDLE g_samolehandlerlog = NULL;
 
#ifdef SAMPLEHANDLER_LOG_ENABLE
#define SampleHLog(level, fmt, ...)  do { if (g_samolehandlerlog != NULL)   \
	WriteLog(g_samolehandlerlog, DEF_SAMPLEHANDLER_LOG_MODE, level, fmt, ##__VA_ARGS__); } while(0)
#else
#define SampleHLog(level, fmt, ...)
#endif
 
//-----------------------------------------------------------------------------
// Types and defines:
//-----------------------------------------------------------------------------
#define cagent_request_custom 2102 /*define the request ID for V3.0, not used on V3.1 or later*/
#define cagent_custom_action 31002 /*define the action ID for V3.0, not used on V3.1 or later*/
 
const char strHandlerName[MAX_TOPIC_LEN] = {"TextHandler"}; /*declare the handler name*/
 
MSG_CLASSIFY_T *g_Capability = NULL; /*the global message structure to describe the sensor data as the handelr capability*/
//-----------------------------------------------------------------------------
// Internal Prototypes:
//-----------------------------------------------------------------------------
//
typedef struct{
   void* threadHandler; // thread handle
   int interval;		// time interval for file read
   bool isThreadRunning;//thread running flag
}handler_context_t;
 
//-----------------------------------------------------------------------------
// Variables
//-----------------------------------------------------------------------------
static Handler_info  g_HandlerInfo; //global Handler info structure
static handler_context_t g_HandlerContex;
static HANDLER_THREAD_STATUS g_status = handler_status_no_init; // global status flag.
static HandlerSendCbf  g_sendcbf = NULL;						// Client Send information (in JSON format) to Cloud Server	
//-----------------------------------------------------------------------------
// Function:
//-----------------------------------------------------------------------------
void Handler_Uninitialize();
 
#ifdef _MSC_VER
BOOL WINAPI DllMain(HINSTANCE module_handle, DWORD reason_for_call, LPVOID reserved)
{
	if (reason_for_call == DLL_PROCESS_ATTACH) // Self-explanatory
	{
		DisableThreadLibraryCalls(module_handle); // Disable DllMain calls for DLL_THREAD_*
		if (reserved == NULL) // Dynamic load
		{
			// Initialize your stuff or whatever
			// Return FALSE if you don't want your module to be dynamically loaded
		}
		else // Static load
		{
			// Return FALSE if you don't want your module to be statically loaded
			return FALSE;
		}
	}
 
	if (reason_for_call == DLL_PROCESS_DETACH) // Self-explanatory
	{
		if (reserved == NULL) // Either loading the DLL has failed or FreeLibrary was called
		{
			// Cleanup
			Handler_Uninitialize();
		}
		else // Process is terminating
		{
			// Cleanup
			Handler_Uninitialize();
		}
	}
	return TRUE;
}
#else
__attribute__((constructor))
/**
 * initializer of the shared lib.
 */
static void Initializer(int argc, char** argv, char** envp)
{
    printf("DllInitializer\r\n");
}
 
__attribute__((destructor))
/** 
 * It is called when shared lib is being unloaded.
 * 
 */
static void Finalizer()
{
    printf("DllFinalizer\r\n");
	Handler_Uninitialize();
}
#endif
 
static char buff[1024]={0};
/*Open text file*/
const char* FileRead()
{
	FILE *fpSrc = fopen("c:/test.txt", "r");
	if(fpSrc)
	{
		fgets(buff, 1024, fpSrc);
		fclose(fpSrc);
	}
	fpSrc = NULL;
	return buff;
}
 
bool ParseReceivedData(MSG_CLASSIFY_T *pGroup)
{
	/*Data String: {"<tag>":<Number>, "<tag>":true, "<tag>":false, "<tag>":null, "<tag>":"<string>"}*/
	char* data = (char *)FileRead();
	if(!data) return false;
	if(strlen(data)<=0) return false;	
	return transfer_parse_json(data, pGroup);
}
 
/*Create Capability Message Structure to describe sensor data*/
MSG_CLASSIFY_T * CreateCapability()
{
	MSG_CLASSIFY_T* myCapability = IoT_CreateRoot((char*)strHandlerName);
	MSG_CLASSIFY_T*myGroup = IoT_AddGroup(myCapability, "Monitor");
	MSG_ATTRIBUTE_T* attr = NULL;
	/*Open text file and parse the JSON string into Message Structure*/
	ParseReceivedData(myGroup);
	return myCapability;
}
 
static DWORD WINAPI SampleHandlerReportThread(void *args)
{
	/*thread to read text file repeatedly.*/
	handler_context_t *pHandlerContex = (handler_context_t *)args;
	int mInterval = pHandlerContex->interval * 1000;
 
	if(!g_Capability)
	{
		g_Capability = CreateCapability();
		HandlerKernel_SetCapability(g_Capability, true);
	}
 
	while(pHandlerContex->isThreadRunning)
	{
 
		if(g_Capability)
		{
			MSG_CLASSIFY_T *myGroup = IoT_FindGroup(g_Capability, "Monitor");
			if(myGroup)
				ParseReceivedData(myGroup);
		}
		Sleep(mInterval);
	}
    return 0;
}
 
/*callback function to handle threshold rule check event*/
void on_threshold_triggered(threshold_event_type type, char* sensorname, double value, MSG_ATTRIBUTE_T* attr, void *pRev)
{
	SampleHLog(Debug, " %s> threshold triggered:[%d, %s, %f]", g_HandlerInfo.Name, type, sensorname, value);
}
 
/*callback function to handle get sensor data event*/
bool on_get_sensor(get_data_t* objlist, void *pRev)
{
	get_data_t *current = objlist;
	if(objlist == NULL) return false;
 
	while(current)
	{
		current->errcode = STATUSCODE_SUCCESS;
		strcpy(current->errstring, STATUS_SUCCESS);
 
		switch(current->attr->type)
		{
		case attr_type_numeric:
			SampleHLog(Debug, " %s> get: %s value:%d", g_HandlerInfo.Name, current->sensorname, current->attr->v);
		 break;
		case attr_type_boolean:
			SampleHLog(Debug, " %s> get: %s value:%s", g_HandlerInfo.Name, current->sensorname, current->attr->bv?"true":"false");
		 break;
		case attr_type_string:
			SampleHLog(Debug, " %s> get: %s value:%s", g_HandlerInfo.Name, current->sensorname, current->attr->sv);
		 break;
		case attr_type_date:
			SampleHLog(Debug, " %s> get: %s value:Date:%s", g_HandlerInfo.Name, current->sensorname, current->attr->sv);
		 break;
		case attr_type_timestamp:
		 SampleHLog(Debug, " %s> get: %s value:Timestamp:%d", g_HandlerInfo.Name, current->sensorname, current->attr->v);
		 break;
		}
 
		current = current->next;
	}
	return true;
}
 
/*callback function to handle set sensor data event*/
bool on_set_sensor(set_data_t* objlist, void *pRev)
{
	set_data_t *current = objlist;
	if(objlist == NULL) return false;
	while(current)
	{
		current->errcode = STATUSCODE_SUCCESS;
		strcpy(current->errstring, STATUS_SUCCESS);
 
		switch(current->newtype)
		{
		case attr_type_numeric:
			SampleHLog(Debug, " %s> set: %s value:%d", g_HandlerInfo.Name, current->sensorname, current->v);
		 break;
		case attr_type_boolean:
			SampleHLog(Debug, " %s> set: %s value:%s", g_HandlerInfo.Name, current->sensorname, current->bv?"true":"false");
		 break;
		case attr_type_string:
			SampleHLog(Debug, " %s> set: %s value:%s", g_HandlerInfo.Name, current->sensorname, current->sv);
		 break;
		}
 
		current = current->next;
	}
 
	return true;
}
 
/* **************************************************************************************
 *  Function Name: Handler_Initialize
 *  Description: Init any objects or variables of this handler
 *  Input :  PLUGIN_INFO *pluginfo
 *  Output: None
 *  Return:  0  : Success Init Handler
 *              -1 : Fail Init Handler
 * ***************************************************************************************/
int HANDLER_API Handler_Initialize( HANDLER_INFO *pluginfo )
{
	if( pluginfo == NULL )
		return handler_fail;
	// 1. Topic of this handler
	sprintf_s( pluginfo->Name, sizeof(pluginfo->Name), "%s", strHandlerName );
	pluginfo->RequestID = cagent_request_custom;
	pluginfo->ActionID = cagent_custom_action;
	g_samolehandlerlog = pluginfo->loghandle;
	SampleHLog(Debug, " %s> Initialize", strHandlerName);
	// 2. Copy agent info 
	memcpy(&g_HandlerInfo, pluginfo, sizeof(HANDLER_INFO));
	g_HandlerInfo.agentInfo = pluginfo->agentInfo;
 
	// 3. Callback function -> Send JSON Data by this callback function
 
	g_HandlerContex.threadHandler = NULL;
	g_HandlerContex.isThreadRunning = false;
	g_status = handler_status_no_init;
 
	return HandlerKernel_Initialize(pluginfo);
}
 
/* **************************************************************************************
 *  Function Name: Handler_Uninitialize
 *  Description: Release the objects or variables used in this handler
 *  Input :  None
 *  Output: None
 *  Return:  void
 * ***************************************************************************************/
void Handler_Uninitialize()
{
	/*Stop read text file thread*/
	if(g_HandlerContex.threadHandler)
	{
		g_HandlerContex.isThreadRunning = false;
		WaitForSingleObject(g_HandlerContex.threadHandler, INFINITE);
		CloseHandle(g_HandlerContex.threadHandler);
		g_HandlerContex.threadHandler = NULL;
	}
	HandlerKernel_Uninitialize();
	/*Release Capability Message Structure*/
	if(g_Capability)
	{
		IoT_ReleaseAll(g_Capability);
		g_Capability = NULL;
	}
}
 
/* **************************************************************************************
 *  Function Name: Handler_Get_Status
 *  Description: Get Handler Threads Status. CAgent will restart current Handler or restart CAgent self if busy.
 *  Input :  None
 *  Output: char * : pOutStatus       // cagent handler status
 *  Return:  handler_success  : Success Init Handler
 *			 handler_fail : Fail Init Handler
 * **************************************************************************************/
int HANDLER_API Handler_Get_Status( HANDLER_THREAD_STATUS * pOutStatus )
{
	int iRet = handler_fail; 
	SampleHLog(Debug, " %s> Get Status", strHandlerName);
	if(!pOutStatus) return iRet;
	/*user need to implement their thread status check function*/
	*pOutStatus = g_status;
 
	iRet = handler_success;
	return iRet;
}
 
 
/* **************************************************************************************
 *  Function Name: Handler_OnStatusChange
 *  Description: Agent can notify handler the status is changed.
 *  Input :  PLUGIN_INFO *pluginfo
 *  Output: None
 *  Return:  None
 * ***************************************************************************************/
void HANDLER_API Handler_OnStatusChange( HANDLER_INFO *pluginfo )
{
	SampleHLog(Debug, " %s> Update Status", strHandlerName);
	if(pluginfo)
		memcpy(&g_HandlerInfo, pluginfo, sizeof(HANDLER_INFO));
	else
	{
		memset(&g_HandlerInfo, 0, sizeof(HANDLER_INFO));
		sprintf_s( g_HandlerInfo.Name, sizeof( g_HandlerInfo.Name), "%s", strHandlerName );
		g_HandlerInfo.RequestID = cagent_request_custom;
		g_HandlerInfo.ActionID = cagent_custom_action;
	}
}
 
/* **************************************************************************************
 *  Function Name: Handler_Start
 *  Description: Start Running
 *  Input :  None
 *  Output: None
 *  Return:  0  : Success Init Handler
 *              -1 : Fail Init Handler
 * ***************************************************************************************/
int HANDLER_API Handler_Start( void )
{
	SampleHLog(Debug, "> %s Start", strHandlerName);
	/*Create thread to read text file*/
	g_HandlerContex.interval = 1;
	g_HandlerContex.isThreadRunning = true;
	g_HandlerContex.threadHandler = CreateThread(NULL, 0, SampleHandlerReportThread, &g_HandlerContex, 0, NULL);
 
	g_status = handler_status_start;
	return handler_success;
}
 
/* **************************************************************************************
 *  Function Name: Handler_Stop
 *  Description: Stop the handler
 *  Input :  None
 *  Output: None
 *  Return:  0  : Success Init Handler
 *              -1 : Fail Init Handler
 * ***************************************************************************************/
int HANDLER_API Handler_Stop( void )
{
	SampleHLog(Debug, "> %s Stop", strHandlerName);
 
	/*Stop text file read thread*/
	if(g_HandlerContex.threadHandler)
	{
		g_HandlerContex.isThreadRunning = false;
		WaitForSingleObject(g_HandlerContex.threadHandler, INFINITE);
		CloseHandle(g_HandlerContex.threadHandler);
		g_HandlerContex.threadHandler = NULL;
	}
 
	g_status = handler_status_stop;
	return handler_success;
}
 
/* **************************************************************************************
 *  Function Name: Handler_Recv
 *  Description: Receive Packet from MQTT Server
 *  Input : char * const topic, 
 *			void* const data, 
 *			const size_t datalen
 *  Output: void *pRev1, 
 *			void* pRev2
 *  Return: None
 * ***************************************************************************************/
void HANDLER_API Handler_Recv(char * const topic, void* const data, const size_t datalen, void *pRev1, void* pRev2  )
{
	int cmdID = 0;
	char sessionID[32] = {0};
	printf(" >Recv Topic [%s] Data %s\n", topic, (char*) data );
 
	/*Parse Received Command*/
	if(HandlerKernel_ParseRecvCMDWithSessionID((char*)data, &cmdID, sessionID) != handler_success)
		return;
	switch(cmdID)
	{
	case hk_auto_upload_req:
		/*start live report*/
		HandlerKernel_LiveReportStart(hk_auto_upload_rep, (char*)data);
		break;
	case hk_set_thr_req:
		/*Stop threshold check thread*/
		HandlerKernel_StopThresholdCheck();
		/*setup threshold rule*/
		HandlerKernel_SetThreshold(hk_set_thr_rep,(char*) data);
		/*register the threshold check callback function to handle trigger event*/
		HandlerKernel_SetThresholdTrigger(on_threshold_triggered);
		/*Restart threshold check thread*/
		HandlerKernel_StartThresholdCheck();
		break;
	case hk_del_thr_req:
		/*Stop threshold check thread*/
		HandlerKernel_StopThresholdCheck();
		/*clear threshold check callback function*/
		HandlerKernel_SetThresholdTrigger(NULL);
		/*Delete all threshold rules*/
		HandlerKernel_DeleteAllThreshold(hk_del_thr_rep);
		break;
	case hk_get_sensors_data_req:
		/*Get Sensor Data with callback function*/
		HandlerKernel_GetSensorData(hk_get_sensors_data_rep, sessionID, (char*)data, on_get_sensor);
		break;
	case hk_set_sensors_data_req:
		/*Set Sensor Data with callback function*/
		HandlerKernel_SetSensorData(hk_set_sensors_data_rep, sessionID, (char*)data, on_set_sensor);
		break;
	default:
		{
			/* Send command not support reply message*/
			char repMsg[32] = {0};
			int len = 0;
			sprintf( repMsg, "{\"errorRep\":\"Unknown cmd!\"}" );
			len= strlen( "{\"errorRep\":\"Unknown cmd!\"}" ) ;
			if ( g_sendcbf ) g_sendcbf( & g_HandlerInfo, hk_error_rep, repMsg, len, NULL, NULL );
		}
		break;
	}
}
 
/* **************************************************************************************
 *  Function Name: Handler_AutoReportStart
 *  Description: Start Auto Report
 *  Input : char *pInQuery
 *  Output: None
 *  Return: None
 * ***************************************************************************************/
void HANDLER_API Handler_AutoReportStart(char *pInQuery)
{
	/*TODO: Parsing received command
	*input data format: 
	* {"susiCommData":{"catalogID":4,"autoUploadIntervalSec":30,"requestID":1001,"requestItems":["all"],"commCmd":2053}}
	*
	* "autoUploadIntervalSec":30 means report sensor data every 30 sec.
	* "requestItems":["all"] defined which handler or sensor data to report. 
	*/
	SampleHLog(Debug, "> %s Start Report", strHandlerName);
	/*create thread to report sensor data*/
	HandlerKernel_AutoReportStart(pInQuery);
}
 
/* **************************************************************************************
 *  Function Name: Handler_AutoReportStop
 *  Description: Stop Auto Report
 *  Input : None
 *  Output: None
 *  Return: None
 * ***************************************************************************************/
void HANDLER_API Handler_AutoReportStop(char *pInQuery)
{
	/*TODO: Parsing received command*/
	SampleHLog(Debug, "> %s Stop Report", strHandlerName);
 
	HandlerKernel_AutoReportStop(pInQuery);
}
 
/* **************************************************************************************
 *  Function Name: Handler_Get_Capability
 *  Description: Get Handler Information specification. 
 *  Input :  None
 *  Output: char ** : pOutReply       // JSON Format
 *  Return:  int  : Length of the status information in JSON format
 *                :  0 : no data need to trans
 * **************************************************************************************/
int HANDLER_API Handler_Get_Capability( char ** pOutReply ) // JSON Format
{
	char* result = NULL;
	int len = 0;
 
	SampleHLog(Debug, "> %s Get Capability", strHandlerName);
 
	if(!pOutReply) return len;
 
	/*Create Capability Message Structure to describe sensor data*/
	if(!g_Capability)
	{
		g_Capability = CreateCapability();
		HandlerKernel_SetCapability(g_Capability, false);
	}
	/*generate capability JSON string*/
	result = IoT_PrintCapability(g_Capability);
 
	/*create buffer to store the string*/
	len = strlen(result);
	*pOutReply = (char *)malloc(len + 1);
	memset(*pOutReply, 0, len + 1);
	strcpy(*pOutReply, result);
	free(result);
	return len;
}
 
/* **************************************************************************************
 *  Function Name: Handler_MemoryFree
 *  Description: free the memory allocated for Handler_Get_Capability
 *  Input : char *pInData.
 *  Output: None
 *  Return: None
 * ***************************************************************************************/
void HANDLER_API Handler_MemoryFree(char *pInData)
{
	SampleHLog(Debug, "> %s Free Allocated Memory", strHandlerName);
 
	if(pInData)
	{
		free(pInData);
		pInData = NULL;
	}
	return;
}