diff --git a/apps/aqhome-data/0BUILD b/apps/aqhome-data/0BUILD index c98fe2f..3a818c7 100644 --- a/apps/aqhome-data/0BUILD +++ b/apps/aqhome-data/0BUILD @@ -45,6 +45,7 @@ c_getvalues.h c_getdatapoints.h c_getlastdatapoint.h + c_setdata.h @@ -59,6 +60,7 @@ c_getvalues.c c_getdatapoints.c c_getlastdatapoint.c + c_setdata.c main.c diff --git a/apps/aqhome-data/c_getdatapoints.c b/apps/aqhome-data/c_getdatapoints.c index 5e38b4a..a862e8d 100644 --- a/apps/aqhome-data/c_getdatapoints.c +++ b/apps/aqhome-data/c_getdatapoints.c @@ -15,6 +15,7 @@ #include "./aqhome_data_p.h" #include "aqhome/ipc/data/ipc_data.h" #include "aqhome/ipc/data/msg_data_datapoints.h" +#include "aqhome/ipc/endpoint_ipc.h" #include "aqhome/ipc/msg_ipc_result.h" #include @@ -48,68 +49,73 @@ void AqHomeData_HandleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, con GWEN_MSG *outMsg; int resultCode=0; - if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { - const char *valueName; - - valueName=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); - if (valueName) { - const AQH_VALUE *value; - - value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName); - if (value) { - uint64_t valueId; - uint32_t numValues; - uint64_t tsBegin=0; - uint64_t tsEnd=0; - uint64_t *tablePtr; - - valueId=AQH_Value_GetId(value); - - numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg); - if (numValues==1) { - const uint64_t *dataPoints; - - dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg); - tsBegin=dataPoints[0]; - tsEnd=dataPoints[1]; - } - - tablePtr=AQH_Storage_GetDataPoints(aqh->storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES); - if (tablePtr) { - int numTableEntries; - int numDataPoints; - - numTableEntries=(int)(tablePtr[0]); - numDataPoints=numTableEntries/2; - outMsg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP, AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG, - valueId, - AQH_Value_GetNameForSystem(value), - AQH_Value_GetValueUnits(value), - &(tablePtr[1]), numDataPoints); - GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); - free(tablePtr); - return; + if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) { + if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { + const char *valueName; + + valueName=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); + if (valueName) { + const AQH_VALUE *value; + + value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName); + if (value) { + uint64_t valueId; + uint32_t numValues; + uint64_t tsBegin=0; + uint64_t tsEnd=0; + uint64_t *tablePtr; + + valueId=AQH_Value_GetId(value); + + numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg); + if (numValues==1) { + const uint64_t *dataPoints; + + dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg); + tsBegin=dataPoints[0]; + tsEnd=dataPoints[1]; + } + + tablePtr=AQH_Storage_GetDataPoints(aqh->storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES); + if (tablePtr) { + int numTableEntries; + int numDataPoints; + + numTableEntries=(int)(tablePtr[0]); + numDataPoints=numTableEntries/2; + outMsg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP, AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG, + valueId, + AQH_Value_GetNameForSystem(value), + AQH_Value_GetValueUnits(value), + &(tablePtr[1]), numDataPoints); + GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); + free(tablePtr); + return; + } + else { + DBG_INFO(NULL, "No matching datapoints for value \"%s\"", valueName); + resultCode=AQH_MSG_IPC_ERROR_NODATA; + } } else { - DBG_INFO(NULL, "No matching datapoints for value \"%s\"", valueName); - resultCode=AQH_MSG_IPC_ERROR_NODATA; + DBG_INFO(NULL, "Value \"%s\" not found", valueName); + resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; } } else { - DBG_INFO(NULL, "Value \"%s\" not found", valueName); - resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; + DBG_INFO(NULL, "No value name in request"); + resultCode=AQH_MSG_IPC_ERROR_INVALID; } } else { - DBG_INFO(NULL, "No value name in request"); + DBG_INFO(NULL, "Invalid request message"); resultCode=AQH_MSG_IPC_ERROR_INVALID; } } else { - DBG_INFO(NULL, "Invalid request message"); - resultCode=AQH_MSG_IPC_ERROR_INVALID; + DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data"); + resultCode=AQH_MSG_IPC_ERROR_PERMS; } - outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode); GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); } diff --git a/apps/aqhome-data/c_getlastdatapoint.c b/apps/aqhome-data/c_getlastdatapoint.c index ed83f2a..8771b76 100644 --- a/apps/aqhome-data/c_getlastdatapoint.c +++ b/apps/aqhome-data/c_getlastdatapoint.c @@ -15,6 +15,7 @@ #include "./aqhome_data_p.h" #include "aqhome/ipc/data/ipc_data.h" #include "aqhome/ipc/data/msg_data_datapoints.h" +#include "aqhome/ipc/endpoint_ipc.h" #include "aqhome/ipc/msg_ipc_result.h" #include @@ -47,58 +48,63 @@ void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *outMsg; int resultCode=0; - if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { - const char *valueName; - - valueName=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); - if (valueName) { - const AQH_VALUE *value; - - value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName); - if (value) { - uint64_t valueId; - uint64_t timestamp=0; - union {double f; uint64_t i;} u; - int rv; - - valueId=AQH_Value_GetId(value); - rv=AQH_Storage_GetLastDataPoint(aqh->storage, valueId, ×tamp, &(u.f)); - if (rv<0) { - switch(rv) { - case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break; - case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break; - default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break; - } - } - else { - uint64_t array[2]; - - array[0]=timestamp; - array[1]=u.i; - outMsg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG, - valueId, - AQH_Value_GetNameForSystem(value), - AQH_Value_GetValueUnits(value), - array, 1); - GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); - return; - } + if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) { + if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { + const char *valueName; + + valueName=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); + if (valueName) { + const AQH_VALUE *value; + + value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName); + if (value) { + uint64_t valueId; + uint64_t timestamp=0; + union {double f; uint64_t i;} u; + int rv; + + valueId=AQH_Value_GetId(value); + rv=AQH_Storage_GetLastDataPoint(aqh->storage, valueId, ×tamp, &(u.f)); + if (rv<0) { + switch(rv) { + case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break; + case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break; + default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break; + } + } + else { + uint64_t array[2]; + + array[0]=timestamp; + array[1]=u.i; + outMsg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP, AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG, + valueId, + AQH_Value_GetNameForSystem(value), + AQH_Value_GetValueUnits(value), + array, 1); + GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); + return; + } + } + else { + DBG_INFO(NULL, "Value \"%s\" not found", valueName); + resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; + } } else { - DBG_INFO(NULL, "Value \"%s\" not found", valueName); - resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; + DBG_INFO(NULL, "No value name in request"); + resultCode=AQH_MSG_IPC_ERROR_INVALID; } } else { - DBG_INFO(NULL, "No value name in request"); + DBG_INFO(NULL, "Invalid request message"); resultCode=AQH_MSG_IPC_ERROR_INVALID; } } else { - DBG_INFO(NULL, "Invalid request message"); - resultCode=AQH_MSG_IPC_ERROR_INVALID; + DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data"); + resultCode=AQH_MSG_IPC_ERROR_PERMS; } - outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode); GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); } diff --git a/apps/aqhome-data/c_setdata.c b/apps/aqhome-data/c_setdata.c new file mode 100644 index 0000000..b67f434 --- /dev/null +++ b/apps/aqhome-data/c_setdata.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * 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 "./c_setdata.h" +#include "./aqhome_data_p.h" +#include "aqhome/ipc/data/ipc_data.h" +#include "aqhome/ipc/data/msg_data_datapoints.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/msg_ipc_result.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +void AqHomeData_HandleSetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg) +{ + GWEN_MSG *outMsg; + int resultCode=AQH_MSG_IPC_SUCCESS; + + if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_SETDATA) { + if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) { + uint32_t numValues; + + numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg); + if (numValues==1) { + const char *s; + + s=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg); + if (s && *s) { + AQH_VALUE *v; + + v=AQH_Storage_GetValueByNameForSystem(aqh->storage, s); + if (v==NULL) { + resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; + } + else { + const uint64_t *dataPoints; + + dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg); + if (dataPoints) { + const char *driverName; + + driverName=AQH_Value_GetDriver(v); + if (driverName && *driverName) { + GWEN_MSG_ENDPOINT *ep; + + ep=AqHomeData_GetIpcEndpointByServiceName(aqh, driverName); + if (ep) { + GWEN_MSG *driverMsg; + + DBG_INFO(AQH_LOGDOMAIN, "Sending SETDATA msg to driver endpoint (%s)", GWEN_MsgEndpoint_GetName(ep)); + driverMsg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_SETDATA, + 0, /* flags */ + AQH_Value_GetId(v), + AQH_Value_GetNameForDriver(v), + AQH_Value_GetValueUnits(v), + dataPoints, numValues); + GWEN_MsgEndpoint_AddSendMessage(ep, driverMsg); + } + else { + DBG_INFO(NULL, "Driver \"%s\" not available", driverName); + resultCode=AQH_MSG_IPC_ERROR_GENERIC; + } + } + else { + DBG_INFO(NULL, "No driver name"); + resultCode=AQH_MSG_IPC_ERROR_GENERIC; + } + } + else { + DBG_INFO(NULL, "No datapoints"); + resultCode=AQH_MSG_IPC_ERROR_BADDATA; + } + } + } + else { + DBG_INFO(NULL, "Value without name "); + resultCode=AQH_MSG_IPC_ERROR_INVALID; + } + } + else { + DBG_INFO(NULL, "Invalid number of datapoints"); + resultCode=AQH_MSG_IPC_ERROR_BADDATA; + } + } + else { + DBG_INFO(NULL, "Invalid message received"); + resultCode=AQH_MSG_IPC_ERROR_BADDATA; + } + } + else { + DBG_ERROR(AQH_LOGDOMAIN, "No permissions to set data"); + resultCode=AQH_MSG_IPC_ERROR_PERMS; + } + + outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode); + GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); +} + + + diff --git a/apps/aqhome-data/c_setdata.h b/apps/aqhome-data/c_setdata.h new file mode 100644 index 0000000..4780614 --- /dev/null +++ b/apps/aqhome-data/c_setdata.h @@ -0,0 +1,25 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQHOME_DATA_C_SETDATA_H +#define AQHOME_DATA_C_SETDATA_H + + +#include "./aqhome_data.h" + + +void AqHomeData_HandleSetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg); + + + +#endif + + + + + diff --git a/apps/aqhome-data/loop.c b/apps/aqhome-data/loop.c index 2834a84..48ae524 100644 --- a/apps/aqhome-data/loop.c +++ b/apps/aqhome-data/loop.c @@ -17,6 +17,7 @@ #include "./c_getdatapoints.h" #include "./c_getlastdatapoint.h" #include "./c_getvalues.h" +#include "./c_setdata.h" #include "./aqhome_data_p.h" #include "aqhome/ipc/data/ipc_data.h" #include "aqhome/ipc/data/msg_data_values.h" @@ -134,6 +135,7 @@ void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg) case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeData_HandleGetValues(aqh, ep, msg); break; case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: AqHomeData_HandleGetDataPoints(aqh, ep, msg); break; case AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ: AqHomeData_HandleGetLastDataPoint(aqh, ep, msg); break; + case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeData_HandleSetData(aqh, ep, msg); break; default: break; } } diff --git a/apps/aqhome-tool/data/0BUILD b/apps/aqhome-tool/data/0BUILD index c0876d6..055e792 100644 --- a/apps/aqhome-tool/data/0BUILD +++ b/apps/aqhome-tool/data/0BUILD @@ -37,6 +37,7 @@ adddata.h getdatapoints.h getlastdatapoint.h + setdata.h @@ -46,6 +47,7 @@ adddata.c getdatapoints.c getlastdatapoint.c + setdata.c diff --git a/apps/aqhome-tool/data/setdata.c b/apps/aqhome-tool/data/setdata.c new file mode 100644 index 0000000..5dc2d0d --- /dev/null +++ b/apps/aqhome-tool/data/setdata.c @@ -0,0 +1,280 @@ +/**************************************************************************** + * 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 "./setdata.h" +#include "../utils.h" + +#include "aqhome/msg/msg_node.h" +#include "aqhome/ipc/msg_ipc_result.h" +#include "aqhome/ipc/data/msg_data_datapoints.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 _doSetData(GWEN_DB_NODE *dbArgs); +static void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, const char *valueUnits, double dataToSend); + + + + +int AQH_Tool_SetData(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 */ + "tcpAddress", /* 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 */ + "tcpPort", /* 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 set (e.g. server/temp/system)"), + I18S("Name/path of the value to set (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 set (e.g. \"Grad Celsius\")"), + I18S("Units of the value to set (e.g. \"Grad Celsius\")") + }, + { + 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 set"), + I18S("Value to set") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "clientId", /* 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; + } + + return _doSetData(dbLocalArgs); +} + + + +int _doSetData(GWEN_DB_NODE *dbArgs) +{ + GWEN_MSG_ENDPOINT *epTcp; + int timeoutInSeconds; + const char *valueName; + const char *valueUnits; + const char *valueData; + double dataToSend; + GWEN_MSG *msg; + int rv; + + timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); + valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL); + valueUnits=GWEN_DB_GetCharValue(dbArgs, "valueUnits", 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; + } + + rv=GWEN_Text_StringToDouble(valueData, &dataToSend); + if (rv<0) { + DBG_ERROR(NULL, "ERROR: Invalid data"); + return 1; + } + + fprintf(stdout, "Sending SetData request\n"); + + + epTcp=Utils_OpenConnection(dbArgs, 0, timeoutInSeconds); + if (epTcp==NULL) { + DBG_ERROR(NULL, "ERROR creating TCP connection"); + return 2; + } + + _sendCommand(epTcp, valueName, valueUnits, 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, double dataToSend) +{ + GWEN_MSG *msgOut; + union {double f; uint64_t i;} u; + uint64_t arrayToSend[2]; + + u.f=dataToSend; + arrayToSend[0]=0; + arrayToSend[1]=u.i; + + msgOut=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_SETDATA, 0, 0, valueName, valueUnits, arrayToSend, 1); + GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); +} + + + + + + diff --git a/apps/aqhome-tool/data/setdata.h b/apps/aqhome-tool/data/setdata.h new file mode 100644 index 0000000..4cab83a --- /dev/null +++ b/apps/aqhome-tool/data/setdata.h @@ -0,0 +1,21 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQHOME_TOOL_SETDATA_H +#define AQHOME_TOOL_SETDATA_H + + +#include + + + +int AQH_Tool_SetData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv); + + +#endif + diff --git a/apps/aqhome-tool/main.c b/apps/aqhome-tool/main.c index 4605c6a..f175540 100644 --- a/apps/aqhome-tool/main.c +++ b/apps/aqhome-tool/main.c @@ -17,6 +17,7 @@ #include "./data/adddata.h" #include "./data/getdatapoints.h" #include "./data/getlastdatapoint.h" +#include "./data/setdata.h" #include #include @@ -77,6 +78,7 @@ int main(int argc, char **argv) GWEN_FE_DAH("adddata", AQH_Tool_AddDataPoint, I18N("Send a datapoint to the data server")), GWEN_FE_DAH("getdata", AQH_Tool_GetDataPoints, I18N("Request list of datapoints for a value on the data server")), GWEN_FE_DAH("getlastdata", AQH_Tool_GetLastDataPoint, I18N("Request last datapoint for a value on the data server")), + GWEN_FE_DAH("setdata", AQH_Tool_SetData, I18N("Set data for a value on the data server (e.g. a switch or thermostat)")), GWEN_FE_END(), }; const GWEN_FUNCS *func; diff --git a/aqhome/ipc/data/ipc_data.h b/aqhome/ipc/data/ipc_data.h index a46012c..83d8ee8 100644 --- a/aqhome/ipc/data/ipc_data.h +++ b/aqhome/ipc/data/ipc_data.h @@ -26,8 +26,7 @@ #define AQH_MSGTYPE_IPC_DATA_UPDATEDATA 0x100 /* AQH_DataPointsDataIpcMsg */ #define AQH_MSGTYPE_IPC_DATA_DATACHANGED 0x200 /* AQH_DataPointsDataIpcMsg */ -#define AQH_MSGTYPE_IPC_DATA_SETDATA_REQ 0x300 /* AQH_DataPointsDataIpcMsg */ -#define AQH_MSGTYPE_IPC_DATA_SETDATA_RSP 0x400 /* AQH_ResultIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_SETDATA 0x300 /* AQH_DataPointsDataIpcMsg */ #define AQH_MSGTYPE_IPC_DATA_GETDATA_REQ 0x500 /* AQH_DataPointsDataIpcMsg (1 pair: fromTime, toTime) */ #define AQH_MSGTYPE_IPC_DATA_GETDATA_RSP 0x600 /* AQH_DataPointsDataIpcMsg */ diff --git a/aqhome/ipc/endpoint_ipc.h b/aqhome/ipc/endpoint_ipc.h index 5f02504..4d0266a 100644 --- a/aqhome/ipc/endpoint_ipc.h +++ b/aqhome/ipc/endpoint_ipc.h @@ -24,6 +24,7 @@ #define AQH_IPCENDPOINT_PERMS_LISTDATA 0x0010 #define AQH_IPCENDPOINT_PERMS_READDATA 0x0020 #define AQH_IPCENDPOINT_PERMS_ADDDATA 0x0040 +#define AQH_IPCENDPOINT_PERMS_SETDATA 0x0080