/**************************************************************************** * This file is part of the project AqHome. * AqHome (c) by 2023 Martin Preuss, all rights reserved. * * The license for this file can be found in the file COPYING which you * should have received along with this file. ****************************************************************************/ #ifdef HAVE_CONFIG_H # include #endif #include "./adddata.h" #include "../utils.h" #include "aqhome/aqhome.h" #include "aqhome/msg/msg_node.h" #include "aqhome/ipc/msg_ipc_result.h" #include "aqhome/ipc/data/msg_data_multidata.h" #include "aqhome/ipc/data/ipc_data.h" #include #include #include #include #include #include #define I18S(msg) msg #define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) static int _doAddData(GWEN_DB_NODE *dbArgs); static void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, const char *valueUnits, const char *deviceName, uint64_t timestampToSend, double dataToSend); int AQH_Tool_AddDataPoint(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) { GWEN_DB_NODE *dbLocalArgs; int rv; const GWEN_ARGS args[]= { { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "brokerAddress", /* name */ 0, /* minnum */ 1, /* maxnum */ "t", /* short option */ "tcpaddress", /* long option */ I18S("Specify TCP address to connect to (defaults to 127.0.0.1)"), I18S("Specify TCP address to connect to (defaults to 127.0.0.1)") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Int, /* type */ "brokerPort", /* name */ 0, /* minnum */ 1, /* maxnum */ "P", /* short option */ "tcpport", /* long option */ I18S("Specify the TCP port to listen on"), I18S("Specify the TCP port to listen on") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Int, /* type */ "timeout", /* name */ 0, /* minnum */ 1, /* maxnum */ "T", /* short option */ NULL, /* long option */ I18S("Specify timeout in seconds for response"), I18S("Specify timeout in seconds for response") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "valueName", /* name */ 1, /* minnum */ 1, /* maxnum */ "N", /* short option */ "valuename", /* long option */ I18S("Name/path of the value to add (e.g. server/temp/system)"), I18S("Name/path of the value to add (e.g. server/temp/system)") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "valueUnits", /* name */ 0, /* minnum */ 1, /* maxnum */ "U", /* short option */ "valueunits", /* long option */ I18S("Units of the value to add (e.g. \"Grad Celsius\")"), I18S("Units of the value to add (e.g. \"Grad Celsius\")") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "timestamp", /* name */ 0, /* minnum */ 1, /* maxnum */ "t", /* short option */ "timestamp", /* long option */ I18S("Timestamp of the data (now if omitted)"), I18S("Timestamp of the data (now if omitted)") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "value", /* name */ 1, /* minnum */ 1, /* maxnum */ "v", /* short option */ "value", /* long option */ I18S("Value to write"), I18S("Value to write") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "device", /* name */ 1, /* minnum */ 1, /* maxnum */ "d", /* short option */ "device", /* long option */ I18S("device name"), I18S("device name") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "brokerClientId", /* name */ 0, /* minnum */ 1, /* maxnum */ "c", /* short option */ "clientid", /* long option */ I18S("Specify CLIENTID"), I18S("Specify CLIENTID") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "userId", /* name */ 0, /* minnum */ 1, /* maxnum */ "u", /* short option */ "userid", /* long option */ I18S("Specify user id"), I18S("Specify user id") }, { GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ GWEN_ArgsType_Char, /* type */ "password", /* name */ 0, /* minnum */ 1, /* maxnum */ "p", /* short option */ "password", /* long option */ I18S("Specify service password"), I18S("Specify service password") }, { GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ GWEN_ArgsType_Int, /* type */ "help", /* name */ 0, /* minnum */ 0, /* maxnum */ "h", /* short option */ "help", /* long option */ "Show this help screen", /* short description */ "Show this help screen" /* long description */ } }; dbLocalArgs=GWEN_DB_GetGroup(dbGlobalArgs, GWEN_DB_FLAGS_DEFAULT, "local"); rv=GWEN_Args_Check(argc, argv, 1, GWEN_ARGS_MODE_ALLOW_FREEPARAM, args, dbLocalArgs); if (rv==GWEN_ARGS_RESULT_ERROR) { fprintf(stderr, "ERROR: Could not parse arguments\n"); return 1; } else if (rv==GWEN_ARGS_RESULT_HELP) { GWEN_BUFFER *ubuf; ubuf=GWEN_Buffer_new(0, 1024, 0, 1); if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) { fprintf(stderr, "ERROR: Could not create help string\n"); return 1; } fprintf(stderr, "%s\n", GWEN_Buffer_GetStart(ubuf)); GWEN_Buffer_free(ubuf); return 0; } AQH_MergeConfigFileIntoConfig(dbLocalArgs, "ConfigFile"); return _doAddData(dbLocalArgs); } int _doAddData(GWEN_DB_NODE *dbArgs) { GWEN_MSG_ENDPOINT *epTcp; int timeoutInSeconds; const char *valueName; const char *deviceName; const char *valueUnits; const char *valueTimestamp; const char *valueData; uint64_t timestampToSend; double dataToSend; GWEN_MSG *msg; int rv; timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); deviceName=GWEN_DB_GetCharValue(dbArgs, "device", 0, NULL); valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL); valueUnits=GWEN_DB_GetCharValue(dbArgs, "valueUnits", 0, NULL); valueTimestamp=GWEN_DB_GetCharValue(dbArgs, "timestamp", 0, NULL); valueData=GWEN_DB_GetCharValue(dbArgs, "value", 0, NULL); if (!(valueName && *valueName)) { DBG_ERROR(NULL, "ERROR: Missing value name"); return 1; } if (!(valueData && *valueData)) { DBG_ERROR(NULL, "ERROR: Missing data"); return 1; } if (valueTimestamp && *valueTimestamp) { unsigned long int x; if (1!=sscanf("%lu", valueTimestamp, &x)) { DBG_ERROR(NULL, "ERROR: Invalid timestamp"); return 1; } timestampToSend=(uint64_t) x; } else timestampToSend=(uint64_t) time(NULL); rv=GWEN_Text_StringToDouble(valueData, &dataToSend); if (rv<0) { DBG_ERROR(NULL, "ERROR: Invalid data"); return 1; } /*fprintf(stdout, "Sending AddData request\n");*/ epTcp=Utils_SetupBrokerClientEndpoint(dbArgs, 0); if (epTcp==NULL) { DBG_ERROR(NULL, "ERROR creating TCP connection"); return 2; } _sendCommand(epTcp, valueName, valueUnits, deviceName, timestampToSend, dataToSend); for (;;) { uint16_t code; msg=Utils_WaitForSpecificIpcMessage(epTcp, AQH_MSGTYPE_IPC_DATA_RESULT, timeoutInSeconds); if (msg==NULL) { DBG_ERROR(NULL, "No response received"); return 2; } code=GWEN_IpcMsg_GetCode(msg); if (code==AQH_MSGTYPE_IPC_DATA_RESULT) { uint32_t resultCode; resultCode=AQH_ResultIpcMsg_GetResultCode(msg); if (resultCode!=AQH_MSG_IPC_SUCCESS) { fprintf(stderr, "ERROR: %d\n", resultCode); GWEN_MsgEndpoint_free(epTcp); return 3; } else { /*fprintf(stdout, "Data added.\n");*/ break; } } else { DBG_INFO(NULL, "Unexpected message \"%d\"", code); GWEN_MsgEndpoint_free(epTcp); return 3; } } /* for */ GWEN_MsgEndpoint_free(epTcp); return 0; } void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, const char *valueUnits, const char *deviceName, uint64_t timestampToSend, double dataToSend) { GWEN_MSG *msgOut; union {double f; uint64_t i;} u; uint64_t arrayToSend[2]; AQH_VALUE *value; u.f=dataToSend; arrayToSend[0]=timestampToSend; arrayToSend[1]=u.i; value=AQH_Value_new(); AQH_Value_SetName(value, valueName); AQH_Value_SetValueUnits(value, valueUnits); AQH_Value_SetDeviceName(value, deviceName); msgOut=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA, value, arrayToSend, 1); AQH_Value_free(value); GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); }