more work on aqhome-cgi.

This commit is contained in:
Martin Preuss
2025-10-23 20:58:40 +02:00
parent 9fec57511a
commit 39dba4ccb8
11 changed files with 264 additions and 85 deletions

View File

@@ -54,7 +54,8 @@
mdevices.h
mdevices_init.h
mdevices_index.h
mdevices_values.h
mdevices_valuestable.h
mdevices_valuesgraph.h
mdevices_value.h
mdevices_setdata.h
mdevices_vgraph.h
@@ -71,7 +72,8 @@
mdevices.c
mdevices_init.c
mdevices_index.c
mdevices_values.c
mdevices_valuestable.c
mdevices_valuesgraph.c
mdevices_value.c
mdevices_setdata.c
mdevices_vgraph.c

View File

@@ -14,7 +14,8 @@
#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_valuestable.h"
#include "aqhome-cgi/modules/devices/mdevices_valuesgraph.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"
@@ -50,7 +51,8 @@ static AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION
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 _handleRqValuesTableGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqValuesGraphGet(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);
@@ -67,7 +69,8 @@ static void _addLastValueToForm(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN
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},
{"vtable.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqValuesTableGet},
{"vgraph.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqValuesGraphGet},
{"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},
@@ -112,9 +115,16 @@ void _handleRqIndexGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, G
void _handleRqValuesGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
void _handleRqValuesTableGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunValues, dbuf);
AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunValuesAsTable, dbuf);
}
void _handleRqValuesGraphGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunValuesAsGraph, dbuf);
}
@@ -300,4 +310,37 @@ void _addLastValueToForm(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER
AQH_VALUE *AQH_ModDevices_GetValueForDevice(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;
}

View File

@@ -32,6 +32,10 @@
#define AQH_MODDEVICES_PERMS_VALUESET 0x100
#define AQH_MODDEVICES_GRAPH_WIDTH 640
#define AQH_MODDEVICES_GRAPH_HEIGHT 480
void AQH_ModDevices_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder);
int AQH_ModDevices_Create(AQH_SERVICE *sv);
@@ -41,6 +45,8 @@ uint32_t AQH_ModDevices_ColorFromHexString(const char *s);
uint32_t AQH_ModDevices_HtmlColorToValueRGBW(uint32_t colorIn);
uint32_t AQH_ModDevices_RgbwToHtmlColor(uint32_t colorIn);
AQH_VALUE *AQH_ModDevices_GetValueForDevice(AQH_DATACLIENT *dc, const char *sDeviceName, const char *sValueName);

View File

@@ -36,6 +36,8 @@
* ------------------------------------------------------------------------------------------------
*/
static void _addLinkForDevice(const char *page, const char *sDevice, const char *action, const char *imgName, GWEN_BUFFER *dbuf);
/* ------------------------------------------------------------------------------------------------
@@ -67,6 +69,7 @@ void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *sess
"<th>Room</th>"
"<th>Location</th>"
"<th>Description</th>"
"<th>Actions</th>"
"</tr>\n"
"</thead>\n"
"<tbody>\n");
@@ -74,17 +77,12 @@ void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *sess
device=AQH_Device_List_First(deviceList);
while(device) {
const char *s;
const char *sDevice;
GBAA(dbuf, "<tr>");
/* name for system */
s=AQH_Device_GetNameForSystem(device);
if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) {
GBAS(dbuf,"<td><a href=\"values.html?device=");
GWEN_Text_EscapeToBufferTolerant(s, dbuf);
GBAA(dbuf,"\">%s</a></td>", s?s:"");
}
else
GBAA(dbuf,"<td>%s</td>", s?s:"");
sDevice=AQH_Device_GetNameForSystem(device);
GBAA(dbuf,"<td>%s</td>", sDevice?sDevice:"");
/* room */
s=AQH_Device_GetRoomName(device);
GBAA(dbuf, "<td>%s</td>", s?s:"");
@@ -95,6 +93,14 @@ void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *sess
s=AQH_Device_GetDescription(device);
GBAA(dbuf, "<td>%s</td>", s?s:"");
GBAS(dbuf, "<td>");
if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) {
_addLinkForDevice("vtable.html", sDevice, "table view", "/pics/document-table.png", dbuf);
_addLinkForDevice("vgraph.html", sDevice, "graph view", "/pics/graph.png", dbuf);
// TODO: add edit link
}
GBAS(dbuf, "</td>");
GBAA(dbuf, "</tr>");
device=AQH_Device_List_Next(device);
}
@@ -107,4 +113,15 @@ void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *sess
void _addLinkForDevice(const char *page, const char *sDevice, const char *action, const char *imgName, GWEN_BUFFER *dbuf)
{
GBAA(dbuf,"<a href=\"%s?device=", page);
GWEN_Text_EscapeToBufferTolerant(sDevice, dbuf);
GBAS(dbuf,"\">");
GBAA(dbuf,"<img src=\"%s\" alt=\"action\" />", imgName);
GBAS(dbuf,"</a>");
}

View File

@@ -53,7 +53,7 @@ void AQH_ModDevices_RunSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *se
GWEN_DB_NODE *dbPost;
const char *sDeviceName;
const char *sValueName;
AQH_VALUE_LIST *valueList;
const AQH_VALUE *value;
/* sample data */
sv=AQH_ModService_GetService(m);
@@ -61,33 +61,25 @@ void AQH_ModDevices_RunSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *se
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;
value=AQH_ModDevices_GetValueForDevice(dc, sDeviceName, sValueName);
if(value && 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 */
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) */
}
AQH_Value_List_free(valueList);
if (sDeviceName && *sDeviceName) {
GWEN_BUFFER *pbuf;

View File

@@ -0,0 +1,125 @@
/****************************************************************************
* 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 <config.h>
#endif
#include "./mdevices_valuesgraph.h"
#include "./mdevices_index.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* 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, GWEN_BUFFER *dbuf);
static void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf);
static void _addGraphLink(const char *sDeviceName, const char *sValueName, const char *sPeriod, GWEN_BUFFER *dbuf);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModDevices_RunValuesAsGraph(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf)
{
GWEN_DB_NODE *dbQuery;
const char *sDeviceName;
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,"<h1>Values for Device %s</h1>\n", sDeviceName);
_writeValueListToTable(sDeviceName, valueList, dbuf);
GBAS(dbuf, "\n");
}
else {
GBAS(dbuf,"<p>No values.</p>\n");
}
AQH_Value_List_free(valueList);
}
}
void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf)
{
const AQH_VALUE *value;
GBAS(dbuf, "<table>\n");
value=AQH_Value_List_First(valueList);
while(value) {
if (AQH_Value_GetValueType(value)==AQH_ValueType_Sensor)
_writeValueToTable(sDeviceName, value, dbuf);
value=AQH_Value_List_Next(value);
}
GBAS(dbuf, "</table>\n");
}
void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf)
{
const char *sValueName;
/* name */
sValueName=AQH_Value_GetName(value);
GBAS(dbuf, "<tr><td>");
_addGraphLink(sDeviceName, sValueName, "1d", dbuf);
GBAS(dbuf, "</td><td>");
_addGraphLink(sDeviceName, sValueName, "1w", dbuf);
GBAS(dbuf, "</td></tr>\n");
}
void _addGraphLink(const char *sDeviceName, const char *sValueName, const char *sPeriod, GWEN_BUFFER *dbuf)
{
GBAS(dbuf, "<img src=\"graph.html?device=");
GWEN_Text_EscapeToBufferTolerant(sDeviceName, dbuf);
GBAS(dbuf, "&value=");
GWEN_Text_EscapeToBufferTolerant(sValueName, dbuf);
GBAA(dbuf, "&period=%s\"", sPeriod);
GBAA(dbuf, " alt=\"%s\" width=\"%d\" height=\"%d\"", sValueName, AQH_MODDEVICES_GRAPH_WIDTH, AQH_MODDEVICES_GRAPH_HEIGHT);
GBAS(dbuf, "/>");
}

View File

@@ -6,8 +6,8 @@
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_CGI_MDEVICES_VALUES_H
#define AQHOME_CGI_MDEVICES_VALUES_H
#ifndef AQHOME_CGI_MDEVICES_VALUESGRAPH_H
#define AQHOME_CGI_MDEVICES_VALUESGRAPH_H
#include "aqhome-cgi/modules/devices/mdevices.h"
@@ -21,7 +21,7 @@
void AQH_ModDevices_RunValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
void AQH_ModDevices_RunValuesAsGraph(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
#endif

View File

@@ -11,7 +11,7 @@
#endif
#include "./mdevices_values.h"
#include "./mdevices_valuestable.h"
#include "./mdevices_index.h"
#include "aqhome-cgi/service/module.h"
@@ -47,7 +47,7 @@ static void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value,
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModDevices_RunValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf)
void AQH_ModDevices_RunValuesAsTable(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf)
{
GWEN_DB_NODE *dbQuery;
const char *sDeviceName;

View File

@@ -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_VALUESTABLE_H
#define AQHOME_CGI_MDEVICES_VALUESTABLE_H
#include "aqhome-cgi/modules/devices/mdevices.h"
#include "aqhome/aqhome.h"
#include "aqhome/dataclient/client.h"
#include <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
void AQH_ModDevices_RunValuesAsTable(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
#endif

View File

@@ -41,6 +41,7 @@
#define GBAA GWEN_Buffer_AppendArgs
enum {
VALUEGRAPH_PERIOD_4H=1,
VALUEGRAPH_PERIOD_1D,
@@ -74,7 +75,6 @@ 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);
@@ -138,7 +138,7 @@ void _runGraphValueWithArgs(AQH_MODULE *m,
sDeviceName?sDeviceName:"<empty>", sValueName?sValueName:"<empty>",
sPeriod?sPeriod:"<empty>");
value=_getValue(dc, sDeviceName, sValueName);
value=AQH_ModDevices_GetValueForDevice(dc, sDeviceName, sValueName);
if (value) {
GWEN_BUFFER *fbuf;
int rv;
@@ -154,7 +154,7 @@ void _runGraphValueWithArgs(AQH_MODULE *m,
2,
AQH_ValueModality_toString(AQH_Value_GetModality(value)),
GWEN_Buffer_GetStart(fbuf),
640, 480,
AQH_MODDEVICES_GRAPH_WIDTH, AQH_MODDEVICES_GRAPH_HEIGHT,
100000);
}
@@ -270,8 +270,8 @@ AQDG_GRAPH *_mkGraphObjectWithTitle(const char *graphTitle, int period, int prec
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;
case VALUEGRAPH_PERIOD_1W: s="last 7 days"; break;
case VALUEGRAPH_PERIOD_1M: s="last 30 days"; break;
default: s="last 24 hours"; break;
}
@@ -352,7 +352,7 @@ const char *_getModifiersForPeriod(int period)
/* period */
switch(period) {
case VALUEGRAPH_PERIOD_4H: return "La5";
case VALUEGRAPH_PERIOD_1D: return "La15";
case VALUEGRAPH_PERIOD_1D: return "La30";
case VALUEGRAPH_PERIOD_1W: return "La240";
case VALUEGRAPH_PERIOD_1M: return "La480";
default: return "La15";
@@ -376,39 +376,6 @@ int _getAcceptedAgeForPeriod(int period)
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)
{