Heavy work on IPC.

We will now have a broker (aqhome-data) which stores data and distributes
value change messages among connected clients.
aqhomed will connect to that broker and send its values there.
aqhome-mqtt will also connect to the broker and send its values there.
Other clients can later connect to check for changes and react according
to rules.
This commit is contained in:
Martin Preuss
2023-09-10 23:13:03 +02:00
parent 2b733a52ca
commit 518a3a53f9
43 changed files with 1412 additions and 707 deletions

View File

@@ -34,16 +34,16 @@
<headers dist="true" >
getvalues.h
addvalue.h
adddata.h
getdatapoints.h
</headers>
<sources>
$(local/typefiles)
getvalues.c
addvalue.c
adddata.c
getdatapoints.c
</sources>
<useTargets>

View File

@@ -101,11 +101,11 @@ int AQH_Tool_AddDataPoint(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"timestamp", /* name */
"timestamp", /* name */
0, /* minnum */
1, /* maxnum */
"t", /* short option */
"timestamp", /* long option */
"timestamp", /* long option */
I18S("Timestamp of the data (now if omitted)"),
I18S("Timestamp of the data (now if omitted)")
},
@@ -120,6 +120,39 @@ int AQH_Tool_AddDataPoint(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
I18S("Value to write"),
I18S("Value to write")
},
{
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 */
@@ -209,7 +242,7 @@ int _doAddData(GWEN_DB_NODE *dbArgs)
fprintf(stdout, "Sending AddData request\n");
epTcp=Utils_SetupIpcEndpoint(dbArgs);
epTcp=Utils_OpenConnection(dbArgs, 0, timeoutInSeconds);
if (epTcp==NULL) {
DBG_ERROR(NULL, "ERROR creating TCP connection");
return 2;
@@ -264,7 +297,7 @@ void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, const char *v
arrayToSend[0]=timestampToSend;
arrayToSend[1]=u.i;
msgOut=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_ADDDATAPOINTS_REQ, 0, 0, valueName, valueUnits, arrayToSend, 1);
msgOut=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA, 0, 0, valueName, valueUnits, arrayToSend, 1);
GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut);
}

View File

@@ -10,12 +10,12 @@
# include <config.h>
#endif
#include "./addvalue.h"
#include "./getdatapoints.h"
#include "../utils.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/ipc/data/msg_data_datapoints.h"
#include "aqhome/ipc/data/ipc_data.h"
#include <gwenhywfar/args.h>
@@ -31,13 +31,14 @@
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
static int _doAddValue(GWEN_DB_NODE *dbArgs);
static void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, const char *valueUnits);
static int _doGetDataPoints(GWEN_DB_NODE *dbArgs);
static void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, uint64_t tsBegin, uint64_t tsEnd);
static uint64_t _getTimeStampFromString(const char *s);
int AQH_Tool_AddValue(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
int AQH_Tool_GetDataPoints(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
GWEN_DB_NODE *dbLocalArgs;
int rv;
@@ -89,13 +90,57 @@ int AQH_Tool_AddValue(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"valueUnits", /* name */
"tsBegin", /* 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\")")
"tb", /* short option */
"tsbegin", /* long option */
I18S("Get data from this timestamp on (earliest timestamp if omitted)"),
I18S("Get data from this timestamp on (earliest timestamp if omitted)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"tsEnd", /* name */
0, /* minnum */
1, /* maxnum */
"te", /* short option */
"tsend", /* long option */
I18S("Get data up until this timestamp (latest timestamp if omitted)"),
I18S("Get data up until this timestamp (latest timestamp if omitted)")
},
{
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 */
@@ -132,59 +177,93 @@ int AQH_Tool_AddValue(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
return 0;
}
return _doAddValue(dbLocalArgs);
return _doGetDataPoints(dbLocalArgs);
}
int _doAddValue(GWEN_DB_NODE *dbArgs)
int _doGetDataPoints(GWEN_DB_NODE *dbArgs)
{
GWEN_MSG_ENDPOINT *epTcp;
int timeoutInSeconds;
const char *valueName;
const char *valueUnits;
GWEN_MSG *msg;
const char *valueName;
uint64_t tsBegin;
uint64_t tsEnd;
timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5);
valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL);
valueUnits=GWEN_DB_GetCharValue(dbArgs, "valueUnits", 0, NULL);
if (!(valueName && *valueName)) {
DBG_ERROR(NULL, "ERROR: Missing value name");
return 1;
tsBegin=_getTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsBegin", 0, NULL));
if (tsBegin==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad begin timestamp");
return 2;
}
tsEnd=_getTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsEnd", 0, NULL));
if (tsEnd==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad end timestamp");
return 2;
}
fprintf(stdout, "Sending AddValue request\n");
epTcp=Utils_SetupIpcEndpoint(dbArgs);
epTcp=Utils_OpenConnection(dbArgs, 0, timeoutInSeconds);
if (epTcp==NULL) {
DBG_ERROR(NULL, "ERROR creating TCP connection");
return 2;
}
_sendCommand(epTcp, valueName, valueUnits);
fprintf(stdout, "Sending GetDataPoints request\n");
_sendCommand(epTcp, valueName, tsBegin, tsEnd);
for (;;) {
uint16_t code;
msg=Utils_WaitForSpecificIpcMessage(epTcp, AQH_MSGTYPE_IPC_DATA_ADDVALUES_RSP, timeoutInSeconds);
msg=Utils_WaitForSpecificIpcMessage(epTcp, AQH_MSGTYPE_IPC_DATA_GETDATA_RSP, timeoutInSeconds);
if (msg==NULL) {
DBG_ERROR(NULL, "No response received");
return 2;
}
code=GWEN_IpcMsg_GetCode(msg);
if (code==AQH_MSGTYPE_IPC_DATA_ADDVALUES_RSP ||
code==AQH_MSGTYPE_IPC_DATA_RESULT) {
if (code==AQH_MSGTYPE_IPC_DATA_GETDATA_RSP) {
if (AQH_DataPointsDataIpcMsg_IsValid(msg)) {
const uint64_t *dataPoints;
const char *valueUnits;
uint32_t numValues;
uint32_t i;
dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(msg);
valueUnits=AQH_DataPointsDataIpcMsg_GetUnits(msg);
numValues=AQH_DataPointsDataIpcMsg_GetNumValues(msg);
for(i=0; i<numValues; i++) {
uint64_t timestamp;
union {double f; uint64_t i;} u;
timestamp=*(dataPoints++);
u.i=*(dataPoints++);
fprintf(stdout, "%lu\t%lf\t%s\n",
(unsigned long int) timestamp,
u.f,
valueUnits?valueUnits:"");
}
if (AQH_DataPointsDataIpcMsg_GetFlags(msg) & AQH_MSGDATA_DATAPOINTS_FLAGS_LASTMSG) {
DBG_INFO(NULL, "Last message received");
break;
}
}
else {
DBG_ERROR(NULL, "Invalid message received");
GWEN_MsgEndpoint_free(epTcp);
return 3;
}
}
else 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, "Value added.\n");
break;
}
fprintf(stderr, "ERROR: %d\n", resultCode);
GWEN_MsgEndpoint_free(epTcp);
return 3;
}
else {
DBG_INFO(NULL, "Unexpected message \"%d\"", code);
@@ -199,22 +278,34 @@ int _doAddValue(GWEN_DB_NODE *dbArgs)
void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, const char *valueUnits)
void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const char *valueName, uint64_t tsBegin, uint64_t tsEnd)
{
GWEN_MSG *msgOut;
AQH_VALUE *v;
uint64_t array[2];
v=AQH_Value_new();
AQH_Value_SetName(v, valueName);
AQH_Value_SetValueUnits(v, valueUnits);
array[0]=tsBegin;
array[1]=tsEnd;
msgOut=AQH_ValuesDataIpcMsg_newForOneValue(AQH_MSGTYPE_IPC_DATA_ADDVALUES_REQ, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, v);
msgOut=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDATA_REQ, 0, 0, valueName, NULL, array, 2);
GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut);
AQH_Value_free(v);
}
uint64_t _getTimeStampFromString(const char *s)
{
if (s && *s) {
unsigned long int x;
if (1!=sscanf("%lu", s, &x)) {
DBG_ERROR(NULL, "ERROR: Invalid timestamp");
return (uint64_t) (-1);
}
return (uint64_t) x;
}
return 0;
}

View File

@@ -6,15 +6,15 @@
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_TOOL_ADDVALUE_H
#define AQHOME_TOOL_ADDVALUE_H
#ifndef AQHOME_TOOL_GETDATAPOINTS_H
#define AQHOME_TOOL_GETDATAPOINTS_H
#include <gwenhywfar/db.h>
int AQH_Tool_AddValue(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
int AQH_Tool_GetDataPoints(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
#endif

View File

@@ -75,6 +75,39 @@ int AQH_Tool_GetValues(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
I18S("Specify timeout in seconds for response"),
I18S("Specify timeout in seconds for response")
},
{
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 */
@@ -121,14 +154,14 @@ int _doGetValues(GWEN_DB_NODE *dbArgs)
int timeoutInSeconds;
GWEN_MSG *msg;
epTcp=Utils_SetupIpcEndpoint(dbArgs);
timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5);
epTcp=Utils_OpenConnection(dbArgs, 0, timeoutInSeconds);
if (epTcp==NULL) {
DBG_ERROR(NULL, "ERROR creating TCP connection");
return 2;
}
timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5);
fprintf(stdout, "Sending GetValues request\n");
_sendCommand(epTcp);