From 68ee24621693f70aa55fd527a4eb43504d790cab Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Thu, 26 Jun 2025 00:18:05 +0200 Subject: [PATCH] aqhome-tool: added some commands - getFirstData - getLastData - getPeriodData --- apps/aqhome-tool/data/0BUILD | 6 + apps/aqhome-tool/data/getdatapoints.c | 49 +------- apps/aqhome-tool/data/getfirstdata.c | 153 +++++++++++++++++++++++ apps/aqhome-tool/data/getfirstdata.h | 21 ++++ apps/aqhome-tool/data/getlastdata.c | 153 +++++++++++++++++++++++ apps/aqhome-tool/data/getlastdata.h | 21 ++++ apps/aqhome-tool/data/getperioddata.c | 167 ++++++++++++++++++++++++++ apps/aqhome-tool/data/getperioddata.h | 21 ++++ apps/aqhome-tool/main.c | 8 +- apps/aqhome-tool/utils.c | 45 +++++++ apps/aqhome-tool/utils.h | 2 + aqhome/data/storage.c | 35 +----- 12 files changed, 605 insertions(+), 76 deletions(-) create mode 100644 apps/aqhome-tool/data/getfirstdata.c create mode 100644 apps/aqhome-tool/data/getfirstdata.h create mode 100644 apps/aqhome-tool/data/getlastdata.c create mode 100644 apps/aqhome-tool/data/getlastdata.h create mode 100644 apps/aqhome-tool/data/getperioddata.c create mode 100644 apps/aqhome-tool/data/getperioddata.h diff --git a/apps/aqhome-tool/data/0BUILD b/apps/aqhome-tool/data/0BUILD index 4af2354..359c2f9 100644 --- a/apps/aqhome-tool/data/0BUILD +++ b/apps/aqhome-tool/data/0BUILD @@ -37,6 +37,9 @@ getdevices.h adddata.h getdatapoints.h + getfirstdata.h + getlastdata.h + getperioddata.h setdata.h moddevice.h watch.h @@ -49,6 +52,9 @@ getdevices.c adddata.c getdatapoints.c + getfirstdata.c + getlastdata.c + getperioddata.c setdata.c moddevice.c watch.c diff --git a/apps/aqhome-tool/data/getdatapoints.c b/apps/aqhome-tool/data/getdatapoints.c index f4ebe4a..5e77bee 100644 --- a/apps/aqhome-tool/data/getdatapoints.c +++ b/apps/aqhome-tool/data/getdatapoints.c @@ -10,7 +10,7 @@ # include #endif -#include "./getvalues.h" +#include "./getdatapoints.h" #include "../client.h" #include "../utils.h" @@ -52,7 +52,6 @@ static AQH_MESSAGE *_createRequestMessage(AQH_OBJECT *o, uint32_t msgId); static int _handleResponseMessage(AQH_OBJECT *o, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, int first); static void _handleDataResponse(const GWEN_TAG16_LIST *tagList, int printMean, int printDiff); -static uint64_t _getTimeStampFromString(const char *s); @@ -110,12 +109,12 @@ AQH_MESSAGE *_createRequestMessage(GWEN_UNUSED AQH_OBJECT *o, uint32_t msgId) dbArgs=AQH_ToolClient_GetDbLocalArgs(o); valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL); num=GWEN_DB_GetIntValue(dbArgs, "numOfLastDatapoints", 0, 0); - tsBegin=_getTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsBegin", 0, NULL)); + tsBegin=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsBegin", 0, NULL)); if (tsBegin==(uint64_t) (-1)) { DBG_ERROR(NULL, "Bad begin timestamp"); return NULL; } - tsEnd=_getTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsEnd", 0, NULL)); + tsEnd=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsEnd", 0, NULL)); if (tsEnd==(uint64_t) (-1)) { DBG_ERROR(NULL, "Bad end timestamp"); return NULL; @@ -183,45 +182,3 @@ void _handleDataResponse(const GWEN_TAG16_LIST *tagList, int printMean, int prin -uint64_t _getTimeStampFromString(const char *s) -{ - if (s && *s) { - if (*s=='-') { - uint64_t x=0; - uint64_t now=time(NULL); - - s++; - while(*s && isdigit(*s)) { - unsigned int i; - - i=*(s++)-'0'; - x*=10; - x+=i; - } - if (*s) { - switch(*s) { - case 0: - case 'm': x*=60; break; - case 'h': x*=(60*60); break; - case 'd': x*=(60*60*24); break; - default: break; - } - } - return (now-x); - } - else { - unsigned long int x; - - if (1!=sscanf(s, "%lu", &x)) { - DBG_ERROR(NULL, "ERROR: Invalid timestamp"); - return (uint64_t) (-1); - } - return (uint64_t) x; - } - } - return 0; -} - - - - diff --git a/apps/aqhome-tool/data/getfirstdata.c b/apps/aqhome-tool/data/getfirstdata.c new file mode 100644 index 0000000..35f54c6 --- /dev/null +++ b/apps/aqhome-tool/data/getfirstdata.c @@ -0,0 +1,153 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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 "./getfirstdata.h" +#include "../utils.h" + +#include "aqhome/dataclient/client.h" +#include "aqhome/msg/ipc/m_ipc.h" +#include "aqhome/msg/ipc/m_ipc_result.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/data/m_ipcd_getdata.h" +#include "aqhome/msg/ipc/data/m_ipcd_multidata.h" +#include "aqhome/dataclient/client.h" + +#include +#include +#include +#include + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defs + * ------------------------------------------------------------------------------------------------ + */ + +#define I18S(msg) msg +#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) + +#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT +#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST) +#define A_CHAR GWEN_ArgsType_Char +#define A_INT GWEN_ArgsType_Int + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _runCommand(AQH_DATACLIENT *dc); + + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +int AQH_Tool_GetFirstData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) +{ + AQH_EVENT_LOOP *eventLoop; + AQH_DATACLIENT *dc; + int rv; + const GWEN_ARGS args[]= { + /* flags type name min max s long short_descr, long_descr */ + { A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL}, + { A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL}, + { A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL}, + { A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL}, + { A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL}, + { A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL}, + { A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL}, + { A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL}, + { 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL}, + { 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL}, + { A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL} + }; + + eventLoop=AQH_EventLoop_new(); + dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION); + + rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + rv=AQH_DataClient_ConnectWithArgs(dc, 0); + if (rv<0) { + DBG_ERROR(NULL, "Error connecting (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + rv=_runCommand(dc); + if (rv<0) { + DBG_ERROR(NULL, "Error running (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 0; +} + + + +int _runCommand(AQH_DATACLIENT *dc) +{ + GWEN_DB_NODE *dbLocalArgs; + const char *valueName; + uint64_t num; + int printMean; + int printDiff; + + dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc); + valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL); + num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1); + printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0); + printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0); + + if (num>0) { + uint64_t *dataPoints; + uint64_t recvdNum; + + dataPoints=malloc(num*sizeof(uint64_t)*2); + + recvdNum=AQH_DataClient_GetFirstData(dc, valueName, dataPoints, num); + if (recvdNum>0) { + if (printMean) + Utils_PrintMeanData(dataPoints, recvdNum, NULL); + else if (printDiff) + Utils_PrintDiffData(dataPoints, recvdNum, NULL); + else + Utils_PrintDataPoints(dataPoints, recvdNum, NULL); + } + free(dataPoints); + } + + return 0; +} + + + diff --git a/apps/aqhome-tool/data/getfirstdata.h b/apps/aqhome-tool/data/getfirstdata.h new file mode 100644 index 0000000..17f25e5 --- /dev/null +++ b/apps/aqhome-tool/data/getfirstdata.h @@ -0,0 +1,21 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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_GETFIRSTDATA_H +#define AQHOME_TOOL_GETFIRSTDATA_H + + +#include + + + +int AQH_Tool_GetFirstData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv); + + +#endif + diff --git a/apps/aqhome-tool/data/getlastdata.c b/apps/aqhome-tool/data/getlastdata.c new file mode 100644 index 0000000..d68fe2f --- /dev/null +++ b/apps/aqhome-tool/data/getlastdata.c @@ -0,0 +1,153 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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 "./getlastdata.h" +#include "../utils.h" + +#include "aqhome/dataclient/client.h" +#include "aqhome/msg/ipc/m_ipc.h" +#include "aqhome/msg/ipc/m_ipc_result.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/data/m_ipcd_getdata.h" +#include "aqhome/msg/ipc/data/m_ipcd_multidata.h" +#include "aqhome/dataclient/client.h" + +#include +#include +#include +#include + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defs + * ------------------------------------------------------------------------------------------------ + */ + +#define I18S(msg) msg +#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) + +#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT +#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST) +#define A_CHAR GWEN_ArgsType_Char +#define A_INT GWEN_ArgsType_Int + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _runCommand(AQH_DATACLIENT *dc); + + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +int AQH_Tool_GetLastData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) +{ + AQH_EVENT_LOOP *eventLoop; + AQH_DATACLIENT *dc; + int rv; + const GWEN_ARGS args[]= { + /* flags type name min max s long short_descr, long_descr */ + { A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL}, + { A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL}, + { A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL}, + { A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL}, + { A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL}, + { A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL}, + { A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL}, + { A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL}, + { 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL}, + { 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL}, + { A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL} + }; + + eventLoop=AQH_EventLoop_new(); + dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION); + + rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + rv=AQH_DataClient_ConnectWithArgs(dc, 0); + if (rv<0) { + DBG_ERROR(NULL, "Error connecting (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + rv=_runCommand(dc); + if (rv<0) { + DBG_ERROR(NULL, "Error running (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 0; +} + + + +int _runCommand(AQH_DATACLIENT *dc) +{ + GWEN_DB_NODE *dbLocalArgs; + const char *valueName; + uint64_t num; + int printMean; + int printDiff; + + dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc); + valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL); + num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1); + printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0); + printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0); + + if (num>0) { + uint64_t *dataPoints; + uint64_t recvdNum; + + dataPoints=malloc(num*sizeof(uint64_t)*2); + + recvdNum=AQH_DataClient_GetLastData(dc, valueName, dataPoints, num); + if (recvdNum>0) { + if (printMean) + Utils_PrintMeanData(dataPoints, recvdNum, NULL); + else if (printDiff) + Utils_PrintDiffData(dataPoints, recvdNum, NULL); + else + Utils_PrintDataPoints(dataPoints, recvdNum, NULL); + } + free(dataPoints); + } + + return 0; +} + + + diff --git a/apps/aqhome-tool/data/getlastdata.h b/apps/aqhome-tool/data/getlastdata.h new file mode 100644 index 0000000..40b7d86 --- /dev/null +++ b/apps/aqhome-tool/data/getlastdata.h @@ -0,0 +1,21 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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_GETLASTDATA_H +#define AQHOME_TOOL_GETLASTDATA_H + + +#include + + + +int AQH_Tool_GetLastData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv); + + +#endif + diff --git a/apps/aqhome-tool/data/getperioddata.c b/apps/aqhome-tool/data/getperioddata.c new file mode 100644 index 0000000..4fe2a0c --- /dev/null +++ b/apps/aqhome-tool/data/getperioddata.c @@ -0,0 +1,167 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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 "./getperioddata.h" +#include "../utils.h" + +#include "aqhome/dataclient/client.h" +#include "aqhome/msg/ipc/m_ipc.h" +#include "aqhome/msg/ipc/m_ipc_result.h" +#include "aqhome/msg/ipc/data/m_ipcd.h" +#include "aqhome/msg/ipc/data/m_ipcd_getdata.h" +#include "aqhome/msg/ipc/data/m_ipcd_multidata.h" +#include "aqhome/dataclient/client.h" + +#include +#include +#include +#include + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defs + * ------------------------------------------------------------------------------------------------ + */ + +#define I18S(msg) msg +#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) + +#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT +#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST) +#define A_CHAR GWEN_ArgsType_Char +#define A_INT GWEN_ArgsType_Int + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static int _runCommand(AQH_DATACLIENT *dc); + + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +int AQH_Tool_GetPeriodData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) +{ + AQH_EVENT_LOOP *eventLoop; + AQH_DATACLIENT *dc; + int rv; + const GWEN_ARGS args[]= { + /* flags type name min max s long short_descr, long_descr */ + { A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL}, + { A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL}, + { A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL}, + { A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL}, + { A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL}, + { A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL}, + { A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL}, + { A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL}, + { A_ARG, A_CHAR, "tsBegin", 0, 1, "tb", "tsbegin", I18S("Timestamp range begin"), NULL}, + { A_ARG, A_CHAR, "tsEnd", 0, 1, "te", "tsend", I18S("Timestamp range end"), NULL}, + { 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL}, + { 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL}, + { A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL} + }; + + eventLoop=AQH_EventLoop_new(); + dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION); + + rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + rv=AQH_DataClient_ConnectWithArgs(dc, 0); + if (rv<0) { + DBG_ERROR(NULL, "Error connecting (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + rv=_runCommand(dc); + if (rv<0) { + DBG_ERROR(NULL, "Error running (%d)", rv); + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 2; + } + + AQH_DataClient_free(dc); + AQH_EventLoop_free(eventLoop); + return 0; +} + + + +int _runCommand(AQH_DATACLIENT *dc) +{ + GWEN_DB_NODE *dbLocalArgs; + const char *valueName; + uint64_t num; + uint64_t tsBegin; + uint64_t tsEnd; + int printMean; + int printDiff; + + dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc); + valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL); + num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1); + tsBegin=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbLocalArgs, "tsBegin", 0, NULL)); + if (tsBegin==(uint64_t) (-1)) { + DBG_ERROR(NULL, "Bad begin timestamp"); + return 1; + } + tsEnd=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbLocalArgs, "tsEnd", 0, NULL)); + if (tsEnd==(uint64_t) (-1)) { + DBG_ERROR(NULL, "Bad end timestamp"); + return 1; + } + printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0); + printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0); + + if (num>0) { + uint64_t *dataPoints; + uint64_t recvdNum; + + dataPoints=malloc(num*sizeof(uint64_t)*2); + + recvdNum=AQH_DataClient_GetPeriodData(dc, valueName, dataPoints, num, tsBegin, tsEnd); + if (recvdNum>0) { + if (printMean) + Utils_PrintMeanData(dataPoints, recvdNum, NULL); + else if (printDiff) + Utils_PrintDiffData(dataPoints, recvdNum, NULL); + else + Utils_PrintDataPoints(dataPoints, recvdNum, NULL); + } + free(dataPoints); + } + + return 0; +} + + + diff --git a/apps/aqhome-tool/data/getperioddata.h b/apps/aqhome-tool/data/getperioddata.h new file mode 100644 index 0000000..77e7e0f --- /dev/null +++ b/apps/aqhome-tool/data/getperioddata.h @@ -0,0 +1,21 @@ +/**************************************************************************** + * This file is part of the project AqHome. + * AqHome (c) by 2025 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_GETPERIODDATA_H +#define AQHOME_TOOL_GETPERIODDATA_H + + +#include + + + +int AQH_Tool_GetPeriodData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv); + + +#endif + diff --git a/apps/aqhome-tool/main.c b/apps/aqhome-tool/main.c index a062873..a13cb83 100644 --- a/apps/aqhome-tool/main.c +++ b/apps/aqhome-tool/main.c @@ -1,6 +1,6 @@ /**************************************************************************** * This file is part of the project AqHome. - * AqHome (c) by 2023 Martin Preuss, all rights reserved. + * AqHome (c) by 2025 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. @@ -17,6 +17,9 @@ #include "./data/getdevices.h" #include "./data/adddata.h" #include "./data/getdatapoints.h" +#include "./data/getfirstdata.h" +#include "./data/getlastdata.h" +#include "./data/getperioddata.h" #include "./data/setdata.h" #include "./data/moddevice.h" #include "./data/watch.h" @@ -92,6 +95,9 @@ int main(int argc, char **argv) GWEN_FE_DAH("adddata", AQH_Tool_AddDataPoint, I18N("Send a datapoint to the data server")), GWEN_FE_DAH("addjsondata", AQH_Tool_AddDataPoint, I18N("(same as adddata)")), GWEN_FE_DAH("getdata", AQH_Tool_GetDataPoints, I18N("Request list of datapoints for a value on the data server")), + GWEN_FE_DAH("getfirstdata", AQH_Tool_GetFirstData, I18N("Request first datapoints for a value on the data server")), + GWEN_FE_DAH("getlastdata", AQH_Tool_GetLastData, I18N("Request last datapoints for a value on the data server")), + GWEN_FE_DAH("getperioddata", AQH_Tool_GetPeriodData, I18N("Request datapoints from a date range 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_DAH("moddevice", AQH_Tool_ModDevice, I18N("Modify a device on the data server")), GWEN_FE_DAH("watch", AQH_Tool_Watch, I18N("Watch and print changes of values on the data server")), diff --git a/apps/aqhome-tool/utils.c b/apps/aqhome-tool/utils.c index 9c9b718..5c7ddf1 100644 --- a/apps/aqhome-tool/utils.c +++ b/apps/aqhome-tool/utils.c @@ -19,6 +19,7 @@ #include "aqhome/msg/ipc/nodes/m_ipcn_setaccmsggrps.h" #include "aqhome/ipc2/tcp_object.h" #include "aqhome/ipc2/ipc_client.h" +#include "aqhome/dataclient/client.h" #include @@ -27,6 +28,7 @@ #include #include +#include #define UTILS_IPC_ENDPOINT_DEFAULT_MSGSIZE 4096 @@ -361,4 +363,47 @@ void Utils_PrintValue(const AQH_VALUE *value, int printHeader) +uint64_t Utils_GetTimeStampFromString(const char *s) +{ + if (s && *s) { + if (*s=='-') { + uint64_t x=0; + uint64_t now=time(NULL); + + s++; + while(*s && isdigit(*s)) { + unsigned int i; + + i=*(s++)-'0'; + x*=10; + x+=i; + } + if (*s) { + switch(*s) { + case 0: + case 'm': x*=60; break; + case 'h': x*=(60*60); break; + case 'd': x*=(60*60*24); break; + default: break; + } + } + return (now-x); + } + else { + unsigned long int x; + + if (1!=sscanf(s, "%lu", &x)) { + DBG_ERROR(NULL, "ERROR: Invalid timestamp"); + return (uint64_t) (-1); + } + return (uint64_t) x; + } + } + return 0; +} + + + + + diff --git a/apps/aqhome-tool/utils.h b/apps/aqhome-tool/utils.h index 125c31d..9c001bf 100644 --- a/apps/aqhome-tool/utils.h +++ b/apps/aqhome-tool/utils.h @@ -41,6 +41,8 @@ void Utils_PrintValue(const AQH_VALUE *value, int printHeader); AQH_DEVICE *Utils_DeviceFromArgs(GWEN_DB_NODE *dbArgs); +uint64_t Utils_GetTimeStampFromString(const char *s); + #endif diff --git a/aqhome/data/storage.c b/aqhome/data/storage.c index 70faf46..561cbf8 100644 --- a/aqhome/data/storage.c +++ b/aqhome/data/storage.c @@ -394,8 +394,8 @@ int AQH_Storage_AddDatapoint(AQH_STORAGE *sto, uint64_t valueId, uint64_t timest } - -uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t fromTime, uint64_t toTime, uint64_t maxArrayLen) +uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t fromTime, uint64_t toTime, + uint64_t maxDataPointsRequested) { AQH_DATAFILE *df; uint64_t numEntries; @@ -410,13 +410,9 @@ uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t return NULL; } numEntries=AQH_DataFile_GetNumberOfEntries(df); - if (fromTime==0 && toTime==0) - arrayLen=(numEntries*2)+1; - else - arrayLen=(AQH_STORAGE_DATAPOINTS_STEPS*2)+1; - if (arrayLen>maxArrayLen+1) - arrayLen=maxArrayLen+1; - + if (maxDataPointsRequested>numEntries) + maxDataPointsRequested=numEntries; + arrayLen=(maxDataPointsRequested*2)+1; arrayPtr=(uint64_t*) malloc(arrayLen*sizeof(uint64_t)); if (arrayPtr==NULL) { DBG_ERROR(AQH_LOGDOMAIN, "Not enough memory for %lu entries", (unsigned long int) arrayLen); @@ -438,30 +434,11 @@ uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t } if ((fromTime==0 || ts>=fromTime) && (toTime==0 || ts<=toTime)) { - if ((arrayPos+1)>maxArrayLen) { + if ((arrayPos+1)>arrayLen) { DBG_INFO(AQH_LOGDOMAIN, "Limit for number of returned entries reached"); break; } - if (arrayPos+1>=arrayLen) { - uint64_t newArrayLen; - void *p; - newArrayLen=arrayLen+(AQH_STORAGE_DATAPOINTS_STEPS*2); - if (newArrayLen>maxArrayLen+1) - newArrayLen=maxArrayLen+1; - if (newArrayLen==arrayLen) { - DBG_INFO(AQH_LOGDOMAIN, "Limit for number of returned entries reached"); - break; - } - p=realloc((void*) arrayPtr, newArrayLen*sizeof(uint64_t)); - if (p==NULL) { - DBG_ERROR(AQH_LOGDOMAIN, "Not enough memory for %lu entries", (unsigned long int) arrayLen+AQH_STORAGE_DATAPOINTS_STEPS); - free(arrayPtr); - return NULL; - } - arrayPtr=(uint64_t*) p; - arrayLen=newArrayLen; - } arrayPtr[arrayPos++]=ts; arrayPtr[arrayPos++]=u.i; }