From 9fec57511a36b05bdcf29b0c899413a70441d3cb Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Tue, 21 Oct 2025 23:42:11 +0200 Subject: [PATCH] moved code for device module into its own folder. Implement graphs. --- apps/aqhome-cgi/0BUILD | 3 + apps/aqhome-cgi/main.c | 41 +- apps/aqhome-cgi/modules/0BUILD | 4 +- apps/aqhome-cgi/modules/common/mservice.c | 8 +- apps/aqhome-cgi/modules/common/mservice.h | 4 + apps/aqhome-cgi/modules/devices/0BUILD | 93 ++ apps/aqhome-cgi/modules/devices/mdevices.c | 303 ++++++ .../modules/{ => devices}/mdevices.h | 4 + .../modules/devices/mdevices_index.c | 110 +++ .../modules/devices/mdevices_index.h | 27 + .../modules/devices/mdevices_init.c | 129 +++ .../modules/devices/mdevices_init.h | 27 + .../modules/devices/mdevices_setdata.c | 202 ++++ .../modules/devices/mdevices_setdata.h | 27 + .../modules/devices/mdevices_value.c | 245 +++++ .../modules/devices/mdevices_value.h | 27 + .../modules/devices/mdevices_values.c | 145 +++ .../modules/devices/mdevices_values.h | 27 + .../modules/devices/mdevices_vgraph.c | 464 ++++++++++ .../modules/devices/mdevices_vgraph.h | 27 + apps/aqhome-cgi/modules/mdevices.c | 873 ------------------ apps/aqhome-cgi/modules/mroot.c | 2 +- apps/aqhome-cgi/service/service.c | 61 +- apps/aqhome-cgi/service/service.h | 7 +- apps/aqhome-cgi/service/service_p.h | 5 + apps/aqhome-cgi/service_file.c | 8 +- apps/aqhome-cgi/service_file.h | 2 +- apps/aqhome-cgi/service_file_p.h | 3 +- 28 files changed, 1979 insertions(+), 899 deletions(-) create mode 100644 apps/aqhome-cgi/modules/devices/0BUILD create mode 100644 apps/aqhome-cgi/modules/devices/mdevices.c rename apps/aqhome-cgi/modules/{ => devices}/mdevices.h (86%) create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_index.c create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_index.h create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_init.c create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_init.h create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_setdata.c create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_setdata.h create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_value.c create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_value.h create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_values.c create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_values.h create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_vgraph.c create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_vgraph.h delete mode 100644 apps/aqhome-cgi/modules/mdevices.c diff --git a/apps/aqhome-cgi/0BUILD b/apps/aqhome-cgi/0BUILD index 12c94a1..2f65c35 100644 --- a/apps/aqhome-cgi/0BUILD +++ b/apps/aqhome-cgi/0BUILD @@ -8,6 +8,7 @@ $(gwenhywfar_cflags) $(aqcgi_cflags) + $(aqdiagram_cflags) -I$(topsrcdir) -I$(topbuilddir) -I$(topsrcdir)/apps @@ -58,6 +59,7 @@ $(gwenhywfar_libs) -lm $(aqcgi_libs) + $(aqdiagram_libs) @@ -127,6 +129,7 @@ $(gwenhywfar_libs) -lm $(aqcgi_libs) + $(aqdiagram_libs) diff --git a/apps/aqhome-cgi/main.c b/apps/aqhome-cgi/main.c index 096f7f6..b9e52c9 100644 --- a/apps/aqhome-cgi/main.c +++ b/apps/aqhome-cgi/main.c @@ -5,11 +5,12 @@ #include "aqhome-cgi/modules/common/madmin.h" #include "aqhome-cgi/modules/common/mmodules.h" #include "aqhome-cgi/modules/common/musers.h" -#include "aqhome-cgi/modules/mdevices.h" +#include "aqhome-cgi/modules/devices/mdevices.h" #include "aqhome/aqhome.h" #include #include +#include #include #include @@ -26,21 +27,34 @@ #define AQHOME_CGI_DEFAULT_STATIC_FILES AQHOME_CGI_WWWDIR"/static" #define AQHOME_CGI_DEFAULT_RUNTIME_FILES AQHOME_CGI_WWWDIR"/data" +#define AQHOME_CGI_DEFAULT_CACHE_FILES AQHOME_CGI_WWWDIR"/cache" +#define AQHOME_CGI_DEFAULT_BASE_URL "http://127.0.0.1/aqbt" -static void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles); +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles, const char *sBaseUrl); static int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles); static void logStart(void); -static int _init(const char *sPathRuntimeFiles); +static int _init(const char *sPathRuntimeFiles, const char *sBaseUrl); +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + int main(int argc, char **argv) { GWEN_GUI *gui; const char *sPathStaticFiles; const char *sPathRuntimeFiles; + const char *sBaseUrl; sPathStaticFiles=getenv("AQHOME_STATIC_FILES"); if (!(sPathStaticFiles && *sPathStaticFiles)) @@ -50,6 +64,10 @@ int main(int argc, char **argv) if (!(sPathRuntimeFiles && *sPathRuntimeFiles)) sPathRuntimeFiles=AQHOME_CGI_DEFAULT_RUNTIME_FILES; + sBaseUrl=getenv("AQHOME_BASE_URL"); + if (!(sBaseUrl && *sBaseUrl)) + sBaseUrl=AQHOME_CGI_DEFAULT_BASE_URL; + GWEN_Init(); gui=GWEN_NoGui_new(); GWEN_Gui_SetGui(gui); @@ -58,6 +76,7 @@ int main(int argc, char **argv) GWEN_Logger_Open(GWEN_LOGDOMAIN, "gwenhywfar", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); GWEN_Logger_Open(AQH_LOGDOMAIN, "aqhome", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); GWEN_Logger_Open(AQCGI_LOGDOMAIN, "aqcgi", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); + GWEN_Logger_Open(AQDG_LOGDOMAIN, "aqdiagram", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); GWEN_Logger_Open(NULL, "aqhome-cgi", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon); GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Debug); @@ -69,13 +88,14 @@ int main(int argc, char **argv) GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Debug); GWEN_Logger_SetLevel(AQCGI_LOGDOMAIN, GWEN_LoggerLevel_Debug); + GWEN_Logger_SetLevel(AQDG_LOGDOMAIN, GWEN_LoggerLevel_Debug); GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Debug); if (argc>1 && argv[1]) { if (0==strcasecmp(argv[1], "init")) { int rv; - rv=_init(sPathRuntimeFiles); + rv=_init(sPathRuntimeFiles, sBaseUrl); if (rv<0) { fprintf(stderr, "Error on init (%d)\n", rv); return 2; @@ -90,7 +110,7 @@ int main(int argc, char **argv) AQCGI_Init(); rq=AQCGI_ReadRequest(); if (rq) { - _handleRequest(rq, sPathStaticFiles, sPathRuntimeFiles); + _handleRequest(rq, sPathStaticFiles, sPathRuntimeFiles, sBaseUrl); } else { fprintf(stdout, "Content-type: text/plain\n\n"); @@ -104,12 +124,12 @@ int main(int argc, char **argv) -void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles) +void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles, const char *sBaseUrl) { AQH_SERVICE *sv; int rv; - sv=AQH_ServiceFiles_new(sPathRuntimeFiles); + sv=AQH_ServiceFiles_new(sPathRuntimeFiles, sBaseUrl); rv=_handlePath(sv, rq, sPathStaticFiles); if (rv<0) { @@ -160,6 +180,7 @@ int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles int rv; /* last, let module handle remaining part */ + DBG_ERROR(NULL, "Entry: %s (last)", s); rv=AQH_ModService_HandleRequest(mParent, rq, session, s); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); @@ -199,13 +220,13 @@ void logStart() -int _init(const char *sPathRuntimeFiles) +int _init(const char *sPathRuntimeFiles, const char *sBaseUrl) { AQH_SERVICE *sv; int rv; - fprintf(stdout, "Creating aqhome-cgi environment in \"%s\"\n", sPathRuntimeFiles); - sv=AQH_ServiceFiles_new(sPathRuntimeFiles); + DBG_ERROR(NULL, "Creating aqhome-cgi environment in \"%s\"", sPathRuntimeFiles); + sv=AQH_ServiceFiles_new(sPathRuntimeFiles, sBaseUrl); rv=AQH_ModAdmin_Create(sv); if (rv<0) { DBG_ERROR(NULL, "Error creating module \"admin\""); diff --git a/apps/aqhome-cgi/modules/0BUILD b/apps/aqhome-cgi/modules/0BUILD index 2cd35ae..435afe9 100644 --- a/apps/aqhome-cgi/modules/0BUILD +++ b/apps/aqhome-cgi/modules/0BUILD @@ -50,7 +50,6 @@ mdataclient.h - mdevices.h mroot.h @@ -64,7 +63,6 @@ $(local/typefiles) mdataclient.c - mdevices.c mroot.c @@ -75,10 +73,12 @@ aqhcgi_modcom + aqhcgi_mdevices common + devices static diff --git a/apps/aqhome-cgi/modules/common/mservice.c b/apps/aqhome-cgi/modules/common/mservice.c index 0ae0754..f4df10f 100644 --- a/apps/aqhome-cgi/modules/common/mservice.c +++ b/apps/aqhome-cgi/modules/common/mservice.c @@ -518,9 +518,13 @@ void AQH_ModService_HandleRequestWithTable(AQH_MODULE *m, } } - AQH_ModService_AddFooter(m, "en", dbuf); + if (!(AQCGI_Request_GetFlags(rq) & AQH_MODSERVICE_RQFLAGS_RAWFILE)) { + DBG_ERROR(NULL, "Not adding footer"); + AQH_ModService_AddFooter(m, "en", dbuf); + } AQCGI_Request_SetBufferResponseBody(rq, dbuf); - AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html"); + if (AQCGI_Request_GetFlags(rq) & AQCGI_FLAGS_HAS_CONTENT_HEADER) + AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html"); } diff --git a/apps/aqhome-cgi/modules/common/mservice.h b/apps/aqhome-cgi/modules/common/mservice.h index 3cd1b76..8a578ce 100644 --- a/apps/aqhome-cgi/modules/common/mservice.h +++ b/apps/aqhome-cgi/modules/common/mservice.h @@ -18,6 +18,10 @@ #include +#define AQH_MODSERVICE_RQFLAGS_RAWFILE 0x10000000 + + + typedef int (*AQH_MODSERVICE_HANDLEREQUEST_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem); typedef AQH_MODULE* (*AQH_MODSERVICE_LOADSUBMODULE_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName); typedef void (*AQH_MODSERVICE_ADDHEADER_FN)(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf); diff --git a/apps/aqhome-cgi/modules/devices/0BUILD b/apps/aqhome-cgi/modules/devices/0BUILD new file mode 100644 index 0000000..53af1bf --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/0BUILD @@ -0,0 +1,93 @@ + + + + + + + + $(gwenhywfar_cflags) + $(aqcgi_cflags) + $(aqdiagram_cflags) + -I$(topsrcdir) + -I$(topbuilddir) + -I$(topsrcdir)/apps + -I$(topbuilddir)/apps + -I$(builddir) + -I$(srcdir) + + + + --include=$(builddir) + --include=$(srcdir) + + + + + + $(visibility_cflags) + + + + --api=AQHOME_API + + + + + + + + + + + + + + + + + + $(local/built_headers_pub) + + + + + mdevices.h + mdevices_init.h + mdevices_index.h + mdevices_values.h + mdevices_value.h + mdevices_setdata.h + mdevices_vgraph.h + + + + + + + + + $(local/typefiles) + + mdevices.c + mdevices_init.c + mdevices_index.c + mdevices_values.c + mdevices_value.c + mdevices_setdata.c + mdevices_vgraph.c + + + + + + + + + + + + + + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices.c b/apps/aqhome-cgi/modules/devices/mdevices.c new file mode 100644 index 0000000..e2c60cd --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices.c @@ -0,0 +1,303 @@ +/**************************************************************************** + * 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 "./mdevices.h" + +#include "aqhome-cgi/modules/devices/mdevices_index.h" +#include "aqhome-cgi/modules/devices/mdevices_values.h" +#include "aqhome-cgi/modules/devices/mdevices_value.h" +#include "aqhome-cgi/modules/devices/mdevices_setdata.h" +#include "aqhome-cgi/modules/devices/mdevices_vgraph.h" +#include "aqhome-cgi/service/module.h" +#include "aqhome-cgi/modules/mdataclient.h" + +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +#define GBAS GWEN_Buffer_AppendString +#define GBAA GWEN_Buffer_AppendArgs + +#define P_DEVICEREAD AQH_MODDEVICES_PERMS_DEVICEREAD +#define P_VALUEREAD AQH_MODDEVICES_PERMS_VALUEREAD +#define P_VALUEWRITE AQH_MODDEVICES_PERMS_VALUEWRITE + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName); +static int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem); + +static void _handleRqIndexGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); +static void _handleRqValuesGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); +static void _handleRqValueGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); +static void _handleRqSetDataPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); +static void _handleRqGraphGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); + +static void _addValueActionToForm(const AQH_VALUE *value, GWEN_BUFFER *dbuf); +static void _addLastValueToForm(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER *dbuf); + + + +/* ------------------------------------------------------------------------------------------------ + * vars + * ------------------------------------------------------------------------------------------------ + */ + +static AQH_MODSERVICE_HANDLER_ENTRY _requestTable[]={ + {"index.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD, _handleRqIndexGet}, + {"values.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqValuesGet}, + {"value.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqValueGet}, + {"setdata.html", AQCGI_REQUEST_METHOD_POST, P_VALUEWRITE, _handleRqSetDataPost}, + {"graph.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqGraphGet}, + {NULL, 0, 0, NULL} +}; + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_ModDevices_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder) +{ + AQH_ModService_Extend(m, sv, baseFolder); + AQH_ModService_SetHandleRequestFn(m, _handleRequest); + AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule); +} + + + +AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName) +{ + return NULL; +} + + + +int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem) +{ + AQH_ModService_HandleRequestWithTable(m, rq, session, sLastPathElem, _requestTable); + return AQCGI_SendResponse(rq); +} + + + +void _handleRqIndexGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) +{ + AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunIndex, dbuf); +} + + + +void _handleRqValuesGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) +{ + AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunValues, dbuf); +} + + + +void _handleRqValueGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) +{ + AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunValue, dbuf); +} + + + +void _handleRqSetDataPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) +{ + AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunSetData, dbuf); +} + + + +void _handleRqGraphGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) +{ + AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunGraphValue, dbuf); +} + + + + + + + + + + +uint32_t AQH_ModDevices_ColorFromHexString(const char *s) +{ + uint32_t colorIn=0; + + while(*s && *s<33) + s++; + if (*s=='#') + s++; + while(*s) { + uint c; + + c=(*s)-'0'; + if (c>9) + c-=7; + colorIn<<=4; + colorIn|=c & 0xf; + s++; + } + + /* hex 00RRGGBB -> GGRRWWBB */ + //return _htmlColorToValueRGBW(colorIn); + return colorIn; +} + + + +uint32_t AQH_ModDevices_HtmlColorToValueRGBW(uint32_t colorIn) +{ + uint32_t colorOut; + /* hex 00RRGGBB -> GGRRWWBB */ + /* RGBW GGRRWWBB GGRRWWBB GGRRWWBB */ + /* html 00RRGGBB 00RRGGBB 00RRGGBB*/ + colorOut=(colorIn & 0x00ff0000) | ((colorIn<<16) & 0xff000000) | (colorIn & 0x000000ff); + return colorOut; +} + + + +uint32_t AQH_ModDevices_RgbwToHtmlColor(uint32_t colorIn) +{ + uint32_t colorOut; + /* RGBW GGRRWWBB GGRRWWBB GGRRWWBB */ + /* hex 00RRGGBB 00RRGGBB 00RRGGBB*/ + colorOut=(colorIn & 0x00ff0000) | ( (colorIn>>16) & 0x0000ff00) | (colorIn & 0x000000ff); + return colorOut; +} + + + +void _addValueActionToForm(const AQH_VALUE *value, GWEN_BUFFER *dbuf) +{ + const char *sValueName; + + sValueName=AQH_Value_GetName(value); + switch(AQH_Value_GetModality(value)) { + case AQH_ValueModality_RGBW: + GBAA(dbuf, "", sValueName); + break; + case AQH_ValueModality_OnOff: + GBAA(dbuf, + "", + sValueName); + break; + case AQH_ValueModality_OnOffAuto: + GBAA(dbuf, + "", + sValueName); + break; + default: + break; + } +} + + + +void _addLastValueToForm(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER *dbuf) +{ + const char *sValueSystemName; + const char *sValueName; + uint64_t dataPoints[2]; + uint64_t recvdNum; +// uint64_t timestamp; + union {double f; uint64_t i;} u; + int intVal; + + sValueSystemName=AQH_Value_GetNameForSystem(value); + sValueName=AQH_Value_GetName(value); + recvdNum=AQH_DataClient_GetLastData(dc, sValueSystemName, &dataPoints[0], 1); + if (recvdNum>0) { +// timestamp=dataPoints[0]; + u.i=dataPoints[1]; + intVal=(int) u.f; + } + else { + u.i=0; + intVal=-1; + } + + if (AQH_Value_GetValueType(value)==AQH_ValueType_Actor) { + DBG_ERROR(NULL, "Adding actor"); + switch(AQH_Value_GetModality(value)) { + case AQH_ValueModality_RGBW: + DBG_ERROR(NULL, "Color: %.f RGBW=%08x HTML=%08x, RGBW2=%08x", + u.f, + (uint32_t) (u.f), + AQH_ModDevices_RgbwToHtmlColor(u.f), + AQH_ModDevices_HtmlColorToValueRGBW(AQH_ModDevices_RgbwToHtmlColor(u.f))); +#if 1 + GBAA(dbuf, "", sValueName, (uint32_t) (u.f)); +#else + GBAA(dbuf, "#%08x (#%08x)", + sValueName, + _rgbwToHtmlColor((unsigned int) (u.f)), + _rgbwToHtmlColor((unsigned int) (u.f)), + (uint32_t) (u.f)); +#endif + break; + case AQH_ValueModality_OnOff: + GBAA(dbuf, ""); + break; + case AQH_ValueModality_OnOffAuto: + GBAA(dbuf, ""); + break; + default: + // GBAA(dbuf, "", sValueName, u.f); + GBAA(dbuf, "%.2f", u.f); + break; + } /* switch */ + } /* if actor */ + else { + DBG_ERROR(NULL, "Adding sensor (%s=%.2f)", sValueName, u.f); + GBAA(dbuf, "%.2f", u.f); + } +} + + + + diff --git a/apps/aqhome-cgi/modules/mdevices.h b/apps/aqhome-cgi/modules/devices/mdevices.h similarity index 86% rename from apps/aqhome-cgi/modules/mdevices.h rename to apps/aqhome-cgi/modules/devices/mdevices.h index 0c1205f..48cc2f1 100644 --- a/apps/aqhome-cgi/modules/mdevices.h +++ b/apps/aqhome-cgi/modules/devices/mdevices.h @@ -37,6 +37,10 @@ void AQH_ModDevices_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolde int AQH_ModDevices_Create(AQH_SERVICE *sv); +uint32_t AQH_ModDevices_ColorFromHexString(const char *s); +uint32_t AQH_ModDevices_HtmlColorToValueRGBW(uint32_t colorIn); +uint32_t AQH_ModDevices_RgbwToHtmlColor(uint32_t colorIn); + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_index.c b/apps/aqhome-cgi/modules/devices/mdevices_index.c new file mode 100644 index 0000000..d460c69 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_index.c @@ -0,0 +1,110 @@ +/**************************************************************************** + * 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 "./mdevices_index.h" + +#include "aqhome-cgi/service/module.h" +#include "aqhome-cgi/modules/mdataclient.h" + +#include +#include +#include + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +#define GBAS GWEN_Buffer_AppendString +#define GBAA GWEN_Buffer_AppendArgs + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) +{ + AQH_DEVICE_LIST *deviceList; + AQH_DEVICE *device; + uint32_t perms; + + perms=AQH_ModService_GetUserPerms(m); + + deviceList=AQH_DataClient_GetDevices(dc, NULL); + if (deviceList==NULL) { + DBG_ERROR(NULL, "No device received"); + GBAS(dbuf, "

No devices.

"); + return; + } + + GBAS(dbuf, "

Devices

\n"); + GBAS(dbuf, + "\n" + "\n" + "" + "" + "" + "" + "" + "\n" + "\n" + "\n"); + + device=AQH_Device_List_First(deviceList); + while(device) { + const char *s; + + GBAA(dbuf, ""); + /* name for system */ + s=AQH_Device_GetNameForSystem(device); + if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) { + GBAS(dbuf,"", s?s:""); + } + else + GBAA(dbuf,"", s?s:""); + /* room */ + s=AQH_Device_GetRoomName(device); + GBAA(dbuf, "", s?s:""); + /* location */ + s=AQH_Device_GetLocation(device); + GBAA(dbuf, "", s?s:""); + /* description */ + s=AQH_Device_GetDescription(device); + GBAA(dbuf, "", s?s:""); + + GBAA(dbuf, ""); + device=AQH_Device_List_Next(device); + } + + GBAS(dbuf, + "\n" + "
Name For SystemRoomLocationDescription
%s%s%s%s%s
\n"); + AQH_Device_List_free(deviceList); +} + + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_index.h b/apps/aqhome-cgi/modules/devices/mdevices_index.h new file mode 100644 index 0000000..f5347df --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_index.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * 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_CGI_MDEVICES_INDEX_H +#define AQHOME_CGI_MDEVICES_INDEX_H + + +#include "aqhome-cgi/modules/devices/mdevices.h" + +#include "aqhome/aqhome.h" +#include "aqhome/dataclient/client.h" + +#include + +#include + + + +void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); + + +#endif diff --git a/apps/aqhome-cgi/modules/devices/mdevices_init.c b/apps/aqhome-cgi/modules/devices/mdevices_init.c new file mode 100644 index 0000000..f35f480 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_init.c @@ -0,0 +1,129 @@ +/**************************************************************************** + * 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 "./mdevices_init.h" + +#include "aqhome-cgi/service/module.h" +#include "aqhome-cgi/modules/mdataclient.h" + +#include +#include +#include + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +#define GBAS GWEN_Buffer_AppendString +#define GBAA GWEN_Buffer_AppendArgs + +#define P_DEVICEREAD AQH_MODDEVICES_PERMS_DEVICEREAD +#define P_VALUEREAD AQH_MODDEVICES_PERMS_VALUEREAD +#define P_VALUEWRITE AQH_MODDEVICES_PERMS_VALUEWRITE + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _createPermDefList(AQH_MODULE *m); +static void _createRoleList(AQH_MODULE *m); + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +int AQH_ModDevices_Create(AQH_SERVICE *sv) +{ + AQH_MODULE *m; + int rv; + + m=AQH_Module_new(); + AQH_Module_SetName(m, "devices"); + AQH_Module_SetDescr(m, "device module"); + AQH_Module_SetGuestPerms(m, 0); + + _createPermDefList(m); + _createRoleList(m); + + rv=AQH_Service_AddModule(sv, m); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + } + AQH_Module_free(m); + return rv; +} + + + +void _createPermDefList(AQH_MODULE *m) +{ + AQH_PERMDEF_LIST *permDefList; + + permDefList=AQH_PermDef_List_new(); + + AQH_ModService_AddPermDef(permDefList, "DeviceRead", 0x001, "Read and list devices"); + AQH_ModService_AddPermDef(permDefList, "DeviceWrite", 0x002, "Modify devices"); + AQH_ModService_AddPermDef(permDefList, "DeviceAdd", 0x004, "Add devices"); + AQH_ModService_AddPermDef(permDefList, "DeviceDel", 0x008, "Remove devices"); + + AQH_ModService_AddPermDef(permDefList, "ValueRead", 0x010, "Read and list values"); + AQH_ModService_AddPermDef(permDefList, "ValueWrite", 0x020, "Modify values"); + AQH_ModService_AddPermDef(permDefList, "ValueAdd", 0x040, "Add values"); + AQH_ModService_AddPermDef(permDefList, "ValueDel", 0x080, "Remove values"); + AQH_ModService_AddPermDef(permDefList, "ValueSet", 0x100, "Set values"); + + AQH_Module_SetPermDefList(m, permDefList); +} + + + +void _createRoleList(AQH_MODULE *m) +{ + AQH_ROLE_LIST *roleList; + int id=0; + + roleList=AQH_Role_List_new(); + AQH_ModService_AddRole(roleList, id++, "Reader", + AQH_MODDEVICES_PERMS_DEVICEREAD | + AQH_MODDEVICES_PERMS_VALUEREAD, + "Read devices and values"); + AQH_ModService_AddRole(roleList, id++, "Writer", + AQH_MODDEVICES_PERMS_DEVICEREAD | + AQH_MODDEVICES_PERMS_DEVICEWRITE | + AQH_MODDEVICES_PERMS_DEVICEADD | + AQH_MODDEVICES_PERMS_DEVICEDEL | + AQH_MODDEVICES_PERMS_VALUEREAD | + AQH_MODDEVICES_PERMS_VALUEWRITE | + AQH_MODDEVICES_PERMS_VALUEADD | + AQH_MODDEVICES_PERMS_VALUEDEL | + AQH_MODDEVICES_PERMS_VALUESET, + "Read and write devices and values"); + AQH_ModService_AddRole(roleList, id++, "Setter", + AQH_MODDEVICES_PERMS_DEVICEREAD | + AQH_MODDEVICES_PERMS_VALUEREAD | + AQH_MODDEVICES_PERMS_VALUESET, + "Set values"); + AQH_Module_SetRoleList(m, roleList); +} + + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_init.h b/apps/aqhome-cgi/modules/devices/mdevices_init.h new file mode 100644 index 0000000..6456e24 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_init.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * 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_CGI_MDEVICES_INIT_H +#define AQHOME_CGI_MDEVICES_INIT_H + + +#include "aqhome-cgi/modules/devices/mdevices.h" + +#include "aqhome/aqhome.h" +#include "aqhome/dataclient/client.h" + +#include + +#include + + + +int AQH_ModDevices_Create(AQH_SERVICE *sv); + + +#endif diff --git a/apps/aqhome-cgi/modules/devices/mdevices_setdata.c b/apps/aqhome-cgi/modules/devices/mdevices_setdata.c new file mode 100644 index 0000000..68f64f2 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_setdata.c @@ -0,0 +1,202 @@ +/**************************************************************************** + * 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 "./mdevices_setdata.h" + +#include "aqhome-cgi/service/module.h" +#include "aqhome-cgi/modules/mdataclient.h" + +#include +#include +#include + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +#define GBAS GWEN_Buffer_AppendString +#define GBAA GWEN_Buffer_AppendArgs + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _setRgbwData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue); +static void _setOnOffData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue); +static void _setOnOffAutoData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue); + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_ModDevices_RunSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) +{ + AQH_SERVICE *sv; + GWEN_DB_NODE *dbPost; + const char *sDeviceName; + const char *sValueName; + AQH_VALUE_LIST *valueList; + + /* sample data */ + sv=AQH_ModService_GetService(m); + dbPost=AQCGI_Request_GetDbPostBody(rq); + sDeviceName=dbPost?GWEN_DB_GetCharValue(dbPost, "device", 0, NULL):NULL; + sValueName=dbPost?GWEN_DB_GetCharValue(dbPost, "value", 0, NULL):NULL; + DBG_ERROR(NULL, "Device=[%s], value=[%s]", sDeviceName?sDeviceName:"", sValueName?sValueName:""); + valueList=sDeviceName?AQH_DataClient_GetValues(dc, sDeviceName, 0):NULL; + if (valueList && AQH_Value_List_GetCount(valueList)) { + const AQH_VALUE *value; + + value=AQH_Value_List_First(valueList); + while(value) { + if (AQH_Value_GetValueType(value)==AQH_ValueType_Actor) { + const char *sValueName; + const char *sValue; + + sValueName=AQH_Value_GetName(value); + sValue=GWEN_DB_GetCharValue(dbPost, sValueName, 0, NULL); + if (sValueName && *sValueName) { + DBG_ERROR(NULL, "Setting value %s to %s", sValueName?sValueName:"no name", sValue?sValue:"no value"); + switch(AQH_Value_GetModality(value)) { + case AQH_ValueModality_RGBW: _setRgbwData(dc, value, sValue); break; + case AQH_ValueModality_OnOff: _setOnOffData(dc, value, sValue); break; + case AQH_ValueModality_OnOffAuto: _setOnOffAutoData(dc, value, sValue); break; + default: + break; + } /* switch */ + } /* if (sValueName) */ + } + value=AQH_Value_List_Next(value); + } /* while */ + } + AQH_Value_List_free(valueList); + + if (sDeviceName && *sDeviceName) { + GWEN_BUFFER *pbuf; + + pbuf=GWEN_Buffer_new(0, 256, 0, 1); + if (sValueName && *sValueName) { + GBAS(pbuf, "Location: /aqbt/devices/value.html?device="); + GWEN_Text_EscapeToBuffer(sDeviceName, pbuf); + GBAS(pbuf, "&value="); + GWEN_Text_EscapeToBuffer(sValueName, pbuf); + } + else { + GBAS(pbuf, "Location: /aqbt/devices/values.html?device="); + GWEN_Text_EscapeToBuffer(sDeviceName, pbuf); + } + AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(pbuf)); + GWEN_Buffer_free(pbuf); + } + AQCGI_Request_SetResponseCode(rq, 303); + AQCGI_Request_SetResponseText(rq, "See other"); +} + + + +void _setRgbwData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue) +{ + if (sValue) { + const char *sValueSystemName; + uint32_t color; + int rv; + + sValueSystemName=AQH_Value_GetNameForSystem(value); + color=AQH_ModDevices_ColorFromHexString(sValue); + DBG_ERROR(NULL, "Send value [#%08x] to %s", color, sValueSystemName); + rv=AQH_DataClient_SetData(dc, value, (double) color); + if (rv<0) { + DBG_ERROR(NULL, "Error sending data: %d", rv); + } + } +} + + + +void _setOnOffData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue) +{ + if (sValue) { + const char *sValueSystemName; + int rv; + + sValueSystemName=AQH_Value_GetNameForSystem(value); + if (strcasecmp(sValue, "unchanged")==0) { + DBG_ERROR(NULL, "Value %s unchanged", sValueSystemName); + } + else if (strcasecmp(sValue, "on")==0) { + DBG_ERROR(NULL, "Send value 1 to %s", sValueSystemName); + rv=AQH_DataClient_SetData(dc, value, 1.0); + if (rv<0) { + DBG_ERROR(NULL, "Error sending data: %d", rv); + } + } + else if (strcasecmp(sValue, "off")==0) { + DBG_ERROR(NULL, "Send value 0 to %s", sValueSystemName); + rv=AQH_DataClient_SetData(dc, value, 0.0); + if (rv<0) { + DBG_ERROR(NULL, "Error sending data: %d", rv); + } + } + else { + } + } +} + + + +void _setOnOffAutoData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue) +{ + if (sValue) { + const char *sValueSystemName; + int rv; + + sValueSystemName=AQH_Value_GetNameForSystem(value); + if (strcasecmp(sValue, "unchanged")==0) { + DBG_ERROR(NULL, "Value %s unchanged", sValueSystemName); + } + else if (strcasecmp(sValue, "on")==0) { + DBG_ERROR(NULL, "Send value 1 to %s", sValueSystemName); + rv=AQH_DataClient_SetData(dc, value, 1.0); + if (rv<0) { + DBG_ERROR(NULL, "Error sending data: %d", rv); + } + } + else if (strcasecmp(sValue, "off")==0) { + DBG_ERROR(NULL, "Send value 0 to %s", sValueSystemName); + rv=AQH_DataClient_SetData(dc, value, 0.0); + if (rv<0) { + DBG_ERROR(NULL, "Error sending data: %d", rv); + } + } + else if (strcasecmp(sValue, "auto")==0) { + DBG_ERROR(NULL, "Send value 2 to %s", sValueSystemName); + rv=AQH_DataClient_SetData(dc, value, 2.0); + if (rv<0) { + DBG_ERROR(NULL, "Error sending data: %d", rv); + } + } + else { + DBG_ERROR(NULL, "Invalid value [%s] for %s", sValue, sValueSystemName); + } + } +} + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_setdata.h b/apps/aqhome-cgi/modules/devices/mdevices_setdata.h new file mode 100644 index 0000000..ac1263a --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_setdata.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * 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_CGI_MDEVICES_SETVALUE_H +#define AQHOME_CGI_MDEVICES_SETVALUE_H + + +#include "aqhome-cgi/modules/devices/mdevices.h" + +#include "aqhome/aqhome.h" +#include "aqhome/dataclient/client.h" + +#include + +#include + + + +void AQH_ModDevices_RunSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); + + +#endif diff --git a/apps/aqhome-cgi/modules/devices/mdevices_value.c b/apps/aqhome-cgi/modules/devices/mdevices_value.c new file mode 100644 index 0000000..61fc436 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_value.c @@ -0,0 +1,245 @@ +/**************************************************************************** + * 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 "./mdevices_value.h" + +#include "aqhome-cgi/service/module.h" +#include "aqhome-cgi/modules/mdataclient.h" + +#include +#include +#include + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +#define GBAS GWEN_Buffer_AppendString +#define GBAA GWEN_Buffer_AppendArgs + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _runValueWithArgs(AQH_MODULE *m, + AQCGI_REQUEST *rq, + AQH_SESSION *session, + AQH_DATACLIENT *dc, + const char *sDeviceName, + const char *sValueName, + GWEN_BUFFER *dbuf); +static void _mkValueForm(AQH_DATACLIENT *dc, const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf); +static void _writeRgbwToForm(const char *sValueName, uint32_t color, GWEN_BUFFER *dbuf); +static void _writeOnOffToForm(const char *sValueName, int intVal, GWEN_BUFFER *dbuf); +static void _writeOnOffAutoToForm(const char *sValueName, int intVal, GWEN_BUFFER *dbuf); + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_ModDevices_RunValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) +{ + GWEN_DB_NODE *dbQuery; + const char *sDeviceName; + const char *sValueName; + + DBG_ERROR(NULL, "RunValue"); + dbQuery=AQCGI_Request_GetDbQuery(rq); + sDeviceName=GWEN_DB_GetCharValue(dbQuery, "device", 0, NULL); + sValueName=GWEN_DB_GetCharValue(dbQuery, "value", 0, NULL); + if (sDeviceName && *sDeviceName && sValueName && *sValueName) { + GWEN_BUFFER *bufDeviceName; + GWEN_BUFFER *bufValueName; + + bufDeviceName=GWEN_Buffer_new(0, 64, 0, 1); + GWEN_Text_UnescapeToBufferTolerant(sDeviceName, bufDeviceName); + bufValueName=GWEN_Buffer_new(0, 64, 0, 1); + GWEN_Text_UnescapeToBufferTolerant(sValueName, bufValueName); + _runValueWithArgs(m, rq, session, dc, + GWEN_Buffer_GetStart(bufDeviceName), + GWEN_Buffer_GetStart(bufValueName), + dbuf); + GWEN_Buffer_free(bufValueName); + GWEN_Buffer_free(bufDeviceName); + } + +#if 0 + if (sDeviceName && *sDeviceName && sValueName && *sValueName) { + GWEN_BUFFER *pbuf; + + pbuf=GWEN_Buffer_new(0, 256, 0, 1); + GBAS(pbuf, "Location: /aqbt/devices/value.html?device="); + GWEN_Text_EscapeToBufferTolerant(sDeviceName, pbuf); + GBAS(pbuf, "&value="); + GWEN_Text_EscapeToBufferTolerant(sValueName, pbuf); + AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(pbuf)); + GWEN_Buffer_free(pbuf); + } + AQCGI_Request_SetResponseCode(rq, 303); + AQCGI_Request_SetResponseText(rq, "See other"); +#endif +} + + + +void _runValueWithArgs(AQH_MODULE *m, + AQCGI_REQUEST *rq, + AQH_SESSION *session, + AQH_DATACLIENT *dc, + const char *sDeviceName, + const char *sValueName, + GWEN_BUFFER *dbuf) +{ + GWEN_DB_NODE *dbQuery; + AQH_VALUE_LIST *valueList; + + dbQuery=AQCGI_Request_GetDbQuery(rq); + DBG_ERROR(NULL, "Device=%s, value=%s", sDeviceName?sDeviceName:"", sValueName?sValueName:""); + + GBAA(dbuf,"

Value %s/%s

\n", sDeviceName, sValueName); + + valueList=AQH_DataClient_GetValues(dc, sDeviceName, 0); + if (valueList) { + const AQH_VALUE *value; + + value=AQH_Value_List_First(valueList); + while(value) { + const char *s; + + s=AQH_Value_GetName(value); + if (s && *s && strcasecmp(s, sValueName)==0) + break; + value=AQH_Value_List_Next(value); + } + if (value && AQH_Value_GetValueType(value)==AQH_ValueType_Actor) { + _mkValueForm(dc, sDeviceName, value, dbuf); + } + else { + GBAS(dbuf, "\n"); + GBAS(dbuf, ""); + + GBAS(dbuf, ""); + + GBAS(dbuf, ""); + + GBAS(dbuf, "
"); + GBAS(dbuf, ""); + GBAS(dbuf, "
"); + GBAS(dbuf, ""); + GBAS(dbuf, "
"); + GBAS(dbuf, ""); + GBAS(dbuf, "
"); + } + AQH_Value_List_free(valueList); + } +} + + + +void _mkValueForm(AQH_DATACLIENT *dc, const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf) +{ + const char *sValueSystemName; + const char *sValueName; + uint64_t dataPoints[2]; + uint64_t recvdNum; + // uint64_t timestamp; + union {double f; uint64_t i;} u; + int intVal; + + sValueSystemName=AQH_Value_GetNameForSystem(value); + sValueName=AQH_Value_GetName(value); + recvdNum=AQH_DataClient_GetLastData(dc, sValueSystemName, &dataPoints[0], 1); + if (recvdNum>0) { + // timestamp=dataPoints[0]; + u.i=dataPoints[1]; + intVal=(int) u.f; + } + else { + u.i=0; + intVal=-1; + } + + GBAS(dbuf,"
\n"); + GBAA(dbuf, "\n", sDeviceName); + GBAA(dbuf, "\n", sValueName); + + DBG_ERROR(NULL, "Adding actor"); + switch(AQH_Value_GetModality(value)) { + case AQH_ValueModality_RGBW: _writeRgbwToForm(sValueName, u.f, dbuf); break; + case AQH_ValueModality_OnOff: _writeOnOffToForm(sValueName, intVal, dbuf); break; + case AQH_ValueModality_OnOffAuto: _writeOnOffAutoToForm(sValueName, intVal, dbuf); break; + default: GBAA(dbuf, "%.2f", u.f); break; + } /* switch */ + + GBAS(dbuf,""); + GBAS(dbuf, "
\n\n"); +} + + + +void _writeRgbwToForm(const char *sValueName, uint32_t color, GWEN_BUFFER *dbuf) +{ +#if 1 + GBAA(dbuf, "", sValueName, color); +#else + GBAA(dbuf, "#%08x (#%08x)", + sValueName, + AQH_ModDevices_RgbwToHtmlColor(color), + AQH_ModDevices_RgbwToHtmlColor(color), + color); +#endif +} + + + +void _writeOnOffToForm(const char *sValueName, int intVal, GWEN_BUFFER *dbuf) +{ + GBAA(dbuf, ""); +} + + + +void _writeOnOffAutoToForm(const char *sValueName, int intVal, GWEN_BUFFER *dbuf) +{ + GBAA(dbuf, ""); +} + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_value.h b/apps/aqhome-cgi/modules/devices/mdevices_value.h new file mode 100644 index 0000000..c1843f4 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_value.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * 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_CGI_MDEVICES_VALUE_H +#define AQHOME_CGI_MDEVICES_VALUE_H + + +#include "aqhome-cgi/modules/devices/mdevices.h" + +#include "aqhome/aqhome.h" +#include "aqhome/dataclient/client.h" + +#include + +#include + + + +void AQH_ModDevices_RunValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); + + +#endif diff --git a/apps/aqhome-cgi/modules/devices/mdevices_values.c b/apps/aqhome-cgi/modules/devices/mdevices_values.c new file mode 100644 index 0000000..d4a98f6 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_values.c @@ -0,0 +1,145 @@ +/**************************************************************************** + * 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 "./mdevices_values.h" +#include "./mdevices_index.h" + +#include "aqhome-cgi/service/module.h" +#include "aqhome-cgi/modules/mdataclient.h" + +#include +#include +#include + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +#define GBAS GWEN_Buffer_AppendString +#define GBAA GWEN_Buffer_AppendArgs + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, uint32_t perms, GWEN_BUFFER *dbuf); +static void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, uint32_t perms, GWEN_BUFFER *dbuf); + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_ModDevices_RunValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) +{ + GWEN_DB_NODE *dbQuery; + const char *sDeviceName; + uint32_t perms; + + perms=AQH_ModService_GetUserPerms(m); + + dbQuery=AQCGI_Request_GetDbQuery(rq); + sDeviceName=GWEN_DB_GetCharValue(dbQuery, "device", 0, NULL); + if (!(sDeviceName && *sDeviceName)) + AQH_ModDevices_RunIndex(m, rq, session, dc, dbuf); + else { + AQH_VALUE_LIST *valueList; + + valueList=AQH_DataClient_GetValues(dc, sDeviceName, 0); + if (valueList && AQH_Value_List_GetCount(valueList)) { + + GBAA(dbuf,"

Values for Device %s

\n", sDeviceName); + _writeValueListToTable(sDeviceName, valueList, perms, dbuf); + GBAS(dbuf, "\n"); + } + else { + GBAS(dbuf,"

No values.

\n"); + } + AQH_Value_List_free(valueList); + } +} + + + +void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, uint32_t perms, GWEN_BUFFER *dbuf) +{ + const AQH_VALUE *value; + + GBAS(dbuf, + "\n" + "" + "" + "" + "" + "" +#if 0 + "" + "" + "" +#endif + "" + "\n" + "\n"); + + value=AQH_Value_List_First(valueList); + while(value) { + //if (AQH_Value_GetModality(value)!=AQH_ValueModality_Stats) + _writeValueToTable(sDeviceName, value, perms, dbuf); + value=AQH_Value_List_Next(value); + } + GBAS(dbuf, + "\n" + "
NameTypeModalityDriverDeviceName for System
\n"); +} + + + +void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, uint32_t perms, GWEN_BUFFER *dbuf) +{ + const char *s; + + GBAS(dbuf, ""); + + /* name for system */ + s=AQH_Value_GetName(value); + if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) { + uint32_t pos; + + pos=GWEN_Buffer_GetPos(dbuf); + GBAS(dbuf,"%s", s); + } + else + GBAA(dbuf,"%s", s?s:""); + + s=AQH_ValueType_toString(AQH_Value_GetValueType(value)); + GBAA(dbuf, "%s", s?s:""); + + s=AQH_ValueModality_toString(AQH_Value_GetModality(value)); + GBAA(dbuf, "%s", s?s:""); + + GBAA(dbuf, "\n"); +} + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_values.h b/apps/aqhome-cgi/modules/devices/mdevices_values.h new file mode 100644 index 0000000..25cc9ed --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_values.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * 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_CGI_MDEVICES_VALUES_H +#define AQHOME_CGI_MDEVICES_VALUES_H + + +#include "aqhome-cgi/modules/devices/mdevices.h" + +#include "aqhome/aqhome.h" +#include "aqhome/dataclient/client.h" + +#include + +#include + + + +void AQH_ModDevices_RunValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); + + +#endif diff --git a/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c new file mode 100644 index 0000000..02d2819 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c @@ -0,0 +1,464 @@ +/**************************************************************************** + * 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 "./mdevices_vgraph.h" + +#include "aqhome-cgi/service/module.h" +#include "aqhome-cgi/modules/mdataclient.h" + +#include +#include +#include +//#include +//#include + +#include +#include +#include + +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defs and enums + * ------------------------------------------------------------------------------------------------ + */ + +#define GBAS GWEN_Buffer_AppendString +#define GBAA GWEN_Buffer_AppendArgs + + +enum { + VALUEGRAPH_PERIOD_4H=1, + VALUEGRAPH_PERIOD_1D, + VALUEGRAPH_PERIOD_1W, + VALUEGRAPH_PERIOD_1M +}; + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _runGraphValueWithArgs(AQH_MODULE *m, + AQCGI_REQUEST *rq, + AQH_SESSION *session, + AQH_DATACLIENT *dc, + const char *sDeviceName, + const char *sValueName, + GWEN_BUFFER *dbuf); +static void _createGraph(AQH_DATACLIENT *dc, + const AQH_VALUE *v, + int period, + const char *graphTitle, int precision, const char *curveLabel, + const char *sImgFile, int imgWidth, int imgHeight, uint64_t numDataPoints); +static int _fileIsCurrent(const char *sPath, int seconds); +static AQDG_GRAPH *_mkGraphObjectWithTitle(const char *graphTitle, int period, int precision); +static int _getPeriodFromString(const char *sPeriod); +static int _getAcceptedAgeForPeriod(int period); +static void _mkPathForValueAndPeriod(AQH_MODULE *m, const AQH_VALUE *v, int pPeriod, GWEN_BUFFER *dbuf); +static uint64_t _getStartTimeForPeriod(int period); +static const char *_getModifiersForPeriod(int period); +static AQH_VALUE *_getValue(AQH_DATACLIENT *dc, const char *sDeviceName, const char *sValueName); + +static AQDG_GRAPH_DATAPAIR_LIST *_requestDataPairList(AQH_DATACLIENT *dc, const char *valueName, + uint64_t tsBegin, uint64_t tsEnd, uint64_t num); +static AQDG_GRAPH_DATAPAIR_LIST *_createDataPairListFromDataPoints(const uint64_t *dataPoints, uint64_t numValues); + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_ModDevices_RunGraphValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) +{ + GWEN_DB_NODE *dbQuery; + const char *sDeviceName; + const char *sValueName; + + DBG_ERROR(NULL, "GraphValue"); + dbQuery=AQCGI_Request_GetDbQuery(rq); + sDeviceName=GWEN_DB_GetCharValue(dbQuery, "device", 0, NULL); + sValueName=GWEN_DB_GetCharValue(dbQuery, "value", 0, NULL); + DBG_ERROR(NULL, "Device=%s, value=%s", sDeviceName?sDeviceName:"", sValueName?sValueName:""); + if (sDeviceName && *sDeviceName && sValueName && *sValueName) { + GWEN_BUFFER *bufDeviceName; + GWEN_BUFFER *bufValueName; + + bufDeviceName=GWEN_Buffer_new(0, 64, 0, 1); + GWEN_Text_UnescapeToBufferTolerant(sDeviceName, bufDeviceName); + bufValueName=GWEN_Buffer_new(0, 64, 0, 1); + GWEN_Text_UnescapeToBufferTolerant(sValueName, bufValueName); + _runGraphValueWithArgs(m, rq, session, dc, + GWEN_Buffer_GetStart(bufDeviceName), + GWEN_Buffer_GetStart(bufValueName), + dbuf); + GWEN_Buffer_free(bufValueName); + GWEN_Buffer_free(bufDeviceName); + } +} + + + +void _runGraphValueWithArgs(AQH_MODULE *m, + AQCGI_REQUEST *rq, + AQH_SESSION *session, + AQH_DATACLIENT *dc, + const char *sDeviceName, + const char *sValueName, + GWEN_BUFFER *dbuf) +{ + GWEN_DB_NODE *dbQuery; + AQH_VALUE *value; + const char *sPeriod; + int period; + + DBG_ERROR(NULL, "GraphValue with args"); + dbQuery=AQCGI_Request_GetDbQuery(rq); + sPeriod=GWEN_DB_GetCharValue(dbQuery, "period", 0, NULL); + period=sPeriod?_getPeriodFromString(sPeriod):VALUEGRAPH_PERIOD_1D; + DBG_ERROR(NULL, "Device=%s, value=%s, period=%s", + sDeviceName?sDeviceName:"", sValueName?sValueName:"", + sPeriod?sPeriod:""); + + value=_getValue(dc, sDeviceName, sValueName); + if (value) { + GWEN_BUFFER *fbuf; + int rv; + + fbuf=GWEN_Buffer_new(0, 256, 0, 1); + _mkPathForValueAndPeriod(m, value, period, fbuf); + if (!_fileIsCurrent(GWEN_Buffer_GetStart(fbuf), _getAcceptedAgeForPeriod(period))) { + DBG_ERROR(NULL, "Creating graph"); + _createGraph(dc, + value, + period, + sValueName, + 2, + AQH_ValueModality_toString(AQH_Value_GetModality(value)), + GWEN_Buffer_GetStart(fbuf), + 640, 480, + 100000); + } + + if (1) { + GWEN_BUFFER *ibuf; + + ibuf=GWEN_Buffer_new(0, 1024, 0, 1); + // return file + rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fbuf), ibuf); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + } + else { + GWEN_Buffer_Reset(dbuf); + GWEN_Buffer_AppendBytes(dbuf, GWEN_Buffer_GetStart(ibuf), GWEN_Buffer_GetUsedBytes(ibuf)); + AQCGI_Request_AddResponseHeaderData(rq, "Content-type: image/png"); + AQCGI_Request_AddFlags(rq, AQH_MODSERVICE_RQFLAGS_RAWFILE); + } + GWEN_Buffer_free(ibuf); + } + + GWEN_Buffer_free(fbuf); + AQH_Value_free(value); + } + else { + DBG_ERROR(NULL, "Could not get value"); + } +} + + + +int _fileIsCurrent(const char *sPath, int seconds) +{ + struct stat sb; + time_t t1; + + if (lstat(sPath, &sb)==-1) { + DBG_ERROR(NULL, "Error on lstat(%s): %s (%d)", sPath, strerror(errno), errno); + return 0; + } + t1=time(0); + if ((t1-sb.st_mtime)<(time_t) seconds) { + DBG_ERROR(NULL, "File %s is current", sPath); + return 1; + } + + return 0; +} + + + +void _createGraph(AQH_DATACLIENT *dc, + const AQH_VALUE *v, + int period, + const char *graphTitle, int precision, + const char *curveLabel, + const char *sImgFile, int imgWidth, int imgHeight, uint64_t numDataPoints) +{ + const char *sValue; + AQDG_GRAPH *g; + AQDG_DRAW_CONTEXT *drawContext; + AQDG_OBJECT *graphObject; + uint64_t tsBegin; + uint64_t tsEnd; + const char *sModifier; + AQDG_GRAPH_DATAPAIR_LIST *dpList; + + sValue=AQH_Value_GetNameForSystem(v); + tsEnd=time(0); + tsBegin=_getStartTimeForPeriod(period); + g=_mkGraphObjectWithTitle(graphTitle, period, precision); + sModifier=_getModifiersForPeriod(period); + + DBG_ERROR(NULL, "Requesting data for %s", sValue); + dpList=_requestDataPairList(dc, sValue, tsBegin, tsEnd, numDataPoints); + if (dpList) { + DBG_ERROR(NULL, "Adding data for %s", sValue); + AQDG_TimeGraph_ModifyDataAndAddCurve(g, curveLabel?curveLabel:sValue, sModifier, dpList); + } + else { + DBG_ERROR(NULL, "No data"); + AQDG_Graph_free(g); + return; + } + + DBG_ERROR(NULL, "Setup ticks for %s", sValue); + AQDG_TimeGraph_SetupTicks(g, 0, 0.0, 0.0); + + DBG_ERROR(NULL, "Draw graph for %s", sValue); + drawContext=AQDG_Draw_ContextCairo_Png_new(sImgFile, imgWidth, imgHeight); + graphObject=AQDG_GraphWidget_new(NULL, AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_STRETCHY, drawContext); + AQDG_Object_SetWidth(graphObject, imgWidth); + AQDG_Object_SetHeight(graphObject, imgHeight); + + AQDG_GraphWidget_SetupDefaultPens(graphObject); + AQDG_GraphWidget_SetupDefaultFonts(graphObject); + + AQDG_GraphWidget_FinishWithGraph(graphObject, g); + + AQDG_Object_free(graphObject); +} + + + +AQDG_GRAPH *_mkGraphObjectWithTitle(const char *graphTitle, int period, int precision) +{ + AQDG_GRAPH *g; + GWEN_BUFFER *tbuf; + const char *s; + + tbuf=GWEN_Buffer_new(0, 256, 0, 1); + + switch(period) { + case VALUEGRAPH_PERIOD_4H: s="last 4 hours"; break; + case VALUEGRAPH_PERIOD_1D: s="last 24 hours"; break; + case VALUEGRAPH_PERIOD_1W: s="last week"; break; + case VALUEGRAPH_PERIOD_1M: s="last month"; break; + default: s="last 24 hours"; break; + } + + GBAA(tbuf, "%s - %s", graphTitle, s); + + g=AQDG_TimeGraph_new(GWEN_Buffer_GetStart(tbuf), NULL, "Value", NULL, precision); + GWEN_Buffer_free(tbuf); + return g; +} + + +int _getPeriodFromString(const char *sPeriod) +{ + if (strcasecmp(sPeriod, "4h")==0) + return VALUEGRAPH_PERIOD_4H; + else if (strcasecmp(sPeriod, "1d")==0) + return VALUEGRAPH_PERIOD_1D; + else if (strcasecmp(sPeriod, "1w")==0) + return VALUEGRAPH_PERIOD_1W; + else if (strcasecmp(sPeriod, "1m")==0) + return VALUEGRAPH_PERIOD_1M; + return VALUEGRAPH_PERIOD_1D; +} + + + +void _mkPathForValueAndPeriod(AQH_MODULE *m, const AQH_VALUE *v, int period, GWEN_BUFFER *dbuf) +{ + AQH_SERVICE *sv; + const char *s; + + sv=AQH_ModService_GetService(m); + + /* cache folder */ + s=AQH_Service_GetCacheFolder(sv); + GBAA(dbuf, "%s%s", s, GWEN_DIR_SEPARATOR_S); + + /* var name */ + s=AQH_Value_GetNameForSystem(v); + GWEN_Text_EscapeToBuffer(s, dbuf); + + /* period */ + switch(period) { + case VALUEGRAPH_PERIOD_4H: s="4h"; break; + case VALUEGRAPH_PERIOD_1D: s="1d"; break; + case VALUEGRAPH_PERIOD_1W: s="1w"; break; + case VALUEGRAPH_PERIOD_1M: s="1m"; break; + default: s="1d"; break; + } + + GBAA(dbuf, "-%s.png", s); +} + + + +uint64_t _getStartTimeForPeriod(int period) +{ + time_t t; + + t=time(0); + + /* period */ + switch(period) { + case VALUEGRAPH_PERIOD_4H: t-=4*60*60; break; + case VALUEGRAPH_PERIOD_1D: t-=24*60*60; break; + case VALUEGRAPH_PERIOD_1W: t-=7*24*60*60; break; + case VALUEGRAPH_PERIOD_1M: t-=30*24*60*60; break; + default: t-=24*60*60; break; + } + + return (uint64_t) t; +} + + + +const char *_getModifiersForPeriod(int period) +{ + /* period */ + switch(period) { + case VALUEGRAPH_PERIOD_4H: return "La5"; + case VALUEGRAPH_PERIOD_1D: return "La15"; + case VALUEGRAPH_PERIOD_1W: return "La240"; + case VALUEGRAPH_PERIOD_1M: return "La480"; + default: return "La15"; + } +} + + + +int _getAcceptedAgeForPeriod(int period) +{ + /* period */ + switch(period) { + case VALUEGRAPH_PERIOD_4H: return 2*60; /* 2m */ + case VALUEGRAPH_PERIOD_1D: return 5*60; /* 5m */ + case VALUEGRAPH_PERIOD_1W: return 15*60; /* 15m */ + case VALUEGRAPH_PERIOD_1M: return 60*60; /* 1h */ + default: return 5*60; /* 5m */ + } +} + + + + +AQH_VALUE *_getValue(AQH_DATACLIENT *dc, const char *sDeviceName, const char *sValueName) +{ + AQH_VALUE_LIST *valueList; + + valueList=AQH_DataClient_GetValues(dc, sDeviceName, 0); + if (valueList) { + AQH_VALUE *value; + + value=AQH_Value_List_First(valueList); + while(value) { + const char *s; + + s=AQH_Value_GetName(value); + if (s && *s && strcasecmp(s, sValueName)==0) { + break; + } + value=AQH_Value_List_Next(value); + } + + if (value) { + AQH_Value_List_Del(value); + AQH_Value_List_free(valueList); + return value; + } + + AQH_Value_List_free(valueList); + } + + return NULL; +} + + + +AQDG_GRAPH_DATAPAIR_LIST *_requestDataPairList(AQH_DATACLIENT *dc, const char *valueName, + uint64_t tsBegin, uint64_t tsEnd, uint64_t num) +{ + 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) { + AQDG_GRAPH_DATAPAIR_LIST *dpList; + + dpList=_createDataPairListFromDataPoints(dataPoints, recvdNum); + free(dataPoints); + return dpList; + } + else { + DBG_ERROR(NULL, "No data received"); + free(dataPoints); + return NULL; + } +} + + + +AQDG_GRAPH_DATAPAIR_LIST *_createDataPairListFromDataPoints(const uint64_t *dataPoints, uint64_t numValues) +{ + AQDG_GRAPH_DATAPAIR_LIST *dpList; + uint64_t i; + + DBG_ERROR(NULL, "Got %d datapoints", (int) numValues); + dpList=AQDG_Graph_DataPair_List_new(); + for(i=0; i + +#include + + + +void AQH_ModDevices_RunGraphValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); + + +#endif diff --git a/apps/aqhome-cgi/modules/mdevices.c b/apps/aqhome-cgi/modules/mdevices.c deleted file mode 100644 index 1b7b430..0000000 --- a/apps/aqhome-cgi/modules/mdevices.c +++ /dev/null @@ -1,873 +0,0 @@ -/**************************************************************************** - * 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 "./mdevices.h" - -#include "aqhome-cgi/service/module.h" -#include "aqhome-cgi/modules/mdataclient.h" - -#include -#include -#include - - - -/* ------------------------------------------------------------------------------------------------ - * defs and enums - * ------------------------------------------------------------------------------------------------ - */ - -#define GBAS GWEN_Buffer_AppendString -#define GBAA GWEN_Buffer_AppendArgs - -#define P_DEVICEREAD AQH_MODDEVICES_PERMS_DEVICEREAD -#define P_VALUEREAD AQH_MODDEVICES_PERMS_VALUEREAD -#define P_VALUEWRITE AQH_MODDEVICES_PERMS_VALUEWRITE - - - -/* ------------------------------------------------------------------------------------------------ - * forward declarations - * ------------------------------------------------------------------------------------------------ - */ - -static void _createPermDefList(AQH_MODULE *m); -static void _createRoleList(AQH_MODULE *m); - -static AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName); -static int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem); - -static void _handleRqIndexGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); -static void _handleRqValuesGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); -static void _handleRqValueGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); -static void _handleRqSetDataPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); - -static void _runIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); -static void _runValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); -static void _runValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); -static void _runValueWithArgs(AQH_MODULE *m, - AQCGI_REQUEST *rq, - AQH_SESSION *session, - AQH_DATACLIENT *dc, - const char *sDeviceName, - const char *sValueName, - GWEN_BUFFER *dbuf); - -static void _runSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf); -static void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, uint32_t perms, GWEN_BUFFER *dbuf); -static void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, uint32_t perms, GWEN_BUFFER *dbuf); -static void _addValueActionToForm(const AQH_VALUE *value, GWEN_BUFFER *dbuf); -static uint32_t _colorFromHexString(const char *s); -static uint32_t _htmlColorToValueRGBW(uint32_t colorIn); -static uint32_t _rgbwToHtmlColor(uint32_t colorIn); -static void _setRgbwData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue); -static void _setOnOffData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue); -static void _setOnOffAutoData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue); -static void _addLastValueToForm(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER *dbuf); - -static void _mkValueForm(AQH_DATACLIENT *dc, const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf); - - - -/* ------------------------------------------------------------------------------------------------ - * vars - * ------------------------------------------------------------------------------------------------ - */ - -static AQH_MODSERVICE_HANDLER_ENTRY _requestTable[]={ - {"index.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD, _handleRqIndexGet}, - {"values.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqValuesGet}, - {"value.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqValueGet}, - {"setdata.html", AQCGI_REQUEST_METHOD_POST, P_VALUEWRITE, _handleRqSetDataPost}, - {NULL, 0, 0, NULL} -}; - - - -/* ------------------------------------------------------------------------------------------------ - * code - * ------------------------------------------------------------------------------------------------ - */ - -void AQH_ModDevices_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder) -{ - AQH_ModService_Extend(m, sv, baseFolder); - AQH_ModService_SetHandleRequestFn(m, _handleRequest); - AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule); -} - - - -int AQH_ModDevices_Create(AQH_SERVICE *sv) -{ - AQH_MODULE *m; - int rv; - - m=AQH_Module_new(); - AQH_Module_SetName(m, "devices"); - AQH_Module_SetDescr(m, "device module"); - AQH_Module_SetGuestPerms(m, 0); - - _createPermDefList(m); - _createRoleList(m); - - rv=AQH_Service_AddModule(sv, m); - if (rv<0) { - DBG_INFO(NULL, "here (%d)", rv); - } - AQH_Module_free(m); - return rv; -} - - - -void _createPermDefList(AQH_MODULE *m) -{ - AQH_PERMDEF_LIST *permDefList; - - permDefList=AQH_PermDef_List_new(); - - AQH_ModService_AddPermDef(permDefList, "DeviceRead", 0x001, "Read and list devices"); - AQH_ModService_AddPermDef(permDefList, "DeviceWrite", 0x002, "Modify devices"); - AQH_ModService_AddPermDef(permDefList, "DeviceAdd", 0x004, "Add devices"); - AQH_ModService_AddPermDef(permDefList, "DeviceDel", 0x008, "Remove devices"); - - AQH_ModService_AddPermDef(permDefList, "ValueRead", 0x010, "Read and list values"); - AQH_ModService_AddPermDef(permDefList, "ValueWrite", 0x020, "Modify values"); - AQH_ModService_AddPermDef(permDefList, "ValueAdd", 0x040, "Add values"); - AQH_ModService_AddPermDef(permDefList, "ValueDel", 0x080, "Remove values"); - AQH_ModService_AddPermDef(permDefList, "ValueSet", 0x100, "Set values"); - - AQH_Module_SetPermDefList(m, permDefList); -} - - - -void _createRoleList(AQH_MODULE *m) -{ - AQH_ROLE_LIST *roleList; - int id=0; - - roleList=AQH_Role_List_new(); - AQH_ModService_AddRole(roleList, id++, "Reader", - AQH_MODDEVICES_PERMS_DEVICEREAD | - AQH_MODDEVICES_PERMS_VALUEREAD, - "Read devices and values"); - AQH_ModService_AddRole(roleList, id++, "Writer", - AQH_MODDEVICES_PERMS_DEVICEREAD | - AQH_MODDEVICES_PERMS_DEVICEWRITE | - AQH_MODDEVICES_PERMS_DEVICEADD | - AQH_MODDEVICES_PERMS_DEVICEDEL | - AQH_MODDEVICES_PERMS_VALUEREAD | - AQH_MODDEVICES_PERMS_VALUEWRITE | - AQH_MODDEVICES_PERMS_VALUEADD | - AQH_MODDEVICES_PERMS_VALUEDEL | - AQH_MODDEVICES_PERMS_VALUESET, - "Read and write devices and values"); - AQH_ModService_AddRole(roleList, id++, "Setter", - AQH_MODDEVICES_PERMS_DEVICEREAD | - AQH_MODDEVICES_PERMS_VALUEREAD | - AQH_MODDEVICES_PERMS_VALUESET, - "Set values"); - AQH_Module_SetRoleList(m, roleList); -} - - - -AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName) -{ - return NULL; -} - - - -int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem) -{ - AQH_ModService_HandleRequestWithTable(m, rq, session, sLastPathElem, _requestTable); - return AQCGI_SendResponse(rq); -} - - - -void _handleRqIndexGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) -{ - AQH_ModDataClient_HandleRequest(m, rq, session, _runIndex, dbuf); -} - - - -void _handleRqValuesGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) -{ - AQH_ModDataClient_HandleRequest(m, rq, session, _runValues, dbuf); -} - - - -void _handleRqValueGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) -{ - AQH_ModDataClient_HandleRequest(m, rq, session, _runValue, dbuf); -} - - - -void _handleRqSetDataPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) -{ - AQH_ModDataClient_HandleRequest(m, rq, session, _runSetData, dbuf); -} - - - -void _runIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) -{ - AQH_DEVICE_LIST *deviceList; - AQH_DEVICE *device; - uint32_t perms; - - perms=AQH_ModService_GetUserPerms(m); - - deviceList=AQH_DataClient_GetDevices(dc, NULL); - if (deviceList==NULL) { - DBG_ERROR(NULL, "No device received"); - GBAS(dbuf, "

No devices.

"); - return; - } - - GBAS(dbuf, "

Devices

\n"); - GBAS(dbuf, - "\n" - "\n" - "" - "" - "" - "" - "" -#if 0 - "" - "" - "" - "" - "" -#endif - "\n" - "\n" - "\n"); - - device=AQH_Device_List_First(deviceList); - while(device) { - const char *s; - - GBAA(dbuf, ""); - /* name for system */ - s=AQH_Device_GetNameForSystem(device); - if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) { - GBAS(dbuf,"", s?s:""); - } - else - GBAA(dbuf,"", s?s:""); - /* room */ - s=AQH_Device_GetRoomName(device); - GBAA(dbuf, "", s?s:""); - /* location */ - s=AQH_Device_GetLocation(device); - GBAA(dbuf, "", s?s:""); - /* description */ - s=AQH_Device_GetDescription(device); - GBAA(dbuf, "", s?s:""); -#if 0 - /* device type */ - s=AQH_Device_GetDeviceType(device); - GBAA(dbuf, "", s?s:""); - /* driver */ - s=AQH_Device_GetDriver(device); - GBAA(dbuf, "", s?s:""); - /* short device name */ - s=AQH_Device_GetName(device); - GBAA(dbuf, "", s?s:""); - /* GUI name for device */ - s=AQH_Device_GetNameForGui(device); - GBAA(dbuf, "", s?s:""); - /* manufacturer */ - s=AQH_Device_GetManufacturer(device); - GBAA(dbuf, "", s?s:""); -#endif - - GBAA(dbuf, ""); - device=AQH_Device_List_Next(device); - } - - GBAS(dbuf, - "\n" - "
Name For SystemRoomLocationDescriptionTypeDriverNameGUI NameManufacturer
%s%s%s%s%s%s%s%s%s%s
\n"); - AQH_Device_List_free(deviceList); -} - - - -void _runValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) -{ - GWEN_DB_NODE *dbQuery; - const char *sDeviceName; - uint32_t perms; - - perms=AQH_ModService_GetUserPerms(m); - - dbQuery=AQCGI_Request_GetDbQuery(rq); - sDeviceName=GWEN_DB_GetCharValue(dbQuery, "device", 0, NULL); - if (!(sDeviceName && *sDeviceName)) - _runIndex(m, rq, session, dc, dbuf); - else { - AQH_VALUE_LIST *valueList; - - valueList=AQH_DataClient_GetValues(dc, sDeviceName, 0); - if (valueList && AQH_Value_List_GetCount(valueList)) { - - GBAA(dbuf,"

Values for Device %s

\n", sDeviceName); - _writeValueListToTable(sDeviceName, valueList, perms, dbuf); - GBAS(dbuf, "\n"); - } - else { - GBAS(dbuf,"

No values.

\n"); - } - AQH_Value_List_free(valueList); - } -} - - - -void _runValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) -{ - GWEN_DB_NODE *dbQuery; - const char *sDeviceName; - const char *sValueName; - - dbQuery=AQCGI_Request_GetDbQuery(rq); - sDeviceName=GWEN_DB_GetCharValue(dbQuery, "device", 0, NULL); - sValueName=GWEN_DB_GetCharValue(dbQuery, "value", 0, NULL); - if (sDeviceName && *sDeviceName && sValueName && *sValueName) { - GWEN_BUFFER *bufDeviceName; - GWEN_BUFFER *bufValueName; - - bufDeviceName=GWEN_Buffer_new(0, 64, 0, 1); - GWEN_Text_UnescapeToBufferTolerant(sDeviceName, bufDeviceName); - bufValueName=GWEN_Buffer_new(0, 64, 0, 1); - GWEN_Text_UnescapeToBufferTolerant(sValueName, bufValueName); - _runValueWithArgs(m, rq, session, dc, - GWEN_Buffer_GetStart(bufDeviceName), - GWEN_Buffer_GetStart(bufValueName), - dbuf); - GWEN_Buffer_free(bufValueName); - GWEN_Buffer_free(bufDeviceName); - } - -#if 0 - if (sDeviceName && *sDeviceName && sValueName && *sValueName) { - GWEN_BUFFER *pbuf; - - pbuf=GWEN_Buffer_new(0, 256, 0, 1); - GBAS(pbuf, "Location: /aqbt/devices/value.html?device="); - GWEN_Text_EscapeToBufferTolerant(sDeviceName, pbuf); - GBAS(pbuf, "&value="); - GWEN_Text_EscapeToBufferTolerant(sValueName, pbuf); - AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(pbuf)); - GWEN_Buffer_free(pbuf); - } - AQCGI_Request_SetResponseCode(rq, 303); - AQCGI_Request_SetResponseText(rq, "See other"); -#endif -} - - - -void _runValueWithArgs(AQH_MODULE *m, - AQCGI_REQUEST *rq, - AQH_SESSION *session, - AQH_DATACLIENT *dc, - const char *sDeviceName, - const char *sValueName, - GWEN_BUFFER *dbuf) -{ - GWEN_DB_NODE *dbQuery; - AQH_VALUE_LIST *valueList; - - dbQuery=AQCGI_Request_GetDbQuery(rq); - DBG_ERROR(NULL, "Device=%s, value=%s", sDeviceName?sDeviceName:"", sValueName?sValueName:""); - - valueList=AQH_DataClient_GetValues(dc, sDeviceName, 0); - if (valueList) { - const AQH_VALUE *value; - - value=AQH_Value_List_First(valueList); - while(value) { - const char *s; - - s=AQH_Value_GetName(value); - if (s && *s && strcasecmp(s, sValueName)==0) - break; - value=AQH_Value_List_Next(value); - } - if (value && AQH_Value_GetValueType(value)==AQH_ValueType_Actor) { - _mkValueForm(dc, sDeviceName, value, dbuf); - } - else { - } - AQH_Value_List_free(valueList); - } -} - - - -void _runSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) -{ - AQH_SERVICE *sv; - GWEN_DB_NODE *dbPost; - const char *sDeviceName; - const char *sValueName; - AQH_VALUE_LIST *valueList; - - /* sample data */ - sv=AQH_ModService_GetService(m); - dbPost=AQCGI_Request_GetDbPostBody(rq); - sDeviceName=dbPost?GWEN_DB_GetCharValue(dbPost, "device", 0, NULL):NULL; - sValueName=dbPost?GWEN_DB_GetCharValue(dbPost, "value", 0, NULL):NULL; - DBG_ERROR(NULL, "Device=[%s], value=[%s]", sDeviceName?sDeviceName:"", sValueName?sValueName:""); - valueList=sDeviceName?AQH_DataClient_GetValues(dc, sDeviceName, 0):NULL; - if (valueList && AQH_Value_List_GetCount(valueList)) { - const AQH_VALUE *value; - - value=AQH_Value_List_First(valueList); - while(value) { - if (AQH_Value_GetValueType(value)==AQH_ValueType_Actor) { - const char *sValueName; - const char *sValue; - - sValueName=AQH_Value_GetName(value); - sValue=GWEN_DB_GetCharValue(dbPost, sValueName, 0, NULL); - if (sValueName && *sValueName) { - DBG_ERROR(NULL, "Setting value %s to %s", sValueName?sValueName:"no name", sValue?sValue:"no value"); - switch(AQH_Value_GetModality(value)) { - case AQH_ValueModality_RGBW: _setRgbwData(dc, value, sValue); break; - case AQH_ValueModality_OnOff: _setOnOffData(dc, value, sValue); break; - case AQH_ValueModality_OnOffAuto: _setOnOffAutoData(dc, value, sValue); break; - default: - break; - } /* switch */ - } /* if (sValueName) */ - } - value=AQH_Value_List_Next(value); - } /* while */ - } - AQH_Value_List_free(valueList); - - if (sDeviceName && *sDeviceName) { - GWEN_BUFFER *pbuf; - - pbuf=GWEN_Buffer_new(0, 256, 0, 1); - if (sValueName && *sValueName) { - GBAS(pbuf, "Location: /aqbt/devices/value.html?device="); - GWEN_Text_EscapeToBuffer(sDeviceName, pbuf); - GBAS(pbuf, "&value="); - GWEN_Text_EscapeToBuffer(sValueName, pbuf); - } - else { - GBAS(pbuf, "Location: /aqbt/devices/values.html?device="); - GWEN_Text_EscapeToBuffer(sDeviceName, pbuf); - } - AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(pbuf)); - GWEN_Buffer_free(pbuf); - } - AQCGI_Request_SetResponseCode(rq, 303); - AQCGI_Request_SetResponseText(rq, "See other"); -} - - -void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, uint32_t perms, GWEN_BUFFER *dbuf) -{ - const AQH_VALUE *value; - - GBAS(dbuf, - "\n" - "" - "" - "" - "" - "" -#if 0 - "" - "" - "" -#endif - "" - "\n" - "\n"); - - value=AQH_Value_List_First(valueList); - while(value) { - if (AQH_Value_GetModality(value)!=AQH_ValueModality_Stats) - _writeValueToTable(sDeviceName, value, perms, dbuf); - value=AQH_Value_List_Next(value); - } - GBAS(dbuf, - "\n" - "
NameTypeModalityDriverDeviceName for System
\n"); -} - - - -void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, uint32_t perms, GWEN_BUFFER *dbuf) -{ - const char *s; - - GBAS(dbuf, ""); - - /* name for system */ - s=AQH_Value_GetName(value); - if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) { - uint32_t pos; - - pos=GWEN_Buffer_GetPos(dbuf); - GBAS(dbuf,"%s", s); - } - else - GBAA(dbuf,"%s", s?s:""); - - s=AQH_ValueType_toString(AQH_Value_GetValueType(value)); - GBAA(dbuf, "%s", s?s:""); - - s=AQH_ValueModality_toString(AQH_Value_GetModality(value)); - GBAA(dbuf, "%s", s?s:""); - - GBAA(dbuf, "\n"); -} - - - -void _addValueActionToForm(const AQH_VALUE *value, GWEN_BUFFER *dbuf) -{ - const char *sValueName; - - sValueName=AQH_Value_GetName(value); - switch(AQH_Value_GetModality(value)) { - case AQH_ValueModality_RGBW: - GBAA(dbuf, "", sValueName); - break; - case AQH_ValueModality_OnOff: - GBAA(dbuf, - "", - sValueName); - break; - case AQH_ValueModality_OnOffAuto: - GBAA(dbuf, - "", - sValueName); - break; - default: - break; - } -} - - - -uint32_t _colorFromHexString(const char *s) -{ - uint32_t colorIn=0; - - while(*s && *s<33) - s++; - if (*s=='#') - s++; - while(*s) { - uint c; - - c=(*s)-'0'; - if (c>9) - c-=7; - colorIn<<=4; - colorIn|=c & 0xf; - s++; - } - - /* hex 00RRGGBB -> GGRRWWBB */ - //return _htmlColorToValueRGBW(colorIn); - return colorIn; -} - - - -uint32_t _htmlColorToValueRGBW(uint32_t colorIn) -{ - uint32_t colorOut; - /* hex 00RRGGBB -> GGRRWWBB */ - /* RGBW GGRRWWBB GGRRWWBB GGRRWWBB */ - /* html 00RRGGBB 00RRGGBB 00RRGGBB*/ - colorOut=(colorIn & 0x00ff0000) | ((colorIn<<16) & 0xff000000) | (colorIn & 0x000000ff); - return colorOut; -} - - - -uint32_t _rgbwToHtmlColor(uint32_t colorIn) -{ - uint32_t colorOut; - /* RGBW GGRRWWBB GGRRWWBB GGRRWWBB */ - /* hex 00RRGGBB 00RRGGBB 00RRGGBB*/ - colorOut=(colorIn & 0x00ff0000) | ( (colorIn>>16) & 0x0000ff00) | (colorIn & 0x000000ff); - return colorOut; -} - - - -void _setRgbwData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue) -{ - if (sValue) { - const char *sValueSystemName; - uint32_t color; - int rv; - - sValueSystemName=AQH_Value_GetNameForSystem(value); - color=_colorFromHexString(sValue); - DBG_ERROR(NULL, "Send value [#%08x] to %s", color, sValueSystemName); - rv=AQH_DataClient_SetData(dc, value, (double) color); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - } - } -} - - - -void _setOnOffData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue) -{ - if (sValue) { - const char *sValueSystemName; - int rv; - - sValueSystemName=AQH_Value_GetNameForSystem(value); - if (strcasecmp(sValue, "unchanged")==0) { - DBG_ERROR(NULL, "Value %s unchanged", sValueSystemName); - } - else if (strcasecmp(sValue, "on")==0) { - DBG_ERROR(NULL, "Send value 1 to %s", sValueSystemName); - rv=AQH_DataClient_SetData(dc, value, 1.0); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - } - } - else if (strcasecmp(sValue, "off")==0) { - DBG_ERROR(NULL, "Send value 0 to %s", sValueSystemName); - rv=AQH_DataClient_SetData(dc, value, 0.0); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - } - } - else { - } - } -} - - - -void _setOnOffAutoData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char *sValue) -{ - if (sValue) { - const char *sValueSystemName; - int rv; - - sValueSystemName=AQH_Value_GetNameForSystem(value); - if (strcasecmp(sValue, "unchanged")==0) { - DBG_ERROR(NULL, "Value %s unchanged", sValueSystemName); - } - else if (strcasecmp(sValue, "on")==0) { - DBG_ERROR(NULL, "Send value 1 to %s", sValueSystemName); - rv=AQH_DataClient_SetData(dc, value, 1.0); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - } - } - else if (strcasecmp(sValue, "off")==0) { - DBG_ERROR(NULL, "Send value 0 to %s", sValueSystemName); - rv=AQH_DataClient_SetData(dc, value, 0.0); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - } - } - else if (strcasecmp(sValue, "auto")==0) { - DBG_ERROR(NULL, "Send value 2 to %s", sValueSystemName); - rv=AQH_DataClient_SetData(dc, value, 2.0); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - } - } - else { - DBG_ERROR(NULL, "Invalid value [%s] for %s", sValue, sValueSystemName); - } - } -} - - - -void _addLastValueToForm(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER *dbuf) -{ - const char *sValueSystemName; - const char *sValueName; - uint64_t dataPoints[2]; - uint64_t recvdNum; -// uint64_t timestamp; - union {double f; uint64_t i;} u; - int intVal; - - sValueSystemName=AQH_Value_GetNameForSystem(value); - sValueName=AQH_Value_GetName(value); - recvdNum=AQH_DataClient_GetLastData(dc, sValueSystemName, &dataPoints[0], 1); - if (recvdNum>0) { -// timestamp=dataPoints[0]; - u.i=dataPoints[1]; - intVal=(int) u.f; - } - else { - u.i=0; - intVal=-1; - } - - if (AQH_Value_GetValueType(value)==AQH_ValueType_Actor) { - DBG_ERROR(NULL, "Adding actor"); - switch(AQH_Value_GetModality(value)) { - case AQH_ValueModality_RGBW: - DBG_ERROR(NULL, "Color: %.f RGBW=%08x HTML=%08x, RGBW2=%08x", - u.f, - (uint32_t) (u.f), - _rgbwToHtmlColor(u.f), - _htmlColorToValueRGBW(_rgbwToHtmlColor(u.f))); -#if 1 - GBAA(dbuf, "", sValueName, (uint32_t) (u.f)); -#else - GBAA(dbuf, "#%08x (#%08x)", - sValueName, - _rgbwToHtmlColor((unsigned int) (u.f)), - _rgbwToHtmlColor((unsigned int) (u.f)), - (uint32_t) (u.f)); -#endif - break; - case AQH_ValueModality_OnOff: - GBAA(dbuf, ""); - break; - case AQH_ValueModality_OnOffAuto: - GBAA(dbuf, ""); - break; - default: - // GBAA(dbuf, "", sValueName, u.f); - GBAA(dbuf, "%.2f", u.f); - break; - } /* switch */ - } /* if actor */ - else { - DBG_ERROR(NULL, "Adding sensor (%s=%.2f)", sValueName, u.f); - GBAA(dbuf, "%.2f", u.f); - } -} - - - -void _mkValueForm(AQH_DATACLIENT *dc, const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf) -{ - const char *sValueSystemName; - const char *sValueName; - uint64_t dataPoints[2]; - uint64_t recvdNum; - // uint64_t timestamp; - union {double f; uint64_t i;} u; - int intVal; - - sValueSystemName=AQH_Value_GetNameForSystem(value); - sValueName=AQH_Value_GetName(value); - recvdNum=AQH_DataClient_GetLastData(dc, sValueSystemName, &dataPoints[0], 1); - if (recvdNum>0) { - // timestamp=dataPoints[0]; - u.i=dataPoints[1]; - intVal=(int) u.f; - } - else { - u.i=0; - intVal=-1; - } - - GBAA(dbuf,"

Value %s/%s

\n", sDeviceName, sValueName); - - GBAS(dbuf,"
\n"); - GBAA(dbuf, "\n", sDeviceName); - GBAA(dbuf, "\n", sValueName); - - DBG_ERROR(NULL, "Adding actor"); - switch(AQH_Value_GetModality(value)) { - case AQH_ValueModality_RGBW: - DBG_ERROR(NULL, "Color: %.f RGBW=%08x HTML=%08x, RGBW2=%08x", - u.f, - (uint32_t) (u.f), - _rgbwToHtmlColor(u.f), - _htmlColorToValueRGBW(_rgbwToHtmlColor(u.f))); -#if 1 - GBAA(dbuf, "", sValueName, (uint32_t) (u.f)); -#else - GBAA(dbuf, "#%08x (#%08x)", - sValueName, - _rgbwToHtmlColor((unsigned int) (u.f)), - _rgbwToHtmlColor((unsigned int) (u.f)), - (uint32_t) (u.f)); -#endif - break; - case AQH_ValueModality_OnOff: - GBAA(dbuf, ""); - break; - case AQH_ValueModality_OnOffAuto: - GBAA(dbuf, ""); - break; - default: - // GBAA(dbuf, "", sValueName, u.f); - GBAA(dbuf, "%.2f", u.f); - break; - } /* switch */ - - GBAS(dbuf,""); - GBAS(dbuf, "
\n\n"); -} - - - diff --git a/apps/aqhome-cgi/modules/mroot.c b/apps/aqhome-cgi/modules/mroot.c index 84e9b74..e9a5c8d 100644 --- a/apps/aqhome-cgi/modules/mroot.c +++ b/apps/aqhome-cgi/modules/mroot.c @@ -14,7 +14,7 @@ #include "./mroot_p.h" #include "aqhome-cgi/service/module.h" -#include "aqhome-cgi/modules/mdevices.h" +#include "aqhome-cgi/modules/devices/mdevices.h" #include "aqhome-cgi/modules/common/madmin.h" #include diff --git a/apps/aqhome-cgi/service/service.c b/apps/aqhome-cgi/service/service.c index c163972..f0abdfd 100644 --- a/apps/aqhome-cgi/service/service.c +++ b/apps/aqhome-cgi/service/service.c @@ -27,7 +27,7 @@ GWEN_LIST_FUNCTIONS(AQH_SERVICE, AQH_Service); -AQH_SERVICE *AQH_Service_new(void) +AQH_SERVICE *AQH_Service_new(const char *baseFolder, const char *baseUrl) { AQH_SERVICE *sv; @@ -35,6 +35,32 @@ AQH_SERVICE *AQH_Service_new(void) GWEN_INHERIT_INIT(AQH_SERVICE, sv); GWEN_LIST_INIT(AQH_SERVICE, sv); + sv->baseUrl=baseUrl?strdup(baseUrl):NULL; + sv->baseFolder=baseFolder?strdup(baseFolder):NULL; + + if (sv->baseFolder) { + GWEN_BUFFER *dbuf; + uint32_t pos; + + dbuf=GWEN_Buffer_new(0, 256, 0, 1); + GWEN_Buffer_AppendArgs(dbuf, "%s%s", sv->baseFolder, GWEN_DIR_SEPARATOR_S); + pos=GWEN_Buffer_GetPos(dbuf); + + /* data folder */ + GWEN_Buffer_AppendString(dbuf, "data"); + sv->runtimeFolder=strdup(GWEN_Buffer_GetStart(dbuf)); + DBG_ERROR(NULL, "Runtime folder: %s", GWEN_Buffer_GetStart(dbuf)); + GWEN_Buffer_Crop(dbuf, 0, pos); + + /* cache folder */ + GWEN_Buffer_AppendString(dbuf, "cache"); + sv->cacheFolder=strdup(GWEN_Buffer_GetStart(dbuf)); + DBG_ERROR(NULL, "Cache folder: %s", GWEN_Buffer_GetStart(dbuf)); + GWEN_Buffer_Crop(dbuf, 0, pos); + + GWEN_Buffer_free(dbuf); + } + return sv; } @@ -46,11 +72,44 @@ void AQH_Service_free(AQH_SERVICE *sv) GWEN_LIST_FINI(AQH_SERVICE, sv); GWEN_INHERIT_FINI(AQH_SERVICE, sv); + free(sv->baseUrl); + free(sv->baseFolder); + free(sv->runtimeFolder); + free(sv->cacheFolder); GWEN_FREE_OBJECT(sv); } } + +const char *AQH_Service_GetBaseUrl(const AQH_SERVICE *sv) +{ + return sv?sv->baseUrl:NULL; +} + + + +const char *AQH_Service_GetBaseFolder(const AQH_SERVICE *sv) +{ + return sv?sv->baseFolder:NULL; +} + + + +const char *AQH_Service_GetRuntimeFolder(const AQH_SERVICE *sv) +{ + return sv?sv->runtimeFolder:NULL; +} + + + +const char *AQH_Service_GetCacheFolder(const AQH_SERVICE *sv) +{ + return sv?sv->cacheFolder:NULL; +} + + + #if 0 AQH_MODULE *AQH_Service_GetModuleByPath(const AQH_SERVICE *sv, const char *s) { diff --git a/apps/aqhome-cgi/service/service.h b/apps/aqhome-cgi/service/service.h index e8b258f..ae2e3b4 100644 --- a/apps/aqhome-cgi/service/service.h +++ b/apps/aqhome-cgi/service/service.h @@ -52,10 +52,13 @@ typedef GWEN_STRINGLIST* (*AQH_SERVICE_LISTSESSIONS_FN)(AQH_SERVICE *sv); -AQH_SERVICE *AQH_Service_new(void); +AQH_SERVICE *AQH_Service_new(const char *baseFolder, const char *baseUrl); void AQH_Service_free(AQH_SERVICE *sv); - +const char *AQH_Service_GetBaseUrl(const AQH_SERVICE *sv); +const char *AQH_Service_GetBaseFolder(const AQH_SERVICE *sv); +const char *AQH_Service_GetRuntimeFolder(const AQH_SERVICE *sv); +const char *AQH_Service_GetCacheFolder(const AQH_SERVICE *sv); int AQH_Service_HandleRequest(AQH_SERVICE *sv, AQCGI_REQUEST *req); diff --git a/apps/aqhome-cgi/service/service_p.h b/apps/aqhome-cgi/service/service_p.h index 7311e35..75a519c 100644 --- a/apps/aqhome-cgi/service/service_p.h +++ b/apps/aqhome-cgi/service/service_p.h @@ -17,6 +17,11 @@ struct AQH_SERVICE { GWEN_INHERIT_ELEMENT(AQH_SERVICE); GWEN_LIST_ELEMENT(AQH_SERVICE); + char *baseUrl; + char *baseFolder; + char *runtimeFolder; + char *cacheFolder; + AQH_SERVICE_HANDLEREQUEST_FN handleRequestFn; AQH_SERVICE_LOADUSER_FN loadUserFn; diff --git a/apps/aqhome-cgi/service_file.c b/apps/aqhome-cgi/service_file.c index eabafd0..5f5d6c3 100644 --- a/apps/aqhome-cgi/service_file.c +++ b/apps/aqhome-cgi/service_file.c @@ -79,16 +79,15 @@ static GWEN_STRINGLIST *_listGroup(AQH_SERVICE *sv, const char *groupName); * ------------------------------------------------------------------------------------------------ */ -AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder) +AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder, const char *baseUrl) { AQH_SERVICE *sv; AQH_SERVICE_FILE *xs; GWEN_BUFFER *dbuf; - sv=AQH_Service_new(); + sv=AQH_Service_new(baseFolder, baseUrl); GWEN_NEW_OBJECT(AQH_SERVICE_FILE, xs); GWEN_INHERIT_SETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv, xs, _freeData); - xs->baseFolder=strdup(baseFolder); AQH_Service_SetLoadUserFn(sv, _loadUser); AQH_Service_SetSaveUserFn(sv, _saveUser); @@ -109,7 +108,7 @@ AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder) AQH_Service_SetListSessionsFn(sv, _listSessions); dbuf=GWEN_Buffer_new(0, 256, 0, 1); - GWEN_Buffer_AppendArgs(dbuf, "dir://%s", baseFolder); + GWEN_Buffer_AppendArgs(dbuf, "dir://%s", AQH_Service_GetRuntimeFolder(sv)); DBG_ERROR(NULL, "Creating config mgr \"%s\"", GWEN_Buffer_GetStart(dbuf)); xs->configMgr=GWEN_ConfigMgr_Factory(GWEN_Buffer_GetStart(dbuf)); if (xs->configMgr==NULL) { @@ -131,7 +130,6 @@ void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p) xs=(AQH_SERVICE_FILE*) p; GWEN_ConfigMgr_free(xs->configMgr); - free(xs->baseFolder); GWEN_FREE_OBJECT(xs); } diff --git a/apps/aqhome-cgi/service_file.h b/apps/aqhome-cgi/service_file.h index 85e1c44..b29052e 100644 --- a/apps/aqhome-cgi/service_file.h +++ b/apps/aqhome-cgi/service_file.h @@ -13,7 +13,7 @@ #include "aqhome-cgi/service/service.h" -AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder); +AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder, const char *baseUrl); diff --git a/apps/aqhome-cgi/service_file_p.h b/apps/aqhome-cgi/service_file_p.h index afee436..018c46f 100644 --- a/apps/aqhome-cgi/service_file_p.h +++ b/apps/aqhome-cgi/service_file_p.h @@ -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. @@ -18,7 +18,6 @@ typedef struct AQH_SERVICE_FILE AQH_SERVICE_FILE; struct AQH_SERVICE_FILE { - char *baseFolder; GWEN_CONFIGMGR *configMgr; };