From 624b1648b5ce678c6c1ca44e13ff3c067c782896 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Tue, 7 Oct 2025 18:09:45 +0200 Subject: [PATCH 01/24] remove string data. --- apps/aqhome-react/types/dataobject.h | 4 ---- apps/aqhome-react/types/dataobject_p.h | 1 - 2 files changed, 5 deletions(-) diff --git a/apps/aqhome-react/types/dataobject.h b/apps/aqhome-react/types/dataobject.h index 4f5cf82..d539165 100644 --- a/apps/aqhome-react/types/dataobject.h +++ b/apps/aqhome-react/types/dataobject.h @@ -21,7 +21,6 @@ GWEN_LIST_FUNCTION_DEFS(AQHREACT_DATAOBJECT, AQHREACT_DataObject) enum { AQHREACT_DATAOBJECTTYPE_UNKNOWN=0, AQHREACT_DATAOBJECTTYPE_DOUBLE, - AQHREACT_DATAOBJECTTYPE_STRING, AQHREACT_DATAOBJECTTYPE_INT }; @@ -54,9 +53,6 @@ void AQHREACT_DataObject_SetDataType(AQHREACT_DATAOBJECT *dataObject, int i); double AQHREACT_DataObject_GetDoubleData(const AQHREACT_DATAOBJECT *dataObject); void AQHREACT_DataObject_SetDoubleData(AQHREACT_DATAOBJECT *dataObject, double i); -const char *AQHREACT_DataObject_GetStringData(const AQHREACT_DATAOBJECT *dataObject); -void AQHREACT_DataObject_SetStringData(AQHREACT_DATAOBJECT *dataObject, const char *s); - int AQHREACT_DataObject_GetIntData(const AQHREACT_DATAOBJECT *dataObject); void AQHREACT_DataObject_SetIntData(AQHREACT_DATAOBJECT *dataObject, int i); diff --git a/apps/aqhome-react/types/dataobject_p.h b/apps/aqhome-react/types/dataobject_p.h index 556b2ca..a10d628 100644 --- a/apps/aqhome-react/types/dataobject_p.h +++ b/apps/aqhome-react/types/dataobject_p.h @@ -24,7 +24,6 @@ struct AQHREACT_DATAOBJECT { int dataType; double doubleData; int intData; - char *stringData; }; From 1aeeed98453883608b03c70d1b686098277a71ea Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Tue, 7 Oct 2025 18:09:53 +0200 Subject: [PATCH 02/24] Revert "remove string data." This reverts commit 624b1648b5ce678c6c1ca44e13ff3c067c782896. --- apps/aqhome-react/types/dataobject.h | 4 ++++ apps/aqhome-react/types/dataobject_p.h | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/aqhome-react/types/dataobject.h b/apps/aqhome-react/types/dataobject.h index d539165..4f5cf82 100644 --- a/apps/aqhome-react/types/dataobject.h +++ b/apps/aqhome-react/types/dataobject.h @@ -21,6 +21,7 @@ GWEN_LIST_FUNCTION_DEFS(AQHREACT_DATAOBJECT, AQHREACT_DataObject) enum { AQHREACT_DATAOBJECTTYPE_UNKNOWN=0, AQHREACT_DATAOBJECTTYPE_DOUBLE, + AQHREACT_DATAOBJECTTYPE_STRING, AQHREACT_DATAOBJECTTYPE_INT }; @@ -53,6 +54,9 @@ void AQHREACT_DataObject_SetDataType(AQHREACT_DATAOBJECT *dataObject, int i); double AQHREACT_DataObject_GetDoubleData(const AQHREACT_DATAOBJECT *dataObject); void AQHREACT_DataObject_SetDoubleData(AQHREACT_DATAOBJECT *dataObject, double i); +const char *AQHREACT_DataObject_GetStringData(const AQHREACT_DATAOBJECT *dataObject); +void AQHREACT_DataObject_SetStringData(AQHREACT_DATAOBJECT *dataObject, const char *s); + int AQHREACT_DataObject_GetIntData(const AQHREACT_DATAOBJECT *dataObject); void AQHREACT_DataObject_SetIntData(AQHREACT_DATAOBJECT *dataObject, int i); diff --git a/apps/aqhome-react/types/dataobject_p.h b/apps/aqhome-react/types/dataobject_p.h index a10d628..556b2ca 100644 --- a/apps/aqhome-react/types/dataobject_p.h +++ b/apps/aqhome-react/types/dataobject_p.h @@ -24,6 +24,7 @@ struct AQHREACT_DATAOBJECT { int dataType; double doubleData; int intData; + char *stringData; }; From d0c8b3b284c8ec192d491d290f662beae4bcca1a Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Tue, 7 Oct 2025 23:50:50 +0200 Subject: [PATCH 03/24] let setData use double values instead of strings. this allows for storing value set with setData which can then be used in the cgi module to retrieve the last value set. --- apps/aqhome-cgi/modules/mdevices.c | 240 ++++++++++++++------- apps/aqhome-data/s_setdata.c | 35 ++- apps/aqhome-mqttlog/s_setdata.c | 74 +++++-- apps/aqhome-mqttlog/types/translation.t2d | 6 +- apps/aqhome-mqttlog/xmlread.c | 8 +- apps/aqhome-mqttlog/xmlwrite.c | 2 +- apps/aqhome-nodes/r_setdata.c | 5 +- apps/aqhome-react/examples/001-tvlight.xml | 12 +- apps/aqhome-react/networks/delayedoff.xml | 2 +- apps/aqhome-react/types/prgrule.c | 27 ++- apps/aqhome-react/units/u_valueset.c | 36 +--- apps/aqhome-tool/data/setdata.c | 54 ++++- aqhome/aqhome.c | 57 +++++ aqhome/aqhome.h | 1 + aqhome/dataclient/client.c | 2 +- aqhome/dataclient/client.h | 2 +- aqhome/msg/ipc/data/m_ipcd_setdata.c | 18 +- aqhome/msg/ipc/data/m_ipcd_setdata.h | 4 +- aqhome/msg/ipc/m_ipc_tag16.c | 13 ++ aqhome/msg/ipc/m_ipc_tag16.h | 1 + devices/mqtt/tasmota_plug.xml | 4 +- devices/mqtt/tasmota_plug_old.xml | 4 +- 22 files changed, 421 insertions(+), 186 deletions(-) diff --git a/apps/aqhome-cgi/modules/mdevices.c b/apps/aqhome-cgi/modules/mdevices.c index baca810..3b57ca0 100644 --- a/apps/aqhome-cgi/modules/mdevices.c +++ b/apps/aqhome-cgi/modules/mdevices.c @@ -55,10 +55,14 @@ static void _runIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQ static void _runValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, 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 AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf); -static void _writeValueToTable(const AQH_VALUE *value, GWEN_BUFFER *dbuf); +static void _writeValueListToTable(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf); +static void _writeValueToTable(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER *dbuf); static void _addValueActionToForm(const AQH_VALUE *value, GWEN_BUFFER *dbuf); static uint32_t _colorFromHexString(const char *s); +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); @@ -309,7 +313,7 @@ void _runValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATA GBAS(dbuf,"
\n"); GBAA(dbuf, "\n", sDeviceName); - _writeValueListToTable(valueList, dbuf); + _writeValueListToTable(dc, valueList, dbuf); GBAS(dbuf,""); GBAS(dbuf, "
\n\n"); @@ -341,86 +345,17 @@ void _runSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DAT value=AQH_Value_List_First(valueList); while(value) { if (AQH_Value_GetValueType(value)==AQH_ValueType_Actor) { - const char *sValueSystemName; const char *sValueName; const char *sValue; - int rv; - sValueSystemName=AQH_Value_GetNameForSystem(value); 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: - if (sValue) { - uint32_t color; - char colbuf[16]; - - color=_colorFromHexString(sValue); - snprintf(colbuf, sizeof(colbuf), "0x%08x", color); - DBG_ERROR(NULL, "Send value [%s] to %s", colbuf, sValueSystemName); - rv=AQH_DataClient_SetData(dc, value, colbuf); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - GBAA(dbuf, "

Error setting value for %s

", sValueSystemName); - } - } - break; - case AQH_ValueModality_OnOff: - if (sValue) { - 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"); - 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"); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - } - } - else { - } - } - break; - case AQH_ValueModality_OnOffAuto: - if (sValue) { - 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"); - 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"); - 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"); - if (rv<0) { - DBG_ERROR(NULL, "Error sending data: %d", rv); - } - } - else { - DBG_ERROR(NULL, "Invalid value [%s] for %s", sValue, sValueSystemName); - } - } - break; + 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 */ @@ -428,10 +363,8 @@ void _runSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DAT } value=AQH_Value_List_Next(value); } /* while */ - - } - AQH_Value_List_free(valueList); + AQH_Value_List_free(valueList); if (sDeviceName && *sDeviceName) { GWEN_BUFFER *pbuf; @@ -448,7 +381,7 @@ void _runSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DAT -void _writeValueListToTable(const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf) +void _writeValueListToTable(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf) { const AQH_VALUE *value; @@ -471,7 +404,7 @@ void _writeValueListToTable(const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf) value=AQH_Value_List_First(valueList); while(value) { - _writeValueToTable(value, dbuf); + _writeValueToTable(dc, value, dbuf); value=AQH_Value_List_Next(value); } GBAS(dbuf, @@ -481,7 +414,7 @@ void _writeValueListToTable(const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf) -void _writeValueToTable(const AQH_VALUE *value, GWEN_BUFFER *dbuf) +void _writeValueToTable(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER *dbuf) { const char *s; @@ -508,8 +441,7 @@ void _writeValueToTable(const AQH_VALUE *value, GWEN_BUFFER *dbuf) #endif GBAS(dbuf, ""); - if (AQH_Value_GetValueType(value)==AQH_ValueType_Actor) - _addValueActionToForm(value, dbuf); + _addLastValueToForm(dc, value, dbuf); GBAS(dbuf, ""); GBAA(dbuf, "\n"); @@ -579,6 +511,148 @@ uint32_t _colorFromHexString(const char *s) +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: + GBAA(dbuf, "", sValueName, (unsigned int) u.f); + 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-data/s_setdata.c b/apps/aqhome-data/s_setdata.c index a80e113..aa4360b 100644 --- a/apps/aqhome-data/s_setdata.c +++ b/apps/aqhome-data/s_setdata.c @@ -42,14 +42,15 @@ * ------------------------------------------------------------------------------------------------ */ +static void _storeDatapoint(AQHOME_SERVER *xo, const AQH_VALUE *v, double valueData); static AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, uint32_t requestMsgId, AQH_OBJECT *epDriver, - const AQH_VALUE *v, const char *data); + const AQH_VALUE *v, double data); static void _rqSubRequestFinished(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST *subRq, int reason); static void _rqAbort(AQH_MSG_REQUEST *rq, int reason); -static AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, const char *data); +static AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, double data); static int _subRqHandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg); static void _subRqAbort(AQH_MSG_REQUEST *rq, int reason); @@ -76,11 +77,11 @@ void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_ recvdValue=AQH_IpcdMessageSetData_ReadValue(tagList); if (recvdValue) { const char *valueName; - char *valueDataFreeable; + double valueData; AQH_VALUE *systemValue; valueName=AQH_Value_GetNameForSystem(recvdValue); - valueDataFreeable=AQH_IpcdMessageSetData_ReadData(tagList); + valueData=AQH_IpcdMessageSetData_ReadData(tagList); systemValue=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName); if (systemValue) { @@ -96,8 +97,10 @@ void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_ AQH_MSG_REQUEST *rq; DBG_ERROR(NULL, "Creating SETDATA request for driver endpoint (%s)", AQH_Endpoint_GetServiceName(epDriver)); - rq=_mkRequest_SetData(o, epSrc, msgId, epDriver, systemValue, valueDataFreeable); + rq=_mkRequest_SetData(o, epSrc, msgId, epDriver, systemValue, valueData); AqHomeDataServer_AddRequestToTree(o, rq); + + _storeDatapoint(xo, systemValue, valueData); } else { DBG_ERROR(NULL, "Driver \"%s\" not available", driverName); @@ -119,7 +122,6 @@ void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_ AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_NOTFOUND); } AQH_Value_free(recvdValue); - free(valueDataFreeable); } /* if recvdValue */ else { DBG_ERROR(NULL, "No value in message"); @@ -131,6 +133,23 @@ void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_ +void _storeDatapoint(AQHOME_SERVER *xo, const AQH_VALUE *v, double valueData) +{ + uint64_t timestamp; + int rv; + + timestamp=(uint64_t) time(NULL); + rv=AQH_Storage_AddDatapoint(xo->storage, AQH_Value_GetId(v), timestamp, valueData); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + } + else { + DBG_INFO(NULL, "Datapoint added for value \"%s\"", AQH_Value_GetNameForSystem(v)); + } +} + + + /* ------------------------------------------------------------------------------------------------ * IPC Request SETDATA */ @@ -138,7 +157,7 @@ void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_ AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, uint32_t requestMsgId, AQH_OBJECT *epDriver, - const AQH_VALUE *v, const char *data) + const AQH_VALUE *v, double data) { AQH_MSG_REQUEST *rq; AQH_MSG_REQUEST *subRq; @@ -205,7 +224,7 @@ void _rqAbort(AQH_MSG_REQUEST *rq, int reason) */ -AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, const char *data) +AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, double data) { AQH_MSG_REQUEST *rq; uint16_t msgId; diff --git a/apps/aqhome-mqttlog/s_setdata.c b/apps/aqhome-mqttlog/s_setdata.c index 13aa5ea..74f1b05 100644 --- a/apps/aqhome-mqttlog/s_setdata.c +++ b/apps/aqhome-mqttlog/s_setdata.c @@ -30,8 +30,13 @@ */ static void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, - const char *valueName, const char *valueData); -static void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData); + const char *valueName, double valueData); +static void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, + const AQHMQTT_DEVICE *device, + const AQHMQTT_TOPIC *topic, + const AQHMQTT_VALUE *value, + double valueData); +static const char *_valueTranslatedForDriver(const AQHMQTT_VALUE *value, double valueData); static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic); @@ -65,12 +70,11 @@ void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o, device=AQH_MqttLogServer_FindRegisteredDevice(o, deviceName); if (device) { - char *valueDataFreeable; + double valueData; DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName); - valueDataFreeable=AQH_IpcdMessageSetData_ReadData(tagList); - _sendDataForDevice(xo, device, valueName, valueDataFreeable); - free(valueDataFreeable); + valueData=AQH_IpcdMessageSetData_ReadData(tagList); + _sendDataForDevice(xo, device, valueName, valueData); } else { DBG_ERROR(NULL, "Device \"%s\" not found", deviceName); @@ -93,7 +97,7 @@ void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o, void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, - const char *valueName, const char *valueData) + const char *valueName, double valueData) { const char *deviceId; @@ -116,7 +120,7 @@ void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, if (value) { /* found value, create publish msg, send */ DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName); - _sendValueToMqtt(xo, deviceId, topic, valueData); + _sendValueToMqtt(xo, device, topic, value, valueData); } } /* if out */ topic=AQHMQTT_Topic_List_Next(topic); @@ -130,32 +134,72 @@ void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, -void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData) +void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, + const AQHMQTT_DEVICE *device, + const AQHMQTT_TOPIC *topic, + const AQHMQTT_VALUE *value, + double valueData) { + const char *deviceId; + const char *translatedValue; GWEN_BUFFER *buf; #if !DEBUG_DRY_RUN AQH_MESSAGE *msgOut; #endif + deviceId=AQHMQTT_Device_GetId(device); buf=_createBufferForTopic(deviceId, topic); + translatedValue=_valueTranslatedForDriver(value, valueData); + if (translatedValue && *translatedValue) { + DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), translatedValue); + msgOut=AQH_MqttMessagePublish_new(0, 0, GWEN_Buffer_GetStart(buf), (const uint8_t*)translatedValue, strlen(translatedValue)); + } + else { + GWEN_BUFFER *vbuf; + + vbuf=GWEN_Buffer_new(0, 64, 0, 1); + GWEN_Buffer_AppendArgs(vbuf, "%f", valueData); + DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetStart(vbuf)); + msgOut=AQH_MqttMessagePublish_new(0, 0, + GWEN_Buffer_GetStart(buf), + (const uint8_t*)GWEN_Buffer_GetStart(vbuf), + GWEN_Buffer_GetUsedBytes(vbuf)); + GWEN_Buffer_free(vbuf); + } + #if !DEBUG_DRY_RUN - DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:""); - msgOut=AQH_MqttMessagePublish_new(0, 0, GWEN_Buffer_GetStart(buf), - (const uint8_t*) (valueData?valueData:NULL), - valueData?strlen(valueData):0); if (msgOut) AQH_Endpoint_AddMsgOut(xo->mqttEndpoint, msgOut); else { DBG_ERROR(NULL, "Error creating message"); } -#else - DBG_ERROR(NULL, "Would MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:""); #endif GWEN_Buffer_free(buf); } +const char *_valueTranslatedForDriver(const AQHMQTT_VALUE *value, double valueData) +{ + const AQHMQTT_TRANSLATION_LIST *translationList; + + translationList=AQHMQTT_Value_GetTranslationList(value); + if (translationList) { + const AQHMQTT_TRANSLATION *t; + int valueAsInt; + + valueAsInt=(int) valueData; + t=AQHMQTT_Translation_List_GetByAqhValue(translationList, valueAsInt); + if (t) { + return AQHMQTT_Translation_GetDriverValue(t); + } + } + + return NULL; +} + + + GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic) { GWEN_BUFFER *buf; diff --git a/apps/aqhome-mqttlog/types/translation.t2d b/apps/aqhome-mqttlog/types/translation.t2d index ce1d4dc..edf5e6c 100644 --- a/apps/aqhome-mqttlog/types/translation.t2d +++ b/apps/aqhome-mqttlog/types/translation.t2d @@ -32,18 +32,18 @@ - + 0 0 public - own + with_getByMember 0 0 public - own + own with_getByMember diff --git a/apps/aqhome-mqttlog/xmlread.c b/apps/aqhome-mqttlog/xmlread.c index 06649b1..ddb19bd 100644 --- a/apps/aqhome-mqttlog/xmlread.c +++ b/apps/aqhome-mqttlog/xmlread.c @@ -458,16 +458,16 @@ AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(GWEN_XMLNODE *parentNode) AQHMQTT_TRANSLATION *_readXmlTranslation(GWEN_XMLNODE *translationNode) { - const char *sAqhValue; + int aqhValue; const char *sDriverValue; - sAqhValue=GWEN_XMLNode_GetProperty(translationNode, "aqhValue", NULL); + aqhValue=GWEN_XMLNode_GetIntProperty(translationNode, "aqhValue", 0); sDriverValue=GWEN_XMLNode_GetProperty(translationNode, "driverValue", NULL); - if (sAqhValue && *sAqhValue && sDriverValue && *sDriverValue) { + if (sDriverValue && *sDriverValue) { AQHMQTT_TRANSLATION *translation; translation=AQHMQTT_Translation_new(); - AQHMQTT_Translation_SetAqhValue(translation, sAqhValue); + AQHMQTT_Translation_SetAqhValue(translation, aqhValue); AQHMQTT_Translation_SetDriverValue(translation, sDriverValue); return translation; } diff --git a/apps/aqhome-mqttlog/xmlwrite.c b/apps/aqhome-mqttlog/xmlwrite.c index d6ea5ea..af56843 100644 --- a/apps/aqhome-mqttlog/xmlwrite.c +++ b/apps/aqhome-mqttlog/xmlwrite.c @@ -222,7 +222,7 @@ void _writeValueToXml(const AQHMQTT_VALUE *value, GWEN_XMLNODE *node) void _writeTranslationToXml(const AQHMQTT_TRANSLATION *t, GWEN_XMLNODE *nTranslation) { - _setXmlPropertyIfNotNull(nTranslation, "aqhValue", AQHMQTT_Translation_GetAqhValue(t)); + GWEN_XMLNode_SetIntProperty(nTranslation, "aqhValue", AQHMQTT_Translation_GetAqhValue(t)); _setXmlPropertyIfNotNull(nTranslation, "driverValue", AQHMQTT_Translation_GetDriverValue(t)); } diff --git a/apps/aqhome-nodes/r_setdata.c b/apps/aqhome-nodes/r_setdata.c index 9ad5a22..6a38c66 100644 --- a/apps/aqhome-nodes/r_setdata.c +++ b/apps/aqhome-nodes/r_setdata.c @@ -92,7 +92,7 @@ void AQH_NodeServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSA varName=AQH_Value_GetName(value); if (varName) { - char *data; + double data; data=AQH_IpcdMessageSetData_ReadData(tagList); if (data) { @@ -115,7 +115,7 @@ void AQH_NodeServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSA uint16_t dataVal=0; uint16_t dataDenom=0; - if (AQH_ReadDataFromString(AQHNODE_Value_GetDataType(devValue), data, &dataVal, &dataDenom)==0) { + if (AQH_ReadDataFromDouble(AQHNODE_Value_GetDataType(devValue), data, &dataVal, &dataDenom)==0) { AQH_MSG_REQUEST *rq; int destAddr; @@ -150,7 +150,6 @@ void AQH_NodeServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSA DBG_ERROR(NULL, "No matching nodeinfo"); _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID); } - free(data); } else { DBG_ERROR(NULL, "No data"); diff --git a/apps/aqhome-react/examples/001-tvlight.xml b/apps/aqhome-react/examples/001-tvlight.xml index 707e5a3..b8e7ec6 100644 --- a/apps/aqhome-react/examples/001-tvlight.xml +++ b/apps/aqhome-react/examples/001-tvlight.xml @@ -26,15 +26,6 @@ - - - OFF - OFF - ON - - - - mqtt/109C2F/power @@ -49,7 +40,6 @@ - - + diff --git a/apps/aqhome-react/networks/delayedoff.xml b/apps/aqhome-react/networks/delayedoff.xml index ec1fe52..587b201 100644 --- a/apps/aqhome-react/networks/delayedoff.xml +++ b/apps/aqhome-react/networks/delayedoff.xml @@ -12,7 +12,7 @@ - + diff --git a/apps/aqhome-react/types/prgrule.c b/apps/aqhome-react/types/prgrule.c index 8dcca13..a572687 100644 --- a/apps/aqhome-react/types/prgrule.c +++ b/apps/aqhome-react/types/prgrule.c @@ -312,10 +312,29 @@ const char *_readValueAndProbablyRange(const char *s, uint64_t *ptrBitField, int { int v=0; - while(isdigit(*s)) { - v*=10; - v+=(*s)-'0'; - s++; + if (*s=='#') { + while(*s) { + unsigned char c; + + c=tolower(*s); + if ((c>='0' && c<='9') || (c>='a' && c<='f')) { + c-='0'; + if (c>9) + c-=7; + v<<=4; + v+=c; + } + else + break; + s++; + } + } + else { + while(isdigit(*s)) { + v*=10; + v+=(*s)-'0'; + s++; + } } if (!_valueOkay(v, minValue, maxValue)) { DBG_INFO(NULL, "here"); diff --git a/apps/aqhome-react/units/u_valueset.c b/apps/aqhome-react/units/u_valueset.c index 2ac6fd4..4643174 100644 --- a/apps/aqhome-react/units/u_valueset.c +++ b/apps/aqhome-react/units/u_valueset.c @@ -38,7 +38,6 @@ */ static void _cbInputData(AQHREACT_UNIT *unit, AQHREACT_PORT *port, const AQHREACT_DATAOBJECT *dataObject); -static AQH_MESSAGE *_mkSetDataMsgString(AQH_OBJECT *brokerEndpoint, const char *sValueName, const AQHREACT_DATAOBJECT *dataObject); static AQH_MESSAGE *_mkSetDataMsgDouble(AQH_OBJECT *brokerEndpoint, const char *sValueName, const AQHREACT_DATAOBJECT *dataObject); @@ -62,12 +61,12 @@ AQHREACT_UNIT *AqHomeReact_UnitValueSet_new(AQH_OBJECT *aqh) port=AQHREACT_Port_new(); AQHREACT_Port_SetName(port, "input"); AQHREACT_Port_SetIdForUnit(port, AQHOMEREACT_UNIT_VALUESET_INSLOT_VALUE); - AQHREACT_Port_SetDataType(port, AQHREACT_DATAOBJECTTYPE_STRING); + AQHREACT_Port_SetDataType(port, AQHREACT_DATAOBJECTTYPE_DOUBLE); AQHREACT_Unit_AddInputPort(unit, port); param=AQHREACT_Param_new(); AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUENAME); - AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_STRING); + AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_DOUBLE); AQHREACT_Unit_AddParam(unit, param); return unit; @@ -92,9 +91,6 @@ void _cbInputData(AQHREACT_UNIT *unit, AQHREACT_PORT *port, const AQHREACT_DATAO case AQHREACT_DATAOBJECTTYPE_DOUBLE: msgOut=_mkSetDataMsgDouble(brokerEndpoint, sValueName, dataObject); break; - case AQHREACT_DATAOBJECTTYPE_STRING: - msgOut=_mkSetDataMsgString(brokerEndpoint, sValueName, dataObject); - break; default: DBG_ERROR(NULL, "Unhandled data type (%d)", AQHREACT_DataObject_GetDataType(dataObject)); msgOut=NULL; @@ -130,47 +126,21 @@ void _cbInputData(AQHREACT_UNIT *unit, AQHREACT_PORT *port, const AQHREACT_DATAO -AQH_MESSAGE *_mkSetDataMsgString(AQH_OBJECT *brokerEndpoint, const char *sValueName, const AQHREACT_DATAOBJECT *dataObject) -{ - AQH_MESSAGE *msgOut; - AQH_VALUE *v; - - v=AQH_Value_new(); - AQH_Value_SetNameForSystem(v, sValueName); - - msgOut=AQH_IpcdMessageSetData_new(AQH_MSGTYPE_IPC_DATA_SETDATA, - AQH_Endpoint_GetNextMessageId(brokerEndpoint), 0, - v, AQHREACT_DataObject_GetStringData(dataObject)); - AQH_Value_free(v); - return msgOut; -} - - - AQH_MESSAGE *_mkSetDataMsgDouble(AQH_OBJECT *brokerEndpoint, const char *sValueName, const AQHREACT_DATAOBJECT *dataObject) { AQH_MESSAGE *msgOut; AQH_VALUE *v; double data; - GWEN_BUFFER *buf; int rv; v=AQH_Value_new(); AQH_Value_SetNameForSystem(v, sValueName); data=AQHREACT_DataObject_GetDoubleData(dataObject); - buf=GWEN_Buffer_new(0, 64, 0, 1); - rv=GWEN_Text_DoubleToBuffer(data, buf); - if (rv<0) { - GWEN_Buffer_free(buf); - AQH_Value_free(v); - return NULL; - } msgOut=AQH_IpcdMessageSetData_new(AQH_MSGTYPE_IPC_DATA_SETDATA, AQH_Endpoint_GetNextMessageId(brokerEndpoint), 0, - v, GWEN_Buffer_GetStart(buf)); - GWEN_Buffer_free(buf); + v, data); AQH_Value_free(v); return msgOut; } diff --git a/apps/aqhome-tool/data/setdata.c b/apps/aqhome-tool/data/setdata.c index 2faee5a..e2b2024 100644 --- a/apps/aqhome-tool/data/setdata.c +++ b/apps/aqhome-tool/data/setdata.c @@ -45,6 +45,7 @@ */ static AQH_MESSAGE *_createRequestMessage(AQH_OBJECT *o, uint32_t msgId); +static int _readValueFromString(const char *s, double *pDouble); @@ -93,18 +94,30 @@ AQH_MESSAGE *_createRequestMessage(GWEN_UNUSED AQH_OBJECT *o, uint32_t msgId) GWEN_DB_NODE *dbArgs; const char *valueName; const char *valueUnits; - const char *valueData; + const char *valueDataAsString; + double valueData; AQH_VALUE *v; + int rv; dbArgs=AQH_ToolClient_GetDbLocalArgs(o); valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL); valueUnits=GWEN_DB_GetCharValue(dbArgs, "valueUnits", 0, NULL); - valueData=GWEN_DB_GetCharValue(dbArgs, "value", 0, NULL); + valueDataAsString=GWEN_DB_GetCharValue(dbArgs, "value", 0, NULL); + + if (valueDataAsString && *valueDataAsString) { + rv=_readValueFromString(valueDataAsString, &valueData); + if (rv<0) { + DBG_ERROR(NULL, "ERROR: Bad value"); + return NULL; + } + } + if (!(valueName && *valueName)) { DBG_ERROR(NULL, "ERROR: Missing value name"); return NULL; } + v=AQH_Value_new(); AQH_Value_SetNameForSystem(v, valueName); AQH_Value_SetValueUnits(v, valueUnits); @@ -116,3 +129,40 @@ AQH_MESSAGE *_createRequestMessage(GWEN_UNUSED AQH_OBJECT *o, uint32_t msgId) +int _readValueFromString(const char *s, double *pDouble) +{ + int l; + + l=strlen(s); + if (l) { + if (*s=='#') { + unsigned int h; + + if (1==sscanf(s+1, "%x", &h)) { + *pDouble=(double) h; + return 0; + } + } + else if (l>1 && s[0]=='0' && ((tolower(s[1])=='x') || tolower(s[1])=='b')) { + unsigned int h; + + if (1==sscanf(s, "%u", &h)) { + *pDouble=(double) h; + return 0; + } + } + else { + double d; + + if (1==sscanf(s, "%lf", &d)) { + return d; + } + } + DBG_ERROR(NULL, "Bad value \"%s\"", s); + return GWEN_ERROR_GENERIC; + } +} + + + + diff --git a/aqhome/aqhome.c b/aqhome/aqhome.c index bee2f17..39ff339 100644 --- a/aqhome/aqhome.c +++ b/aqhome/aqhome.c @@ -43,6 +43,10 @@ static void _definePath(const char *pathName, const char *pathValue); static GWEN_STRINGLIST *_getListOfMatchingFiles(const char *pathName, const char *subFolder, const char *mask); static GWEN_BUFFER *_getRuntimeFilePath(const char *pathName, const char *sFilename); static GWEN_BUFFER *_findFileinPath(const char *pathName, const char *sFilename); +static int _readUint8DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom); +static int _readUint16DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom); +static int _readUint32DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom); + static int _readUint8DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom); static int _readUint16DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom); static int _readUint32DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom); @@ -469,6 +473,59 @@ GWEN_BUFFER *_findFileinPath(const char *pathName, const char *sFilename) +int AQH_ReadDataFromDouble(int dataType, double d, uint16_t *pDataVal, uint16_t *pDataDenom) +{ + switch(dataType) { + case AQH_ValueDataType_Uint8: return _readUint8DataFromDouble(d, pDataVal, pDataDenom); + case AQH_ValueDataType_Int: + case AQH_ValueDataType_Uint16: return _readUint16DataFromDouble(d, pDataVal, pDataDenom); + case AQH_ValueDataType_Uint32: return _readUint32DataFromDouble(d, pDataVal, pDataDenom); + case AQH_ValueDataType_Rational: break; + default: break; + } + + return GWEN_ERROR_INVALID; +} + + + +int _readUint8DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom) +{ + uint8_t v; + + v=((uint8_t) (d)) & 0xff; + *pDataVal=v & 0xff; + *pDataDenom=1; + return 0; +} + + + +int _readUint16DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom) +{ + uint16_t v; + + v=((uint16_t) d) & 0xffff; + *pDataVal=v; + *pDataDenom=1; + return 0; +} + + + +int _readUint32DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom) +{ + uint32_t v; + + v=((uint32_t) d) & 0xffffffff; + + *pDataVal=(v>>16) & 0xffff; + *pDataDenom=v & 0xffff; + return 0; +} + + + int AQH_ReadDataFromString(int dataType, const char *s, uint16_t *pDataVal, uint16_t *pDataDenom) { if (s && *s) { diff --git a/aqhome/aqhome.h b/aqhome/aqhome.h index d86f540..ff159af 100644 --- a/aqhome/aqhome.h +++ b/aqhome/aqhome.h @@ -84,6 +84,7 @@ AQHOME_API int AQH_ValueModality_fromString(const char *s); AQHOME_API const char *AQH_ValueModality_toString(int i); AQHOME_API int AQH_ReadDataFromString(int dataType, const char *s, uint16_t *pDataVal, uint16_t *pDataDenom); +AQHOME_API int AQH_ReadDataFromDouble(int dataType, double d, uint16_t *pDataVal, uint16_t *pDataDenom); #endif diff --git a/aqhome/dataclient/client.c b/aqhome/dataclient/client.c index 9b6336e..7d94c39 100644 --- a/aqhome/dataclient/client.c +++ b/aqhome/dataclient/client.c @@ -343,7 +343,7 @@ uint64_t AQH_DataClient_GetPeriodData(AQH_DATACLIENT *dc, const char *valueName, -int AQH_DataClient_SetData(AQH_DATACLIENT *dc, const AQH_VALUE *v, const char *data) +int AQH_DataClient_SetData(AQH_DATACLIENT *dc, const AQH_VALUE *v, double data) { if (dc) { AQH_MESSAGE *msgOut; diff --git a/aqhome/dataclient/client.h b/aqhome/dataclient/client.h index 1a77195..f6071ac 100644 --- a/aqhome/dataclient/client.h +++ b/aqhome/dataclient/client.h @@ -43,7 +43,7 @@ AQHOME_API uint64_t AQH_DataClient_GetPeriodData(AQH_DATACLIENT *dc, const char uint64_t *dataPtr, uint64_t maxNum, uint64_t tsBegin, uint64_t tsEnd); -AQHOME_API int AQH_DataClient_SetData(AQH_DATACLIENT *dc, const AQH_VALUE *v, const char *data); +AQHOME_API int AQH_DataClient_SetData(AQH_DATACLIENT *dc, const AQH_VALUE *v, double data); AQHOME_API int AQH_DataClient_UpdateData(AQH_DATACLIENT *dc, const AQH_VALUE *v, uint64_t timeStamp, double dataPoint); diff --git a/aqhome/msg/ipc/data/m_ipcd_setdata.c b/aqhome/msg/ipc/data/m_ipcd_setdata.c index 63b71a5..ea0f85b 100644 --- a/aqhome/msg/ipc/data/m_ipcd_setdata.c +++ b/aqhome/msg/ipc/data/m_ipcd_setdata.c @@ -37,7 +37,7 @@ AQH_MESSAGE *AQH_IpcdMessageSetData_new(uint16_t code, uint32_t msgId, uint32_t refMsgId, - const AQH_VALUE *value, const char *data) + const AQH_VALUE *value, double data) { AQH_MESSAGE *msg; GWEN_BUFFER *buf; @@ -51,8 +51,7 @@ AQH_MESSAGE *AQH_IpcdMessageSetData_new(uint16_t code, GWEN_Buffer_free(buf); return NULL; } - if (data && *data) - GWEN_Tag16_WriteStringTagToBuffer(AQH_MSGDATA_SET_TAGS_DATA, data, buf); + GWEN_Tag16_WriteDoubleTagToBuffer(AQH_MSGDATA_SET_TAGS_DATA, data, buf); msg=AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, code, msgId, refMsgId, GWEN_Buffer_GetUsedBytes(buf), (const uint8_t*) GWEN_Buffer_GetStart(buf)); @@ -78,9 +77,9 @@ AQH_VALUE *AQH_IpcdMessageSetData_ReadValue(const GWEN_TAG16_LIST *tagList) -char *AQH_IpcdMessageSetData_ReadData(const GWEN_TAG16_LIST *tagList) +double AQH_IpcdMessageSetData_ReadData(const GWEN_TAG16_LIST *tagList) { - return AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_SET_TAGS_DATA, NULL); + return AQH_Tag16_GetTagDataAsDouble(tagList, AQH_MSGDATA_SET_TAGS_DATA, 0.0); } @@ -92,16 +91,16 @@ void AQH_IpcdMessageSetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG1 const char *valueName; const char *valueUnits; int valueType; - char *data; + double data; value=tagList?AQH_IpcdMessageSetData_ReadValue(tagList):NULL; valueName=value?AQH_Value_GetNameForSystem(value):NULL; valueUnits=value?AQH_Value_GetValueUnits(value):NULL; valueType=value?AQH_Value_GetValueType(value):0; - data=tagList?AQH_IpcdMessageSetData_ReadData(tagList):NULL; + data=tagList?AQH_IpcdMessageSetData_ReadData(tagList):0.0; GWEN_Buffer_AppendArgs(dbuf, - "SETDATA(%s) %s (code=%d, proto=%d, proto version=%d, name=%s, units=%s, type=%d, value=%s)\n", + "SETDATA(%s) %s (code=%d, proto=%d, proto version=%d, name=%s, units=%s, type=%d, value=%.2f)\n", AQH_IpcdMessage_MsgTypeToChar(AQH_IpcMessage_GetCode(msg)), sText?sText:"", AQH_IpcMessage_GetCode(msg), @@ -110,8 +109,7 @@ void AQH_IpcdMessageSetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG1 valueName?valueName:"", valueUnits?valueUnits:"", valueType, - data?data:""); - free(data); + data); AQH_Value_free(value); } diff --git a/aqhome/msg/ipc/data/m_ipcd_setdata.h b/aqhome/msg/ipc/data/m_ipcd_setdata.h index 3aee4ba..c6c28d3 100644 --- a/aqhome/msg/ipc/data/m_ipcd_setdata.h +++ b/aqhome/msg/ipc/data/m_ipcd_setdata.h @@ -27,10 +27,10 @@ AQHOME_API AQH_MESSAGE *AQH_IpcdMessageSetData_new(uint16_t code, uint32_t msgId, uint32_t refMsgId, - const AQH_VALUE *value, const char *data); + const AQH_VALUE *value, double data); AQHOME_API AQH_VALUE *AQH_IpcdMessageSetData_ReadValue(const GWEN_TAG16_LIST *tagList); -AQHOME_API char *AQH_IpcdMessageSetData_ReadData(const GWEN_TAG16_LIST *tagList); +AQHOME_API double AQH_IpcdMessageSetData_ReadData(const GWEN_TAG16_LIST *tagList); AQHOME_API void AQH_IpcdMessageSetData_DumpToBuffer(const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, GWEN_BUFFER *dbuf, const char *sText); diff --git a/aqhome/msg/ipc/m_ipc_tag16.c b/aqhome/msg/ipc/m_ipc_tag16.c index a7a2e6d..f151e75 100644 --- a/aqhome/msg/ipc/m_ipc_tag16.c +++ b/aqhome/msg/ipc/m_ipc_tag16.c @@ -161,6 +161,19 @@ uint64_t AQH_Tag16_GetTagDataAsUint64(const GWEN_TAG16_LIST *tagList, unsigned i +double AQH_Tag16_GetTagDataAsDouble(const GWEN_TAG16_LIST *tagList, unsigned int tagType, double defaultValue) +{ + if (tagList) { + const GWEN_TAG16 *tag; + + tag=GWEN_Tag16_List_FindFirstByTagType(tagList, tagType); + return tag?GWEN_Tag16_GetTagDataAsDouble(tag, defaultValue):defaultValue; + } + return defaultValue; +} + + + int AQH_Tag16_WriteValueListAsTagsToBuffer(unsigned int tagType, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *buf) { if (valueList) { diff --git a/aqhome/msg/ipc/m_ipc_tag16.h b/aqhome/msg/ipc/m_ipc_tag16.h index 044169a..1df64b3 100644 --- a/aqhome/msg/ipc/m_ipc_tag16.h +++ b/aqhome/msg/ipc/m_ipc_tag16.h @@ -27,6 +27,7 @@ AQHOME_API GWEN_TAG16_LIST *AQH_Tag16_ParseTags(const uint8_t *payloadPtr, uint3 AQHOME_API char *AQH_Tag16_GetTagDataAsNewString(const GWEN_TAG16_LIST *tagList, unsigned int tagType, const char *defaultValue); AQHOME_API uint32_t AQH_Tag16_GetTagDataAsUint32(const GWEN_TAG16_LIST *tagList, unsigned int tagType, uint32_t defaultValue); AQHOME_API uint64_t AQH_Tag16_GetTagDataAsUint64(const GWEN_TAG16_LIST *tagList, unsigned int tagType, uint64_t defaultValue); +AQHOME_API double AQH_Tag16_GetTagDataAsDouble(const GWEN_TAG16_LIST *tagList, unsigned int tagType, double defaultValue); /* utils */ AQHOME_API int AQH_Tag16_WriteValueListAsTagsToBuffer(unsigned int tagType, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *buf); diff --git a/devices/mqtt/tasmota_plug.xml b/devices/mqtt/tasmota_plug.xml index b6b4e49..cb53d46 100644 --- a/devices/mqtt/tasmota_plug.xml +++ b/devices/mqtt/tasmota_plug.xml @@ -27,8 +27,8 @@ - - + + diff --git a/devices/mqtt/tasmota_plug_old.xml b/devices/mqtt/tasmota_plug_old.xml index 7f7c708..f20d994 100644 --- a/devices/mqtt/tasmota_plug_old.xml +++ b/devices/mqtt/tasmota_plug_old.xml @@ -27,8 +27,8 @@ - - + + From 5a16117240a1c80b1caa6e3327544f8ec4b26026 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Thu, 9 Oct 2025 20:19:04 +0200 Subject: [PATCH 04/24] More work on aqhome-cgi. --- 0BUILD | 2 +- apps/aqhome-cgi/modules/mdevices.c | 48 +++++++++++++++++++--- apps/aqhome-mqttlog/s_setdata.c | 12 +++++- apps/aqhome-mqttlog/xmlread.c | 11 +++-- apps/aqhome-react/types/prgrule.c | 61 +++++++++++++++------------- apps/aqhome-react/units/u_valueset.c | 3 +- aqhome/data/storage.c | 1 - 7 files changed, 95 insertions(+), 43 deletions(-) diff --git a/0BUILD b/0BUILD index 36425b2..cd3cc8f 100644 --- a/0BUILD +++ b/0BUILD @@ -2,7 +2,7 @@ - + $(project_name) $(project_vmajor).$(project_vminor).$(project_vpatchlevel) diff --git a/apps/aqhome-cgi/modules/mdevices.c b/apps/aqhome-cgi/modules/mdevices.c index 3b57ca0..f5489f8 100644 --- a/apps/aqhome-cgi/modules/mdevices.c +++ b/apps/aqhome-cgi/modules/mdevices.c @@ -59,6 +59,8 @@ static void _writeValueListToTable(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *val static void _writeValueToTable(AQH_DATACLIENT *dc, const AQH_VALUE *value, 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); @@ -404,7 +406,8 @@ void _writeValueListToTable(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *valueList, value=AQH_Value_List_First(valueList); while(value) { - _writeValueToTable(dc, value, dbuf); + if (AQH_Value_GetModality(value)!=AQH_ValueModality_Stats) + _writeValueToTable(dc, value, dbuf); value=AQH_Value_List_Next(value); } GBAS(dbuf, @@ -487,7 +490,6 @@ void _addValueActionToForm(const AQH_VALUE *value, GWEN_BUFFER *dbuf) uint32_t _colorFromHexString(const char *s) { uint32_t colorIn=0; - uint32_t colorOut; while(*s && *s<33) s++; @@ -505,7 +507,30 @@ uint32_t _colorFromHexString(const char *s) } /* hex 00RRGGBB -> GGRRWWBB */ - colorOut=(colorIn & 0x00ff0000) | ((colorIn & 0x00ff00)<<16) | (colorIn & 0x0000ff); + //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; } @@ -627,7 +652,20 @@ void _addLastValueToForm(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER DBG_ERROR(NULL, "Adding actor"); switch(AQH_Value_GetModality(value)) { case AQH_ValueModality_RGBW: - GBAA(dbuf, "", sValueName, (unsigned int) u.f); + 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; default: -// GBAA(dbuf, "", sValueName, u.f); + // GBAA(dbuf, "", sValueName, u.f); GBAA(dbuf, "%.2f", u.f); break; } /* switch */ diff --git a/apps/aqhome-mqttlog/s_setdata.c b/apps/aqhome-mqttlog/s_setdata.c index 74f1b05..0cb54d6 100644 --- a/apps/aqhome-mqttlog/s_setdata.c +++ b/apps/aqhome-mqttlog/s_setdata.c @@ -191,8 +191,18 @@ const char *_valueTranslatedForDriver(const AQHMQTT_VALUE *value, double valueDa valueAsInt=(int) valueData; t=AQHMQTT_Translation_List_GetByAqhValue(translationList, valueAsInt); if (t) { - return AQHMQTT_Translation_GetDriverValue(t); + const char *s; + + s=AQHMQTT_Translation_GetDriverValue(t); + DBG_ERROR(NULL, "Translated value %d to %s", valueAsInt, s); + return s; } + else { + DBG_ERROR(NULL, "No translation found for %d", valueAsInt); + } + } + else { + DBG_ERROR(NULL, "No translation list"); } return NULL; diff --git a/apps/aqhome-mqttlog/xmlread.c b/apps/aqhome-mqttlog/xmlread.c index ddb19bd..e55504b 100644 --- a/apps/aqhome-mqttlog/xmlread.c +++ b/apps/aqhome-mqttlog/xmlread.c @@ -62,6 +62,7 @@ static AQHMQTT_TRANSLATION *_readXmlTranslation(GWEN_XMLNODE *translationNode); AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDeviceFile(AQH_OBJECT *o, const char *sFilename) { + DBG_ERROR(NULL, "Reading device file \"%s\"", sFilename); if (o) { AQH_MQTTLOG_SERVER *xo; @@ -390,13 +391,15 @@ AQHMQTT_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *parentNode) AQHMQTT_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode) { + const char *sValueName; AQHMQTT_VALUE *value; GWEN_XMLNODE *translationNode; const char *s; int i; + sValueName=GWEN_XMLNode_GetProperty(valueNode, "name", NULL); value=AQHMQTT_Value_new(); - AQHMQTT_Value_SetName(value, GWEN_XMLNode_GetProperty(valueNode, "name", NULL)); + AQHMQTT_Value_SetName(value, sValueName); AQHMQTT_Value_SetValueUnits(value, GWEN_XMLNode_GetProperty(valueNode, "units", NULL)); AQHMQTT_Value_SetPath(value, GWEN_XMLNode_GetProperty(valueNode, "path", NULL)); @@ -415,12 +418,12 @@ AQHMQTT_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode) translationList=_readXmlTranslationList(translationNode); if (translationList) { - DBG_INFO(NULL, "Translations read"); + DBG_ERROR(NULL, "Translations read for value \"%s\"", sValueName); AQHMQTT_Value_SetTranslationList(value, translationList); } } else { - DBG_INFO(NULL, "No element"); + DBG_ERROR(NULL, "No element in value %s", sValueName); } return value; @@ -440,7 +443,7 @@ AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(GWEN_XMLNODE *parentNode) if (translation) AQHMQTT_Translation_List_Add(translation, translationList); else { - DBG_INFO(NULL, "Error reading element"); + DBG_ERROR(NULL, "Error reading element"); AQHMQTT_Translation_List_free(translationList); return NULL; } diff --git a/apps/aqhome-react/types/prgrule.c b/apps/aqhome-react/types/prgrule.c index a572687..965994c 100644 --- a/apps/aqhome-react/types/prgrule.c +++ b/apps/aqhome-react/types/prgrule.c @@ -312,29 +312,10 @@ const char *_readValueAndProbablyRange(const char *s, uint64_t *ptrBitField, int { int v=0; - if (*s=='#') { - while(*s) { - unsigned char c; - - c=tolower(*s); - if ((c>='0' && c<='9') || (c>='a' && c<='f')) { - c-='0'; - if (c>9) - c-=7; - v<<=4; - v+=c; - } - else - break; - s++; - } - } - else { - while(isdigit(*s)) { - v*=10; - v+=(*s)-'0'; - s++; - } + while(isdigit(*s)) { + v*=10; + v+=(*s)-'0'; + s++; } if (!_valueOkay(v, minValue, maxValue)) { DBG_INFO(NULL, "here"); @@ -368,13 +349,35 @@ const char *_readDouble(const char *s, double *ptrDouble) while(*s && isspace(*s)) s++; sStart=s; - while(*s && (isdigit(*s) || *s=='.' || *s=='+' || *s=='-')) - s++; + if (*s=='#') { + uint32_t v=0; - rv=GWEN_Text_StringToDouble(sStart, ptrDouble); - if (rv<0) { - DBG_ERROR(NULL, "Error reading double: %d", rv); - return NULL; + s++; + while(*s) { + unsigned char c; + + c=tolower(*s); + if ((c>='0' && c<='9') || (c>='a' && c<='f')) { + c-='0'; + if (c>9) + c-=7; + v<<=4; + v+=c; + } + else + break; + s++; + } + *ptrDouble=(double) v; + } + else { + while(*s && (isdigit(*s) || *s=='.' || *s=='+' || *s=='-')) + s++; + rv=GWEN_Text_StringToDouble(sStart, ptrDouble); + if (rv<0) { + DBG_ERROR(NULL, "Error reading double: %d", rv); + return NULL; + } } return s; diff --git a/apps/aqhome-react/units/u_valueset.c b/apps/aqhome-react/units/u_valueset.c index 4643174..ffb5389 100644 --- a/apps/aqhome-react/units/u_valueset.c +++ b/apps/aqhome-react/units/u_valueset.c @@ -66,7 +66,7 @@ AQHREACT_UNIT *AqHomeReact_UnitValueSet_new(AQH_OBJECT *aqh) param=AQHREACT_Param_new(); AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUENAME); - AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_STRING); AQHREACT_Unit_AddParam(unit, param); return unit; @@ -131,7 +131,6 @@ AQH_MESSAGE *_mkSetDataMsgDouble(AQH_OBJECT *brokerEndpoint, const char *sValueN AQH_MESSAGE *msgOut; AQH_VALUE *v; double data; - int rv; v=AQH_Value_new(); AQH_Value_SetNameForSystem(v, sValueName); diff --git a/aqhome/data/storage.c b/aqhome/data/storage.c index ad3ffd1..f42ac59 100644 --- a/aqhome/data/storage.c +++ b/aqhome/data/storage.c @@ -404,7 +404,6 @@ uint64_t *AQH_Storage_GetDataPoints(AQH_STORAGE *sto, uint64_t valueId, uint64_t uint64_t *arrayPtr; uint64_t i; - DBG_ERROR(NULL, "Requested %d entries", (int) maxDataPointsRequested); df=_getDataFileByValueId(sto, valueId); if (df==NULL) { DBG_ERROR(AQH_LOGDOMAIN, "No file for value id %lu", (unsigned long int) valueId); From 01aca2d3b739e17b577d478c519773b0773c2d55 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Fri, 10 Oct 2025 00:29:52 +0200 Subject: [PATCH 05/24] aqcgi: use single value pages. --- apps/aqhome-cgi/modules/mdevices.c | 245 +++++++++++++++++++++++++---- 1 file changed, 211 insertions(+), 34 deletions(-) diff --git a/apps/aqhome-cgi/modules/mdevices.c b/apps/aqhome-cgi/modules/mdevices.c index f5489f8..1b7b430 100644 --- a/apps/aqhome-cgi/modules/mdevices.c +++ b/apps/aqhome-cgi/modules/mdevices.c @@ -49,14 +49,23 @@ static int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session 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(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf); -static void _writeValueToTable(AQH_DATACLIENT *dc, const AQH_VALUE *value, 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); @@ -66,6 +75,8 @@ static void _setOnOffData(AQH_DATACLIENT *dc, const AQH_VALUE *value, const char 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); + /* ------------------------------------------------------------------------------------------------ @@ -76,6 +87,7 @@ 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}, + {"value.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqValueGet}, {"setdata.html", AQCGI_REQUEST_METHOD_POST, P_VALUEWRITE, _handleRqSetDataPost}, {NULL, 0, 0, NULL} }; @@ -201,6 +213,13 @@ void _handleRqValuesGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, +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); @@ -300,6 +319,9 @@ void _runValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATA { 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); @@ -312,13 +334,8 @@ void _runValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATA if (valueList && AQH_Value_List_GetCount(valueList)) { GBAA(dbuf,"

Values for Device %s

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

No values.

\n"); @@ -329,17 +346,102 @@ void _runValues(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATA +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; @@ -372,8 +474,16 @@ void _runSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DAT GWEN_BUFFER *pbuf; pbuf=GWEN_Buffer_new(0, 256, 0, 1); - GBAS(pbuf, "Location: /aqbt/devices/values.html?device="); - GWEN_Text_EscapeToBufferTolerant(sDeviceName, pbuf); + 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); } @@ -382,8 +492,7 @@ void _runSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DAT } - -void _writeValueListToTable(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf) +void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, uint32_t perms, GWEN_BUFFER *dbuf) { const AQH_VALUE *value; @@ -399,7 +508,6 @@ void _writeValueListToTable(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *valueList, "Device" "Name for System" #endif - "Action" "" "\n" "\n"); @@ -407,7 +515,7 @@ void _writeValueListToTable(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *valueList, value=AQH_Value_List_First(valueList); while(value) { if (AQH_Value_GetModality(value)!=AQH_ValueModality_Stats) - _writeValueToTable(dc, value, dbuf); + _writeValueToTable(sDeviceName, value, perms, dbuf); value=AQH_Value_List_Next(value); } GBAS(dbuf, @@ -417,36 +525,33 @@ void _writeValueListToTable(AQH_DATACLIENT *dc, const AQH_VALUE_LIST *valueList, -void _writeValueToTable(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER *dbuf) +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); - GBAA(dbuf, "%s", s?s:""); - + 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:""); -#if 0 - s=AQH_Value_GetDriver(value); - GBAA(dbuf, "%s", s?s:""); - - s=AQH_Value_GetDeviceNameForSystem(value); - GBAA(dbuf, "%s", s?s:""); - - s=AQH_Value_GetNameForSystem(value); - GBAA(dbuf, "%s", s?s:""); -#endif - - GBAS(dbuf, ""); - _addLastValueToForm(dc, value, dbuf); - GBAS(dbuf, ""); - GBAA(dbuf, "\n"); } @@ -694,3 +799,75 @@ void _addLastValueToForm(AQH_DATACLIENT *dc, const AQH_VALUE *value, GWEN_BUFFER +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"); +} + + + From 9fec57511a36b05bdcf29b0c899413a70441d3cb Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Tue, 21 Oct 2025 23:42:11 +0200 Subject: [PATCH 06/24] 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; }; From 39dba4ccb8519a814328de26576b978318c96212 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Thu, 23 Oct 2025 20:58:40 +0200 Subject: [PATCH 07/24] more work on aqhome-cgi. --- 0BUILD | 2 +- apps/aqhome-cgi/modules/devices/0BUILD | 6 +- apps/aqhome-cgi/modules/devices/mdevices.c | 53 +++++++- apps/aqhome-cgi/modules/devices/mdevices.h | 6 + .../modules/devices/mdevices_index.c | 33 +++-- .../modules/devices/mdevices_setdata.c | 42 +++--- .../modules/devices/mdevices_valuesgraph.c | 125 ++++++++++++++++++ ...evices_values.h => mdevices_valuesgraph.h} | 6 +- ...evices_values.c => mdevices_valuestable.c} | 4 +- .../modules/devices/mdevices_valuestable.h | 27 ++++ .../modules/devices/mdevices_vgraph.c | 45 +------ 11 files changed, 264 insertions(+), 85 deletions(-) create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.c rename apps/aqhome-cgi/modules/devices/{mdevices_values.h => mdevices_valuesgraph.h} (72%) rename apps/aqhome-cgi/modules/devices/{mdevices_values.c => mdevices_valuestable.c} (95%) create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_valuestable.h diff --git a/0BUILD b/0BUILD index cd3cc8f..aed2339 100644 --- a/0BUILD +++ b/0BUILD @@ -2,7 +2,7 @@ - + $(project_name) $(project_vmajor).$(project_vminor).$(project_vpatchlevel) diff --git a/apps/aqhome-cgi/modules/devices/0BUILD b/apps/aqhome-cgi/modules/devices/0BUILD index 53af1bf..3022c96 100644 --- a/apps/aqhome-cgi/modules/devices/0BUILD +++ b/apps/aqhome-cgi/modules/devices/0BUILD @@ -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 diff --git a/apps/aqhome-cgi/modules/devices/mdevices.c b/apps/aqhome-cgi/modules/devices/mdevices.c index e2c60cd..c5572dc 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices.c +++ b/apps/aqhome-cgi/modules/devices/mdevices.c @@ -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; +} + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices.h b/apps/aqhome-cgi/modules/devices/mdevices.h index 48cc2f1..8a160de 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices.h +++ b/apps/aqhome-cgi/modules/devices/mdevices.h @@ -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); + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_index.c b/apps/aqhome-cgi/modules/devices/mdevices_index.c index d460c69..22930c5 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_index.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_index.c @@ -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 "Room" "Location" "Description" + "Actions" "\n" "\n" "\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, ""); /* name for system */ - s=AQH_Device_GetNameForSystem(device); - if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) { - GBAS(dbuf,"%s", s?s:""); - } - else - GBAA(dbuf,"%s", s?s:""); + sDevice=AQH_Device_GetNameForSystem(device); + GBAA(dbuf,"%s", sDevice?sDevice:""); /* room */ s=AQH_Device_GetRoomName(device); GBAA(dbuf, "%s", 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, "%s", s?s:""); + GBAS(dbuf, ""); + 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, ""); + GBAA(dbuf, ""); 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,""); + GBAA(dbuf,"\"action\"", imgName); + GBAS(dbuf,""); +} + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_setdata.c b/apps/aqhome-cgi/modules/devices/mdevices_setdata.c index 68f64f2..5a16bd8 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_setdata.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_setdata.c @@ -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; diff --git a/apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.c b/apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.c new file mode 100644 index 0000000..ef043f0 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.c @@ -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 +#endif + + +#include "./mdevices_valuesgraph.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, 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,"

Values for Device %s

\n", sDeviceName); + _writeValueListToTable(sDeviceName, valueList, 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, GWEN_BUFFER *dbuf) +{ + const AQH_VALUE *value; + + GBAS(dbuf, "\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, "
\n"); +} + + + +void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf) +{ + const char *sValueName; + + /* name */ + sValueName=AQH_Value_GetName(value); + + GBAS(dbuf, ""); + _addGraphLink(sDeviceName, sValueName, "1d", dbuf); + GBAS(dbuf, ""); + _addGraphLink(sDeviceName, sValueName, "1w", dbuf); + GBAS(dbuf, "\n"); +} + + + +void _addGraphLink(const char *sDeviceName, const char *sValueName, const char *sPeriod, GWEN_BUFFER *dbuf) +{ + GBAS(dbuf, "\"%s\""); +} + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_values.h b/apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.h similarity index 72% rename from apps/aqhome-cgi/modules/devices/mdevices_values.h rename to apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.h index 25cc9ed..ff5c9a4 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_values.h +++ b/apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.h @@ -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 diff --git a/apps/aqhome-cgi/modules/devices/mdevices_values.c b/apps/aqhome-cgi/modules/devices/mdevices_valuestable.c similarity index 95% rename from apps/aqhome-cgi/modules/devices/mdevices_values.c rename to apps/aqhome-cgi/modules/devices/mdevices_valuestable.c index d4a98f6..ef19476 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_values.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_valuestable.c @@ -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; diff --git a/apps/aqhome-cgi/modules/devices/mdevices_valuestable.h b/apps/aqhome-cgi/modules/devices/mdevices_valuestable.h new file mode 100644 index 0000000..524ae05 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_valuestable.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_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 + +#include + + + +void AQH_ModDevices_RunValuesAsTable(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 index 02d2819..c1340c8 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c @@ -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:"", sValueName?sValueName:"", sPeriod?sPeriod:""); - 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) { From cfa071c6deba751497b1b0dc02b97034f46604c6 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Thu, 23 Oct 2025 20:58:54 +0200 Subject: [PATCH 08/24] increased verbosity. --- apps/aqhome-nodes/db.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/aqhome-nodes/db.c b/apps/aqhome-nodes/db.c index 01152b7..43a55ac 100644 --- a/apps/aqhome-nodes/db.c +++ b/apps/aqhome-nodes/db.c @@ -246,7 +246,7 @@ void _announceNodeValues(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_NODE_INFO v=AQHNODE_Value_List_First(valueList); while(v) { - DBG_INFO(NULL, "Announcing value \"%08x/%s\" (%d=%s)", + DBG_ERROR(NULL, "Announcing value \"%08x/%s\" (%d=%s)", AQH_NodeInfo_GetUid(ni), AQHNODE_Value_GetName(v), AQHNODE_Value_GetModality(v), AQH_ValueModality_toString(AQHNODE_Value_GetModality(v))); From 55ac83820edd8e77562c2dcdb1bfa6d82d4ff24b Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Thu, 23 Oct 2025 20:59:12 +0200 Subject: [PATCH 09/24] fixed a bug. was not accepting "0.0" as value. --- apps/aqhome-nodes/r_setdata.c | 69 ++++++++++++++++------------------- 1 file changed, 31 insertions(+), 38 deletions(-) diff --git a/apps/aqhome-nodes/r_setdata.c b/apps/aqhome-nodes/r_setdata.c index 6a38c66..96ddd73 100644 --- a/apps/aqhome-nodes/r_setdata.c +++ b/apps/aqhome-nodes/r_setdata.c @@ -93,67 +93,60 @@ void AQH_NodeServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSA varName=AQH_Value_GetName(value); if (varName) { double data; + AQH_NODE_INFO *nodeInfo; data=AQH_IpcdMessageSetData_ReadData(tagList); - if (data) { - AQH_NODE_INFO *nodeInfo; + nodeInfo=_getNodeInfoFromValue(xo, value); + if (nodeInfo) { + const char *devName; - nodeInfo=_getNodeInfoFromValue(xo, value); - if (nodeInfo) { - const char *devName; + devName=AQH_NodeInfo_GetDeviceId(nodeInfo); + if (devName) { + const AQHNODE_DEVICE *devInfo; - devName=AQH_NodeInfo_GetDeviceId(nodeInfo); - if (devName) { - const AQHNODE_DEVICE *devInfo; + devInfo=AQH_NodeServer_GetDeviceDefByName(o, devName); + if (devInfo) { + const AQHNODE_VALUE *devValue; - devInfo=AQH_NodeServer_GetDeviceDefByName(o, devName); - if (devInfo) { - const AQHNODE_VALUE *devValue; + devValue=AQHNODE_Value_List_GetByName(AQHNODE_Device_GetValueList(devInfo), varName); + if (devValue) { + uint16_t dataVal=0; + uint16_t dataDenom=0; - devValue=AQHNODE_Value_List_GetByName(AQHNODE_Device_GetValueList(devInfo), varName); - if (devValue) { - uint16_t dataVal=0; - uint16_t dataDenom=0; + if (AQH_ReadDataFromDouble(AQHNODE_Value_GetDataType(devValue), data, &dataVal, &dataDenom)==0) { + AQH_MSG_REQUEST *rq; + int destAddr; - if (AQH_ReadDataFromDouble(AQHNODE_Value_GetDataType(devValue), data, &dataVal, &dataDenom)==0) { - AQH_MSG_REQUEST *rq; - int destAddr; + destAddr=AQH_NodeInfo_GetBusAddress(nodeInfo); + DBG_DEBUG(NULL, "Creating SETDATA request"); - destAddr=AQH_NodeInfo_GetBusAddress(nodeInfo); - DBG_DEBUG(NULL, "Creating SETDATA request"); - - rq=_mkRequest_SetData(o, xo, ep, msgId, destAddr, AQHNODE_Value_GetId(devValue), dataVal, dataDenom); - AQH_NodeServer_AddRequestToTree(o, rq); - /* done */ - } - else { - DBG_ERROR(NULL, "Bad data \"%s\"", data); - _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_BADDATA); - } + rq=_mkRequest_SetData(o, xo, ep, msgId, destAddr, AQHNODE_Value_GetId(devValue), dataVal, dataDenom); + AQH_NodeServer_AddRequestToTree(o, rq); + /* done */ } else { - DBG_ERROR(NULL, "Invalid value name \"%s\"", varName); - _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID); + DBG_ERROR(NULL, "Bad data \"%.2f\"", data); + _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_BADDATA); } } else { - DBG_ERROR(NULL, "Unknown node \"%s\"", devName); + DBG_ERROR(NULL, "Invalid value name \"%s\"", varName); _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID); } } else { - DBG_ERROR(NULL, "Node not yet fully identified, come back later"); - _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_TRYAGAIN); + DBG_ERROR(NULL, "Unknown node \"%s\"", devName); + _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID); } } else { - DBG_ERROR(NULL, "No matching nodeinfo"); - _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID); + DBG_ERROR(NULL, "Node not yet fully identified, come back later"); + _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_TRYAGAIN); } } else { - DBG_ERROR(NULL, "No data"); - _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_NODATA); + DBG_ERROR(NULL, "No matching nodeinfo"); + _sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID); } } else { From 9caf468b86fb4776b46dee4e427e0fc62582c1ce Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Thu, 23 Oct 2025 20:59:42 +0200 Subject: [PATCH 10/24] avr: daily clear more stats. --- avr/modules/network/iface.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avr/modules/network/iface.asm b/avr/modules/network/iface.asm index 4313716..d1e584f 100644 --- a/avr/modules/network/iface.asm +++ b/avr/modules/network/iface.asm @@ -241,7 +241,7 @@ NET_Interface_ResetStats: mov xl, yl mov xh, yh adiw xh:xl, NET_IFACE_OFFS_PACKETSIN_LOW - ldi r17, ((NET_IFACE_OFFS_ERR_BUSY_HIGH+1)-NET_IFACE_OFFS_PACKETSIN_LOW) + ldi r17, ((NET_IFACE_OFFS_ERR_MISSED_HIGH+1)-NET_IFACE_OFFS_PACKETSIN_LOW) clr r16 rcall Utils_FillSram ; (R17, X) out SREG, r15 From 0fa4c6c8b54b3fa5b7f92181d083fd26bf67c832 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Fri, 24 Oct 2025 16:39:53 +0200 Subject: [PATCH 11/24] sk6812: set state to on when setting mode to auto. need to have a better solution for this... --- avr/modules/sk6812/main.asm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/avr/modules/sk6812/main.asm b/avr/modules/sk6812/main.asm index 15acdd6..432f771 100644 --- a/avr/modules/sk6812/main.asm +++ b/avr/modules/sk6812/main.asm @@ -148,8 +148,9 @@ SK6812_SetMode: sts sk6812Mode, r18 cpi r18, SK6812_MODE_OFF breq SK6812_SetState_off - cpi r18, SK6812_MODE_ON - breq SK6812_SetState_on +; cpi r18, SK6812_MODE_ON +; breq SK6812_SetState_on + rjmp SK6812_SetState_on ret SK6812_SetState_off: clr r18 From 7c320b210f79d74622f3e669fad0e971b638c051 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sat, 25 Oct 2025 16:36:24 +0200 Subject: [PATCH 12/24] more work on mdevices module. --- apps/aqhome-cgi/modules/devices/0BUILD | 4 + apps/aqhome-cgi/modules/devices/mdevices.c | 49 +++++++ apps/aqhome-cgi/modules/devices/mdevices.h | 1 + .../modules/devices/mdevices_device.c | 131 ++++++++++++++++++ .../modules/devices/mdevices_device.h | 27 ++++ .../modules/devices/mdevices_index.c | 12 +- .../modules/devices/mdevices_setdevice.c | 105 ++++++++++++++ .../modules/devices/mdevices_setdevice.h | 27 ++++ .../modules/devices/mdevices_valuesgraph.c | 76 ++++++++-- .../modules/devices/mdevices_vgraph.c | 56 +++++--- aqhome/dataclient/client.c | 18 +++ aqhome/dataclient/client.h | 1 + 12 files changed, 471 insertions(+), 36 deletions(-) create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_device.c create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_device.h create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_setdevice.c create mode 100644 apps/aqhome-cgi/modules/devices/mdevices_setdevice.h diff --git a/apps/aqhome-cgi/modules/devices/0BUILD b/apps/aqhome-cgi/modules/devices/0BUILD index 3022c96..051c8ae 100644 --- a/apps/aqhome-cgi/modules/devices/0BUILD +++ b/apps/aqhome-cgi/modules/devices/0BUILD @@ -59,6 +59,8 @@ mdevices_value.h mdevices_setdata.h mdevices_vgraph.h + mdevices_device.h + mdevices_setdevice.h @@ -77,6 +79,8 @@ mdevices_value.c mdevices_setdata.c mdevices_vgraph.c + mdevices_device.c + mdevices_setdevice.c diff --git a/apps/aqhome-cgi/modules/devices/mdevices.c b/apps/aqhome-cgi/modules/devices/mdevices.c index c5572dc..70e1e2d 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices.c +++ b/apps/aqhome-cgi/modules/devices/mdevices.c @@ -19,6 +19,8 @@ #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/modules/devices/mdevices_device.h" +#include "aqhome-cgi/modules/devices/mdevices_setdevice.h" #include "aqhome-cgi/service/module.h" #include "aqhome-cgi/modules/mdataclient.h" @@ -37,6 +39,7 @@ #define GBAA GWEN_Buffer_AppendArgs #define P_DEVICEREAD AQH_MODDEVICES_PERMS_DEVICEREAD +#define P_DEVICEWRITE AQH_MODDEVICES_PERMS_DEVICEWRITE #define P_VALUEREAD AQH_MODDEVICES_PERMS_VALUEREAD #define P_VALUEWRITE AQH_MODDEVICES_PERMS_VALUEWRITE @@ -56,6 +59,8 @@ static void _handleRqValuesGraphGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSIO 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 _handleRqDeviceGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf); +static void _handleRqDevicePost(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); @@ -69,6 +74,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}, + {"device.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqDeviceGet}, + {"device.html", AQCGI_REQUEST_METHOD_POST, P_DEVICEWRITE, _handleRqDevicePost}, {"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}, @@ -150,6 +157,20 @@ void _handleRqGraphGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, G +void _handleRqDeviceGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) +{ + AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunDevice, dbuf); +} + + + +void _handleRqDevicePost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf) +{ + AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunSetDevice, dbuf); +} + + + @@ -343,4 +364,32 @@ AQH_VALUE *AQH_ModDevices_GetValueForDevice(AQH_DATACLIENT *dc, const char *sDev +AQH_DEVICE *AQH_ModDevices_GetDevice(AQH_DATACLIENT *dc, const char *sDeviceName) +{ + AQH_DEVICE_LIST *deviceList; + + deviceList=AQH_DataClient_GetDevices(dc, sDeviceName); + if (deviceList) { + AQH_DEVICE *device; + + device=AQH_Device_List_First(deviceList); + while(device) { + const char *s; + + s=AQH_Device_GetNameForSystem(device); + if (s && *s && 0==strcasecmp(s, sDeviceName)) { + AQH_Device_List_Del(device); + AQH_Device_List_free(deviceList); + return device; + } + device=AQH_Device_List_Next(device); + } + AQH_Device_List_free(deviceList); + } + + return NULL; +} + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices.h b/apps/aqhome-cgi/modules/devices/mdevices.h index 8a160de..15b0476 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices.h +++ b/apps/aqhome-cgi/modules/devices/mdevices.h @@ -46,6 +46,7 @@ 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); +AQH_DEVICE *AQH_ModDevices_GetDevice(AQH_DATACLIENT *dc, const char *sDeviceName); diff --git a/apps/aqhome-cgi/modules/devices/mdevices_device.c b/apps/aqhome-cgi/modules/devices/mdevices_device.c new file mode 100644 index 0000000..ff70697 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_device.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * 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_device.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 I18N(msg) msg + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _runDeviceWithArgs(AQH_MODULE *m, + AQCGI_REQUEST *rq, + AQH_SESSION *session, + AQH_DATACLIENT *dc, + const char *sDeviceName, + GWEN_BUFFER *dbuf); +static void _mkDeviceForm(AQH_DATACLIENT *dc, const char *sDeviceName, const AQH_DEVICE *device, GWEN_BUFFER *dbuf); +static void _addFieldToForm(const char *sFieldTitle, const char *sFieldName, const char *sFieldContent, GWEN_BUFFER *dbuf); + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_ModDevices_RunDevice(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf) +{ + GWEN_DB_NODE *dbQuery; + const char *sDeviceName; + + DBG_ERROR(NULL, "RunValue"); + dbQuery=AQCGI_Request_GetDbQuery(rq); + sDeviceName=GWEN_DB_GetCharValue(dbQuery, "device", 0, NULL); + if (sDeviceName && *sDeviceName) { + GWEN_BUFFER *bufDeviceName; + + bufDeviceName=GWEN_Buffer_new(0, 64, 0, 1); + GWEN_Text_UnescapeToBufferTolerant(sDeviceName, bufDeviceName); + _runDeviceWithArgs(m, rq, session, dc, GWEN_Buffer_GetStart(bufDeviceName), dbuf); + GWEN_Buffer_free(bufDeviceName); + } +} + + + +void _runDeviceWithArgs(AQH_MODULE *m, + AQCGI_REQUEST *rq, + AQH_SESSION *session, + AQH_DATACLIENT *dc, + const char *sDeviceName, + GWEN_BUFFER *dbuf) +{ + GWEN_DB_NODE *dbQuery; + AQH_DEVICE *device; + + dbQuery=AQCGI_Request_GetDbQuery(rq); + DBG_ERROR(NULL, "Device=%s", sDeviceName?sDeviceName:""); + + GBAA(dbuf,"

Device %s

\n", sDeviceName); + + device=AQH_ModDevices_GetDevice(dc, sDeviceName); + if (device) { + _mkDeviceForm(dc, sDeviceName, device, dbuf); + AQH_Device_free(device); + } +} + + + +void _mkDeviceForm(AQH_DATACLIENT *dc, const char *sDeviceName, const AQH_DEVICE *device, GWEN_BUFFER *dbuf) +{ + const char *s; + + GBAS(dbuf,"
\n"); + GBAA(dbuf, "\n", sDeviceName); + + GBAS(dbuf,"\n"); + _addFieldToForm(I18N("Room"), "roomName", AQH_Device_GetRoomName(device), dbuf); + _addFieldToForm(I18N("GUI Name"), "nameForGui", AQH_Device_GetNameForGui(device), dbuf); + _addFieldToForm(I18N("Location"), "location", AQH_Device_GetLocation(device), dbuf); + _addFieldToForm(I18N("Description"), "description", AQH_Device_GetDescription(device), dbuf); + GBAS(dbuf,"
\n"); + GBAS(dbuf,"
\n"); + + GBAS(dbuf,""); + GBAS(dbuf, "
\n\n"); +} + + + +void _addFieldToForm(const char *sFieldTitle, const char *sFieldName, const char *sFieldContent, GWEN_BUFFER *dbuf) +{ + GBAS(dbuf, ""); + GBAA(dbuf, "", sFieldName, sFieldTitle); + GBAA(dbuf, "", sFieldName, sFieldContent?sFieldContent:""); + GBAS(dbuf, ""); +} + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_device.h b/apps/aqhome-cgi/modules/devices/mdevices_device.h new file mode 100644 index 0000000..aae3489 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_device.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_DEVICE_H +#define AQHOME_CGI_MDEVICES_DEVICE_H + + +#include "aqhome-cgi/modules/devices/mdevices.h" + +#include "aqhome/aqhome.h" +#include "aqhome/dataclient/client.h" + +#include + +#include + + + +void AQH_ModDevices_RunDevice(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_index.c b/apps/aqhome-cgi/modules/devices/mdevices_index.c index 22930c5..6381047 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_index.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_index.c @@ -66,6 +66,7 @@ void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *sess "\n" "" "Name For System" + "Name For GUI" "Room" "Location" "Description" @@ -83,6 +84,9 @@ void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *sess /* name for system */ sDevice=AQH_Device_GetNameForSystem(device); GBAA(dbuf,"%s", sDevice?sDevice:""); + /* nameForGui */ + s=AQH_Device_GetNameForGui(device); + GBAA(dbuf, "%s", s?s:""); /* room */ s=AQH_Device_GetRoomName(device); GBAA(dbuf, "%s", s?s:""); @@ -97,8 +101,12 @@ void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *sess 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 } + + if (perms & AQH_MODDEVICES_PERMS_DEVICEWRITE) { + _addLinkForDevice("device.html", sDevice, "edit device", "/pics/edit.png", dbuf); + } + GBAS(dbuf, ""); GBAA(dbuf, ""); @@ -118,7 +126,7 @@ void _addLinkForDevice(const char *page, const char *sDevice, const char *action GBAA(dbuf,""); - GBAA(dbuf,"\"action\"", imgName); + GBAA(dbuf,"\"%s\"", imgName, action, action); GBAS(dbuf,""); } diff --git a/apps/aqhome-cgi/modules/devices/mdevices_setdevice.c b/apps/aqhome-cgi/modules/devices/mdevices_setdevice.c new file mode 100644 index 0000000..6edfd72 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_setdevice.c @@ -0,0 +1,105 @@ +/**************************************************************************** + * 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_setdevice.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 _handleDeviceForm(AQH_DATACLIENT *dc, AQH_DEVICE *device, GWEN_DB_NODE *dbPost, GWEN_BUFFER *dbuf); + + + +/* ------------------------------------------------------------------------------------------------ + * code + * ------------------------------------------------------------------------------------------------ + */ + +void AQH_ModDevices_RunSetDevice(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; + AQH_DEVICE *device; + + DBG_ERROR(NULL, "Post device.html"); + /* sample data */ + sv=AQH_ModService_GetService(m); + dbPost=AQCGI_Request_GetDbPostBody(rq); + sDeviceName=dbPost?GWEN_DB_GetCharValue(dbPost, "device", 0, NULL):NULL; + DBG_ERROR(NULL, "Device=[%s]", sDeviceName?sDeviceName:""); + + device=AQH_ModDevices_GetDevice(dc, sDeviceName); + if (device) { + int rv; + + DBG_ERROR(NULL, "Reading data from form"); + _handleDeviceForm(dc, device, dbPost, dbuf); + DBG_ERROR(NULL, "Updating device on server"); + rv=AQH_DataClient_ModDevice(dc, device); + if (rv<0) { + DBG_ERROR(NULL, "here (%d)", rv); + } + AQH_Device_free(device); + } + else { + DBG_ERROR(NULL, "device not found"); + } + + if (sDeviceName && *sDeviceName) { + GWEN_BUFFER *pbuf; + + pbuf=GWEN_Buffer_new(0, 256, 0, 1); + GBAS(pbuf, "Location: /aqbt/devices/device.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 _handleDeviceForm(AQH_DATACLIENT *dc, AQH_DEVICE *device, GWEN_DB_NODE *dbPost, GWEN_BUFFER *dbuf) +{ + AQH_Device_SetRoomName(device, GWEN_DB_GetCharValue(dbPost, "roomName", 0, NULL)); + AQH_Device_SetNameForGui(device, GWEN_DB_GetCharValue(dbPost, "nameForGui", 0, NULL)); + AQH_Device_SetLocation(device, GWEN_DB_GetCharValue(dbPost, "location", 0, NULL)); + AQH_Device_SetDescription(device, GWEN_DB_GetCharValue(dbPost, "description", 0, NULL)); +} + + + + + diff --git a/apps/aqhome-cgi/modules/devices/mdevices_setdevice.h b/apps/aqhome-cgi/modules/devices/mdevices_setdevice.h new file mode 100644 index 0000000..d370f40 --- /dev/null +++ b/apps/aqhome-cgi/modules/devices/mdevices_setdevice.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_SETDEVICE_H +#define AQHOME_CGI_MDEVICES_SETDEVICE_H + + +#include "aqhome-cgi/modules/devices/mdevices.h" + +#include "aqhome/aqhome.h" +#include "aqhome/dataclient/client.h" + +#include + +#include + + + +void AQH_ModDevices_RunSetDevice(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_valuesgraph.c b/apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.c index ef043f0..3163f0e 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_valuesgraph.c @@ -37,9 +37,10 @@ * ------------------------------------------------------------------------------------------------ */ +static void _writeValueToDetailedTable(const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf); 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); +static void _addGraphLink(const char *sDeviceName, const char *sValueName, const char *sPeriod, GWEN_BUFFER *dbuf, int withLink); @@ -58,24 +59,61 @@ void AQH_ModDevices_RunValuesAsGraph(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSI if (!(sDeviceName && *sDeviceName)) AQH_ModDevices_RunIndex(m, rq, session, dc, dbuf); else { - AQH_VALUE_LIST *valueList; + const char *sValueName; - valueList=AQH_DataClient_GetValues(dc, sDeviceName, 0); - if (valueList && AQH_Value_List_GetCount(valueList)) { + sValueName=GWEN_DB_GetCharValue(dbQuery, "value", 0, NULL); + if (sValueName && *sValueName) { + AQH_VALUE *value; - GBAA(dbuf,"

Values for Device %s

\n", sDeviceName); - _writeValueListToTable(sDeviceName, valueList, dbuf); - GBAS(dbuf, "\n"); + GBAA(dbuf,"

Value %s/%s

\n", sDeviceName, sValueName); + value=AQH_ModDevices_GetValueForDevice(dc, sDeviceName, sValueName); + if (value) { + _writeValueToDetailedTable(sDeviceName, value, dbuf); + AQH_Value_free(value); + AQCGI_Request_AddResponseHeaderData(rq, "Refresh: 120"); + } } else { - GBAS(dbuf,"

No values.

\n"); + 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, dbuf); + GBAS(dbuf, "\n"); + } + else { + GBAS(dbuf,"

No values.

\n"); + } + AQH_Value_List_free(valueList); + AQCGI_Request_AddResponseHeaderData(rq, "Refresh: 305"); } - AQH_Value_List_free(valueList); } } +void _writeValueToDetailedTable(const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf) +{ + const char *sValueName; + + GBAS(dbuf, "\n"); + sValueName=AQH_Value_GetName(value); + + GBAS(dbuf, "\n"); +} + + + void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf) { const AQH_VALUE *value; @@ -85,7 +123,7 @@ void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *value value=AQH_Value_List_First(valueList); while(value) { - if (AQH_Value_GetValueType(value)==AQH_ValueType_Sensor) + if (AQH_Value_GetValueType(value)!=AQH_ValueType_Actor) _writeValueToTable(sDeviceName, value, dbuf); value=AQH_Value_List_Next(value); } @@ -102,16 +140,24 @@ void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, GWEN_BU sValueName=AQH_Value_GetName(value); GBAS(dbuf, "\n"); } -void _addGraphLink(const char *sDeviceName, const char *sValueName, const char *sPeriod, GWEN_BUFFER *dbuf) +void _addGraphLink(const char *sDeviceName, const char *sValueName, const char *sPeriod, GWEN_BUFFER *dbuf, int withLink) { + if (withLink) { + GBAS(dbuf, ""); + } + GBAS(dbuf, "\"%s\""); + + if (withLink) { + GBAS(dbuf, ""); + } } diff --git a/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c index c1340c8..b8d35ca 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c @@ -46,7 +46,9 @@ enum { VALUEGRAPH_PERIOD_4H=1, VALUEGRAPH_PERIOD_1D, VALUEGRAPH_PERIOD_1W, - VALUEGRAPH_PERIOD_1M + VALUEGRAPH_PERIOD_1M, + VALUEGRAPH_PERIOD_6M, + VALUEGRAPH_PERIOD_12M, }; @@ -268,11 +270,13 @@ AQDG_GRAPH *_mkGraphObjectWithTitle(const char *graphTitle, int period, int prec 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 7 days"; break; - case VALUEGRAPH_PERIOD_1M: s="last 30 days"; break; - default: s="last 24 hours"; break; + case VALUEGRAPH_PERIOD_4H: s="last 4 hours"; break; + case VALUEGRAPH_PERIOD_1D: s="last 24 hours"; break; + case VALUEGRAPH_PERIOD_1W: s="last 7 days"; break; + case VALUEGRAPH_PERIOD_1M: s="last 30 days"; break; + case VALUEGRAPH_PERIOD_6M: s="last 6 months"; break; + case VALUEGRAPH_PERIOD_12M: s="last 12 months"; break; + default: s="last 24 hours"; break; } GBAA(tbuf, "%s - %s", graphTitle, s); @@ -293,6 +297,10 @@ int _getPeriodFromString(const char *sPeriod) return VALUEGRAPH_PERIOD_1W; else if (strcasecmp(sPeriod, "1m")==0) return VALUEGRAPH_PERIOD_1M; + else if (strcasecmp(sPeriod, "6m")==0) + return VALUEGRAPH_PERIOD_6M; + else if (strcasecmp(sPeriod, "12m")==0) + return VALUEGRAPH_PERIOD_12M; return VALUEGRAPH_PERIOD_1D; } @@ -315,11 +323,13 @@ void _mkPathForValueAndPeriod(AQH_MODULE *m, const AQH_VALUE *v, int period, GWE /* 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; + 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; + case VALUEGRAPH_PERIOD_6M: s="6m"; break; + case VALUEGRAPH_PERIOD_12M: s="12m"; break; + default: s="1d"; break; } GBAA(dbuf, "-%s.png", s); @@ -335,11 +345,13 @@ uint64_t _getStartTimeForPeriod(int period) /* 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; + 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; + case VALUEGRAPH_PERIOD_6M: t-=182*24*60*60; break; + case VALUEGRAPH_PERIOD_12M: t-=365*24*60*60; break; + default: t-=24*60*60; break; } return (uint64_t) t; @@ -351,11 +363,13 @@ const char *_getModifiersForPeriod(int period) { /* period */ switch(period) { - case VALUEGRAPH_PERIOD_4H: return "La5"; - case VALUEGRAPH_PERIOD_1D: return "La30"; - case VALUEGRAPH_PERIOD_1W: return "La240"; - case VALUEGRAPH_PERIOD_1M: return "La480"; - default: return "La15"; + case VALUEGRAPH_PERIOD_4H: return "La5"; + case VALUEGRAPH_PERIOD_1D: return "La30"; + case VALUEGRAPH_PERIOD_1W: return "La240"; + case VALUEGRAPH_PERIOD_1M: return "La480"; + case VALUEGRAPH_PERIOD_6M: return "La720"; + case VALUEGRAPH_PERIOD_12M: return "La1440"; + default: return "La30"; } } diff --git a/aqhome/dataclient/client.c b/aqhome/dataclient/client.c index 7d94c39..c335a8b 100644 --- a/aqhome/dataclient/client.c +++ b/aqhome/dataclient/client.c @@ -379,6 +379,24 @@ int AQH_DataClient_UpdateData(AQH_DATACLIENT *dc, const AQH_VALUE *v, uint64_t t +int AQH_DataClient_ModDevice(AQH_DATACLIENT *dc, const AQH_DEVICE *d) +{ + if (dc) { + AQH_MESSAGE *msgOut; + uint32_t msgId; + + msgId=++(dc->lastMsgId); + msgOut=AQH_IpcdMessageDevices_newForOneDevice(AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ, msgId, 0, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, d); + AQH_Endpoint_AddMsgOut(dc->ipcEndpoint, msgOut); + + return _handleResult(dc, msgId); + } + + return GWEN_ERROR_INVALID; +} + + + diff --git a/aqhome/dataclient/client.h b/aqhome/dataclient/client.h index f6071ac..99f8266 100644 --- a/aqhome/dataclient/client.h +++ b/aqhome/dataclient/client.h @@ -45,6 +45,7 @@ AQHOME_API uint64_t AQH_DataClient_GetPeriodData(AQH_DATACLIENT *dc, const char AQHOME_API int AQH_DataClient_SetData(AQH_DATACLIENT *dc, const AQH_VALUE *v, double data); AQHOME_API int AQH_DataClient_UpdateData(AQH_DATACLIENT *dc, const AQH_VALUE *v, uint64_t timeStamp, double dataPoint); +AQHOME_API int AQH_DataClient_ModDevice(AQH_DATACLIENT *dc, const AQH_DEVICE *d); AQHOME_API int AQH_DataClient_ReadLocalArgs(AQH_DATACLIENT *dc, From c32be5cd3882c3bf1d1518e895bac4b89485a8c9 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sat, 25 Oct 2025 16:36:52 +0200 Subject: [PATCH 13/24] increased verbosity. --- apps/aqhome-nodes/db.c | 2 +- aqhome/events2/fdobject.c | 2 +- aqhome/ipc2/endpoint.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/aqhome-nodes/db.c b/apps/aqhome-nodes/db.c index 43a55ac..01152b7 100644 --- a/apps/aqhome-nodes/db.c +++ b/apps/aqhome-nodes/db.c @@ -246,7 +246,7 @@ void _announceNodeValues(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_NODE_INFO v=AQHNODE_Value_List_First(valueList); while(v) { - DBG_ERROR(NULL, "Announcing value \"%08x/%s\" (%d=%s)", + DBG_INFO(NULL, "Announcing value \"%08x/%s\" (%d=%s)", AQH_NodeInfo_GetUid(ni), AQHNODE_Value_GetName(v), AQHNODE_Value_GetModality(v), AQH_ValueModality_toString(AQHNODE_Value_GetModality(v))); diff --git a/aqhome/events2/fdobject.c b/aqhome/events2/fdobject.c index d66ac04..b181988 100644 --- a/aqhome/events2/fdobject.c +++ b/aqhome/events2/fdobject.c @@ -180,7 +180,7 @@ int AQH_FdObject_Read(AQH_OBJECT *o, uint8_t *ptrBuffer, uint32_t lenBuffer) return GWEN_ERROR_TRY_AGAIN; } else { - DBG_ERROR(AQH_LOGDOMAIN, "Error on read: %s (%d)", strerror(errno), errno); + DBG_ERROR(AQH_LOGDOMAIN, "Error on read(%d): %s (%d)", xo->fd, strerror(errno), errno); close(xo->fd); xo->fd=-1; return GWEN_ERROR_IO; diff --git a/aqhome/ipc2/endpoint.c b/aqhome/ipc2/endpoint.c index d4c5100..4e25306 100644 --- a/aqhome/ipc2/endpoint.c +++ b/aqhome/ipc2/endpoint.c @@ -561,7 +561,7 @@ int _handleClosed(AQH_OBJECT *o) { AQH_ENDPOINT *xo; - DBG_INFO(AQH_LOGDOMAIN, "Connection closed."); + DBG_ERROR(AQH_LOGDOMAIN, "Connection closed."); xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_ENDPOINT, o); if (xo) { AQH_Object_Disable(xo->msgWriter); From 617c8551dc5860a1455e8cceac9026519783d886 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sat, 25 Oct 2025 16:37:11 +0200 Subject: [PATCH 14/24] fixed a bug (was not closing connection on error). --- aqhome/ipc2/msgreader.c | 1 + 1 file changed, 1 insertion(+) diff --git a/aqhome/ipc2/msgreader.c b/aqhome/ipc2/msgreader.c index c2600a3..9fe903c 100644 --- a/aqhome/ipc2/msgreader.c +++ b/aqhome/ipc2/msgreader.c @@ -313,6 +313,7 @@ int _fillRingbuffer(AQH_OBJECT *o, AQH_MSG_READER *xo, AQH_OBJECT *fdObject) if (rv<0) { if (rv!=GWEN_ERROR_TRY_AGAIN) { DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv); + AQH_Object_EmitSignal(o, AQH_MSG_READER_SIGNAL_CLOSED, 0, NULL); } return rv; } From ced89d984521bda1d02f158e42f31e6c683b3833 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sat, 25 Oct 2025 16:38:44 +0200 Subject: [PATCH 15/24] moved device files back into separate folder otherwise installed module files are not update when compiling without AVR. --- avr/devices/c01/0BUILD | 4 ---- avr/devices/c02/0BUILD | 4 ---- avr/devices/n14/0BUILD | 5 ----- avr/devices/n16/0BUILD | 4 ---- avr/devices/n21/0BUILD | 5 ----- avr/devices/n24/0BUILD | 4 ---- avr/devices/n25/0BUILD | 4 ---- avr/devices/n26/0BUILD | 4 ---- avr/devices/n27/0BUILD | 4 ---- avr/devices/n28/0BUILD | 5 ----- avr/devices/r05/0BUILD | 5 ----- avr/devices/r06/0BUILD | 4 ---- avr/devices/s03/0BUILD | 4 ---- avr/devices/t03/0BUILD | 4 ---- avr/devices/t04/0BUILD | 4 ---- devices/nodes/0BUILD | 15 +++++++++++++++ {avr/devices/c01 => devices/nodes}/aqua_c01.xml | 0 {avr/devices/c02 => devices/nodes}/aqua_c02.xml | 0 {avr/devices/n14 => devices/nodes}/aqua_n14.xml | 0 {avr/devices/n16 => devices/nodes}/aqua_n16.xml | 0 {avr/devices/n21 => devices/nodes}/aqua_n21.xml | 0 {avr/devices/n24 => devices/nodes}/aqua_n24.xml | 0 {avr/devices/n25 => devices/nodes}/aqua_n25.xml | 0 {avr/devices/n26 => devices/nodes}/aqua_n26.xml | 0 {avr/devices/n27 => devices/nodes}/aqua_n27.xml | 0 {avr/devices/n28 => devices/nodes}/aqua_n28.xml | 0 {avr/devices/r05 => devices/nodes}/aqua_r05.xml | 0 {avr/devices/r06 => devices/nodes}/aqua_r06.xml | 0 {avr/devices/s03 => devices/nodes}/aqua_s03.xml | 0 {avr/devices/t03 => devices/nodes}/aqua_t03.xml | 0 {avr/devices/t04 => devices/nodes}/aqua_t04.xml | 0 31 files changed, 15 insertions(+), 64 deletions(-) rename {avr/devices/c01 => devices/nodes}/aqua_c01.xml (100%) rename {avr/devices/c02 => devices/nodes}/aqua_c02.xml (100%) rename {avr/devices/n14 => devices/nodes}/aqua_n14.xml (100%) rename {avr/devices/n16 => devices/nodes}/aqua_n16.xml (100%) rename {avr/devices/n21 => devices/nodes}/aqua_n21.xml (100%) rename {avr/devices/n24 => devices/nodes}/aqua_n24.xml (100%) rename {avr/devices/n25 => devices/nodes}/aqua_n25.xml (100%) rename {avr/devices/n26 => devices/nodes}/aqua_n26.xml (100%) rename {avr/devices/n27 => devices/nodes}/aqua_n27.xml (100%) rename {avr/devices/n28 => devices/nodes}/aqua_n28.xml (100%) rename {avr/devices/r05 => devices/nodes}/aqua_r05.xml (100%) rename {avr/devices/r06 => devices/nodes}/aqua_r06.xml (100%) rename {avr/devices/s03 => devices/nodes}/aqua_s03.xml (100%) rename {avr/devices/t03 => devices/nodes}/aqua_t03.xml (100%) rename {avr/devices/t04 => devices/nodes}/aqua_t04.xml (100%) diff --git a/avr/devices/c01/0BUILD b/avr/devices/c01/0BUILD index dc1bfd9..dc4c439 100644 --- a/avr/devices/c01/0BUILD +++ b/avr/devices/c01/0BUILD @@ -7,10 +7,6 @@ main - - aqua_c01.xml - - defs.asm README diff --git a/avr/devices/c02/0BUILD b/avr/devices/c02/0BUILD index ba8c739..dc4c439 100644 --- a/avr/devices/c02/0BUILD +++ b/avr/devices/c02/0BUILD @@ -7,10 +7,6 @@ main - - aqua_c02.xml - - defs.asm README diff --git a/avr/devices/n14/0BUILD b/avr/devices/n14/0BUILD index 58af77b..343465e 100644 --- a/avr/devices/n14/0BUILD +++ b/avr/devices/n14/0BUILD @@ -7,11 +7,6 @@ main - - aqua_n14.xml - - - defs.asm eeprom.asm diff --git a/avr/devices/n16/0BUILD b/avr/devices/n16/0BUILD index e54b57e..be449f6 100644 --- a/avr/devices/n16/0BUILD +++ b/avr/devices/n16/0BUILD @@ -7,10 +7,6 @@ main - - aqua_n16.xml - - defs.asm README diff --git a/avr/devices/n21/0BUILD b/avr/devices/n21/0BUILD index 8416b5b..472c33c 100644 --- a/avr/devices/n21/0BUILD +++ b/avr/devices/n21/0BUILD @@ -12,10 +12,5 @@ README - - aqua_n21.xml - - - diff --git a/avr/devices/n24/0BUILD b/avr/devices/n24/0BUILD index 4ffa268..dc4c439 100644 --- a/avr/devices/n24/0BUILD +++ b/avr/devices/n24/0BUILD @@ -7,10 +7,6 @@ main - - aqua_n24.xml - - defs.asm README diff --git a/avr/devices/n25/0BUILD b/avr/devices/n25/0BUILD index 7d93fbf..343465e 100644 --- a/avr/devices/n25/0BUILD +++ b/avr/devices/n25/0BUILD @@ -7,10 +7,6 @@ main - - aqua_n25.xml - - defs.asm eeprom.asm diff --git a/avr/devices/n26/0BUILD b/avr/devices/n26/0BUILD index 8736df4..dc4c439 100644 --- a/avr/devices/n26/0BUILD +++ b/avr/devices/n26/0BUILD @@ -7,10 +7,6 @@ main - - aqua_n26.xml - - defs.asm README diff --git a/avr/devices/n27/0BUILD b/avr/devices/n27/0BUILD index 081044b..dc4c439 100644 --- a/avr/devices/n27/0BUILD +++ b/avr/devices/n27/0BUILD @@ -7,10 +7,6 @@ main - - aqua_n27.xml - - defs.asm README diff --git a/avr/devices/n28/0BUILD b/avr/devices/n28/0BUILD index a2d9bae..472c33c 100644 --- a/avr/devices/n28/0BUILD +++ b/avr/devices/n28/0BUILD @@ -12,10 +12,5 @@ README - - aqua_n28.xml - - - diff --git a/avr/devices/r05/0BUILD b/avr/devices/r05/0BUILD index 9e83ec2..25ab0fb 100644 --- a/avr/devices/r05/0BUILD +++ b/avr/devices/r05/0BUILD @@ -13,11 +13,6 @@ README - - aqua_r05.xml - - - diff --git a/avr/devices/r06/0BUILD b/avr/devices/r06/0BUILD index ef47309..dc4c439 100644 --- a/avr/devices/r06/0BUILD +++ b/avr/devices/r06/0BUILD @@ -7,10 +7,6 @@ main - - aqua_r06.xml - - defs.asm README diff --git a/avr/devices/s03/0BUILD b/avr/devices/s03/0BUILD index 0829603..dc4c439 100644 --- a/avr/devices/s03/0BUILD +++ b/avr/devices/s03/0BUILD @@ -7,10 +7,6 @@ main - - aqua_s03.xml - - defs.asm README diff --git a/avr/devices/t03/0BUILD b/avr/devices/t03/0BUILD index ba832c8..c1b8f79 100644 --- a/avr/devices/t03/0BUILD +++ b/avr/devices/t03/0BUILD @@ -9,10 +9,6 @@ uartfd - - aqua_t03.xml - - defs.asm README diff --git a/avr/devices/t04/0BUILD b/avr/devices/t04/0BUILD index 2775440..dc4c439 100644 --- a/avr/devices/t04/0BUILD +++ b/avr/devices/t04/0BUILD @@ -7,10 +7,6 @@ main - - aqua_t04.xml - - defs.asm README diff --git a/devices/nodes/0BUILD b/devices/nodes/0BUILD index ed2e335..bf990a7 100644 --- a/devices/nodes/0BUILD +++ b/devices/nodes/0BUILD @@ -2,15 +2,30 @@ + aqua_c01.xml + aqua_c02.xml aqua_n06.xml aqua_n11.xml aqua_n12.xml + aqua_n14.xml aqua_n15.xml + aqua_n16.xml aqua_n17.xml aqua_n18.xml aqua_n19.xml aqua_n20.xml + aqua_n21.xml aqua_n22.xml + aqua_n24.xml + aqua_n25.xml + aqua_n26.xml + aqua_n27.xml + aqua_n28.xml + aqua_r05.xml + aqua_r06.xml + aqua_s03.xml + aqua_t03.xml + aqua_t04.xml diff --git a/avr/devices/c01/aqua_c01.xml b/devices/nodes/aqua_c01.xml similarity index 100% rename from avr/devices/c01/aqua_c01.xml rename to devices/nodes/aqua_c01.xml diff --git a/avr/devices/c02/aqua_c02.xml b/devices/nodes/aqua_c02.xml similarity index 100% rename from avr/devices/c02/aqua_c02.xml rename to devices/nodes/aqua_c02.xml diff --git a/avr/devices/n14/aqua_n14.xml b/devices/nodes/aqua_n14.xml similarity index 100% rename from avr/devices/n14/aqua_n14.xml rename to devices/nodes/aqua_n14.xml diff --git a/avr/devices/n16/aqua_n16.xml b/devices/nodes/aqua_n16.xml similarity index 100% rename from avr/devices/n16/aqua_n16.xml rename to devices/nodes/aqua_n16.xml diff --git a/avr/devices/n21/aqua_n21.xml b/devices/nodes/aqua_n21.xml similarity index 100% rename from avr/devices/n21/aqua_n21.xml rename to devices/nodes/aqua_n21.xml diff --git a/avr/devices/n24/aqua_n24.xml b/devices/nodes/aqua_n24.xml similarity index 100% rename from avr/devices/n24/aqua_n24.xml rename to devices/nodes/aqua_n24.xml diff --git a/avr/devices/n25/aqua_n25.xml b/devices/nodes/aqua_n25.xml similarity index 100% rename from avr/devices/n25/aqua_n25.xml rename to devices/nodes/aqua_n25.xml diff --git a/avr/devices/n26/aqua_n26.xml b/devices/nodes/aqua_n26.xml similarity index 100% rename from avr/devices/n26/aqua_n26.xml rename to devices/nodes/aqua_n26.xml diff --git a/avr/devices/n27/aqua_n27.xml b/devices/nodes/aqua_n27.xml similarity index 100% rename from avr/devices/n27/aqua_n27.xml rename to devices/nodes/aqua_n27.xml diff --git a/avr/devices/n28/aqua_n28.xml b/devices/nodes/aqua_n28.xml similarity index 100% rename from avr/devices/n28/aqua_n28.xml rename to devices/nodes/aqua_n28.xml diff --git a/avr/devices/r05/aqua_r05.xml b/devices/nodes/aqua_r05.xml similarity index 100% rename from avr/devices/r05/aqua_r05.xml rename to devices/nodes/aqua_r05.xml diff --git a/avr/devices/r06/aqua_r06.xml b/devices/nodes/aqua_r06.xml similarity index 100% rename from avr/devices/r06/aqua_r06.xml rename to devices/nodes/aqua_r06.xml diff --git a/avr/devices/s03/aqua_s03.xml b/devices/nodes/aqua_s03.xml similarity index 100% rename from avr/devices/s03/aqua_s03.xml rename to devices/nodes/aqua_s03.xml diff --git a/avr/devices/t03/aqua_t03.xml b/devices/nodes/aqua_t03.xml similarity index 100% rename from avr/devices/t03/aqua_t03.xml rename to devices/nodes/aqua_t03.xml diff --git a/avr/devices/t04/aqua_t04.xml b/devices/nodes/aqua_t04.xml similarity index 100% rename from avr/devices/t04/aqua_t04.xml rename to devices/nodes/aqua_t04.xml From 89228ed03bfa4a1f263d50a49ec6a9ade7119dbc Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sat, 25 Oct 2025 16:38:59 +0200 Subject: [PATCH 16/24] prepared release 0.0.18 --- 0BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0BUILD b/0BUILD index aed2339..3631e9d 100644 --- a/0BUILD +++ b/0BUILD @@ -2,7 +2,7 @@ - + $(project_name) $(project_vmajor).$(project_vminor).$(project_vpatchlevel) From ffc86b3e61c0da8117ef5ebfe5f7c361209e03dc Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 26 Oct 2025 00:14:54 +0200 Subject: [PATCH 17/24] aqhome-cgi: changed graph modifier. --- apps/aqhome-cgi/modules/devices/mdevices_vgraph.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c index b8d35ca..fad25d3 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c @@ -363,13 +363,13 @@ const char *_getModifiersForPeriod(int period) { /* period */ switch(period) { - case VALUEGRAPH_PERIOD_4H: return "La5"; - case VALUEGRAPH_PERIOD_1D: return "La30"; - case VALUEGRAPH_PERIOD_1W: return "La240"; - case VALUEGRAPH_PERIOD_1M: return "La480"; - case VALUEGRAPH_PERIOD_6M: return "La720"; - case VALUEGRAPH_PERIOD_12M: return "La1440"; - default: return "La30"; + case VALUEGRAPH_PERIOD_4H: return "Lm5"; + case VALUEGRAPH_PERIOD_1D: return "Lm30"; + case VALUEGRAPH_PERIOD_1W: return "Lm240"; + case VALUEGRAPH_PERIOD_1M: return "Lm480"; + case VALUEGRAPH_PERIOD_6M: return "Lm720"; + case VALUEGRAPH_PERIOD_12M: return "Lm1440"; + default: return "Lm30"; } } From aaf460ec6f9fe1cbde9764359253007c4c6c36f5 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 26 Oct 2025 00:15:43 +0200 Subject: [PATCH 18/24] add apache2 example conf for aqhome-cgi --- etc/0BUILD | 2 ++ etc/aqhome-apache2.conf | 48 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 etc/aqhome-apache2.conf diff --git a/etc/0BUILD b/etc/0BUILD index a7b57d1..166efa8 100644 --- a/etc/0BUILD +++ b/etc/0BUILD @@ -7,6 +7,8 @@ aqhome-mqttlog.service aqhome-nodes.service aqhome-react.service + + aqhome-apache2.conf diff --git a/etc/aqhome-apache2.conf b/etc/aqhome-apache2.conf new file mode 100644 index 0000000..fe29a76 --- /dev/null +++ b/etc/aqhome-apache2.conf @@ -0,0 +1,48 @@ + + # The ServerName directive sets the request scheme, hostname and port that + # the server uses to identify itself. This is used when creating + # redirection URLs. In the context of virtual hosts, the ServerName + # specifies what hostname must appear in the request's Host: header to + # match this virtual host. For the default virtual host (this file) this + # value is not decisive as it is used as a last resort host regardless. + # However, you must set it for any further virtual host explicitly. + ServerName aqhome.withinet.lan + + ServerAdmin webmaster@localhost + DocumentRoot /var/www/aqhome-cgi/html + + # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, + # error, crit, alert, emerg. + # It is also possible to configure the loglevel for particular + # modules, e.g. + #LogLevel info ssl:warn + LogLevel debug + + ErrorLog ${APACHE_LOG_DIR}/aqhome-error.log + CustomLog ${APACHE_LOG_DIR}/aqhome-access.log combined + + # For most configuration files from conf-available/, which are + # enabled or disabled at a global level, it is possible to + # include a line for only one particular virtual host. For example the + # following line enables the CGI configuration for this host only + # after it has been globally disabled with "a2disconf". + #Include conf-available/serve-cgi-bin.conf + + + Header set Cache-Control "no-cache, no-store, must-revalidate" + Header set Pragma "no-cache" + Header set Expires 0 + + + ScriptAlias "/aqhome" "/usr/local/lib/cgi-bin/aqhome-cgi" + + SetEnv AQHOME_STATIC_FILES /var/www/aqhome-cgi/static + SetEnv AQHOME_RUNTIME_FILES /var/www/aqhome-cgi + SetEnv AQHOME_BASE_URL http://aqhome.withinet.lan/aqhome + AllowOverride None + Options +ExecCGI + SetHandler cgi-script + Require all granted + + + From 32bf7c0da44774fe59c91843dc6ccda633c0f286 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 26 Oct 2025 00:16:36 +0200 Subject: [PATCH 19/24] set LimitNOFILE for unit aqhome-data currently we use one file per value, so we need a larger max number of open files. --- etc/aqhome-data.service | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/aqhome-data.service b/etc/aqhome-data.service index 2be5421..4c6a908 100644 --- a/etc/aqhome-data.service +++ b/etc/aqhome-data.service @@ -11,6 +11,7 @@ RemainAfterExit=no ExecStart=/usr/local/sbin/aqhome-data --datafolder=/var/lib/aqhome-data -p /var/run/aqhome-data.pid Restart=on-failure RestartSec=5s +LimitNOFILE=16384 [Install] WantedBy=multi-user.target From f858b5b3de01192fddb8a5d7c56a4cfbecd26d31 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 26 Oct 2025 00:17:25 +0200 Subject: [PATCH 20/24] added icons. --- apps/aqhome-cgi/modules/html/pics/cancel.png | Bin 0 -> 1775 bytes apps/aqhome-cgi/modules/html/pics/edit.png | Bin 0 -> 912 bytes apps/aqhome-cgi/modules/html/pics/graph.png | Bin 0 -> 1741 bytes apps/aqhome-cgi/modules/html/pics/minus.png | Bin 0 -> 356 bytes apps/aqhome-cgi/modules/html/pics/ok.png | Bin 0 -> 1013 bytes apps/aqhome-cgi/modules/html/pics/plus.png | Bin 0 -> 834 bytes apps/aqhome-cgi/modules/html/style.css | 63 +++++++++++++++++++ 7 files changed, 63 insertions(+) create mode 100644 apps/aqhome-cgi/modules/html/pics/cancel.png create mode 100644 apps/aqhome-cgi/modules/html/pics/edit.png create mode 100644 apps/aqhome-cgi/modules/html/pics/graph.png create mode 100644 apps/aqhome-cgi/modules/html/pics/minus.png create mode 100644 apps/aqhome-cgi/modules/html/pics/ok.png create mode 100644 apps/aqhome-cgi/modules/html/pics/plus.png create mode 100644 apps/aqhome-cgi/modules/html/style.css diff --git a/apps/aqhome-cgi/modules/html/pics/cancel.png b/apps/aqhome-cgi/modules/html/pics/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..20ada8f92be509d70263f0a459ac9b03e559ed60 GIT binary patch literal 1775 zcmVoGwzJP0^$_Bt@qD(u1=38qVuJx*$c`=?ckYzV`=iUZ>cQ66hC5FA+Uwu*Cmuf` zW4Ro6g}0WZrL*HtWt?4P`H{Pw%=z3&%iiZoOkEhR=uj8bTslBk#o zZQi778 z6iA6t5-DTqX_Kjf&pU6w?R%Nb(8BD&7tZ(-xe*$bodLK2j7d>OVGsaVQ5Y`$;rG9* zRUbTJR9hIOFe=3;*?lRbOlYbm#e&cEw|+VxabvD{D(gDstBVW%#8{rj+9QP4L*a>T zv#S)#wMGqC61^hyyzDGaf5+hSEU|TjL#^Z6V!5?pyYmM5IC4j8! zmai@@_>-e~g8RFuYIP8fBvEZvqL|N`K`k+6>4VDl=c4~9JkKlt?AkTIP{m?Hm6g(Wj?H;_FGrHL!3c!qb_BG*Xn|4|uF>S24ANvtR#zcShrrvcgfX8E zfe#2gBeAwx`u5S|-k6s|YK0I^PXKL!woux}XhBk`U|OvKc&OW~h7q4OnnU431$q*B zZ~4ph_0p>|$Gm)Q6lM0F-s(yigi@&8Dr#%%S-8-Irp;<}F#Nd!dlF~!-tz5ArS!_t zW8P@SL#w?EfKUn@w2+kwmN8GOU1&lbvKmJGy?!wKK!K+cx#ioHN@;$&=#9D=w6YLN zL6VTJuOrfQ2t0f#IP5!)4;or&P!gdPD2aSa#y|;nY-OcyloolcWj950x+7>B z!)Fg4)S7X;WC7(%XV3a4=jK7$on5ZG?rL+h51vp>2jKwS>!pA0?$*{@0UH)Xm;nJB zn3sl}W%I_-Ssy4{nUN8W%p5^$h3WQ#LMcqMf!f|i2&jvsllGlK_mZd%fB`rR=?Q`I=|aID&$#^U8^VW4z zU1-x#6vzLq9|h-_DC&a>69iwT_$2tWp)ZPv6G2g5uK1uJI7Lwq1>Z#cm`>-%)ZMN_ z#Ru62P9H=nqEp#w*R4t0wQ15cX*aF7xsR?(llag~bknY_*$_N%NZ=m${q8+U?hWw2 z1$Xw0bLeKR{-S(61pw}66dR4Y|&AP$CA=KF$k?0=~ z5@YGg@$qSW28J)4r>m{nx@0nmx&{YQiqc_wy`4z;Bs;%-{<)V=9!DnDn!WUri7a+Fj{+!#-jr16F4MU54!zR z!%Y)N-MT?zqCk4XJs9mJ};C&H@t!T;ROpQ_v)x5hDn6!Lb}IWFuWiE<^EkNi#!p! z-B5#GFg@{t;du+B>+e%p43n_uBeb9wOfYV*QnZ5Mc?qOxJ(WbBaPD?!AqK1o@SFwG zc1mTDCn47d=phDdsMi#DP6BF!oysCl0`2dia}0dB!7a$V;#2N5S$9L#(LkjLPy8R+ z0FFU`>&phWATuE=0NqH{xaKdQIvS`f3dHyB4Ztzz3HRBL{2o3Fz?`4Js*zeYa8?1e z(LrTVAk5p>0LLK6f0_ul7*LyWuK`d1qz!n^F{wwRj~>!bJV(5*odCxoB>V!m0+?sO zVSrOcW?kx>qPexTn(uV$&vtCpTURaBYvx$TkIps#3jr(vuo%Ds0CRsgfqdh~W^~}# ziSm^zOOK|DY)Ee22u`y(jwo6cfTaKy8Ng8h{YH+#gjvr9GH3VF<;$9_Y6=~07x=`t ztEaLnp=F1BaXy mTee+BrpLvYfghHCCcXpmAKrOcD_yhz0000IR5Gb{$NxL2@#Fw9!md(vUWjnd0<^r!!5f zG@brPreis2-P)Z}x#PADHUY#iWmm)BM=w@>Om zS@VbWzaqz4e@*~^CWL?|Bw`7;0?C?vZ|`ty-m+9^%(l}E*jFyR?NQBjeW zE0E+z*z2f9qgBVmuRzn_1wHU(4-mpfOdx3uSAIx$P+D60D!3%h6s(u6jyDzU-iv>B zpB=96zF^+CWdk;C*=P(CT$7uZQ=XOiEqu~<+H_vmc?tjoiwP_t@OTeIvB*fzz?9pL z`wK4YJET!A+_^yF781d-EZhPY@`^JtI(Hjxi$pG7kjky!xPs?j*rimX?-MI-QORhrnZ$u1GUL$fN&uzp33YaX79jPQ4>< zk8-eo*d&RWs@btyE$^AI!9Fsf_xp^SXUi=~m$W&#-;wtB4H)KJbJE=<&nw602JzWU zx4PvuyDKn;VDa<_Nq{SmXwsFb^3I`8VQ+OA0idhCPcMs2Fc-YEQ+}(nw_Fq>KzrL& zL)Uv>jQIWRb#B+~tU<%Nq;#VyS5eOMJS0*v>IeR%Z~1|}EBKItpb{+gz|-<%h+~DY z{;da+L2h`%1{Um97T53hV^>)`GM`nVt?M%4ElR`w{W*rmz7O|Vw6``P_qkjMX%>B5 z{m^(1oA!UengYKGI-QOZ@H`JZ-UCS3Ayj0QY_yHu9m4duLv6o3Zdpp%2E=UlR&yMu z9h)50TF+lUA5uF2DZ1GF*tKG_=b^`D`^SL#uXUGP;p~9E=B z+?HUchS&S|aRuXX_BwaiO#xuw^sHrmsz+|GbB{!_0RS2R2;fHm0FacCsGoF>!QL@r z^i7R7k9>NC9Le1Di$KTaf(O_v8ytwx1AMdxH=4$vc%U{tuwKS0`v~^F@us2ecP9)F zgu;+nus->l@VV#V03yzSaIDkmD6HR_OHNe$g`{Ub7cvXxdpfQUlogSNT^q^l#}%aV zXGa`mDpg#dO`oMHf7X1F+`DEWXMg&W&N7uM;>-v~izOhTb7*0D@)g(R+AMQNFB)fv ze(=nnoQ2s+>AH;dHGZ3G=RQ)%qnVni z>EpkA>P+9XdCcY3vez4)%}9A#zOGPnDADDVHVux{1_vxtsq$4Er&e*C)H*RSLZvBl z$l*6%$I;)Oz<+G55DJBO?YjqYqYgkmv73=>#vNv$HzbnB+|`+j8)fSt@-=Z4~yN`9gj)onMO4mLqqSyi>v z?G*qRMe>ichX#xXiVuLMDDa<;fy{gXVjsf7Lmrd&9^i9<%n1O3a6QoZ_fzPe_BbJw z7=j^8aM{(pH6PgqiA37RCa6zZtsz(Khh3w`-p4cMwBH{y-lfHur9@7eBDNch%n85- zu)`;*DM+>SEN)V=$AtxQ1+iX j92${05QVSliPL`pcG2zNjLfpq00000NkvXXu0mjf;(1_O literal 0 HcmV?d00001 diff --git a/apps/aqhome-cgi/modules/html/pics/minus.png b/apps/aqhome-cgi/modules/html/pics/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..6fe6cf6b033d52a9719edf2eb4392bd79033292e GIT binary patch literal 356 zcmV-q0h|7bP) zfZ3KkD@r0l%w`MjCXWMv3ZSYgUSFP3|;t>S6^fa2{(;%0_nxcjDogw%B6YpD|u`BM-eC;W+6On)Vg@r?lz zL{6(VwQVHsZe>BL?|&_BW`xJO0r!T(qdnXKshybiA+=4eeLiLXpz4OKowDT)2q6h6 z2+xBT5kv&3N!0ax&A|BP`eG-);SMwlg+ih52l)gr`Od+H6ERBw00001uSXT~wc;BmpmO(F$aXyvF4L={BhY8pjl5mlgcLDVk7u6uq5zk#l*{DP`N zy|`7CNKw?9rWI9d2v?;9i`vBY*w}NX3wsFnOMz8+w=?>l=ljk%ItMQDe~&nCKy+-P z9ryxxFf%zmz5Ba7Z@3|~cwel$xm+lGeyOc@K9!i-A#rX3F1)*^)2t1cG=xIrH!{OD z@AU1EI2QpI-qX`*hTB@un}Te54C)OZh3u&#kAn9S z#f&1ozCIjkzdfHyOiiEZCX9|vv>Un>@9XI@8(W)k>T1YolAM&JHObFqiSy<6P_ocd zvuU7NKd2B82V(o}+(Y5LU1q4Y8CC5(r%C=s@}#I?&9Bm^Y~(+S>1yrFo+WVMpMG}N zY|_=}t4Qb9sl?Rkap3*EU1qqo8OL9PRfQ*QjmITPdEq6EkDnpepQlB6bE`4AyATi` z9f_GYuQzig(%^luvN|f>>OD}R0+;cDzFTIvtul5?R>uCMsPU^U(U!KsONAX%mHWZp zYq?6XP(t{8T)Q0dCTEvNebK=^5-vQ}_qy}ECP@iNJTF)fI{G2-EddvPeETMqmqYq(o^N(@&rA%}!XG)AAC5_Wj0ki-_SJTIrvM- z6TxBIW#mp`QYax%;=*(J*?>21GhH)nF z0|mBA%rC4A)q8!B-wQg^!b8q;c5pbxlgvFGcDSuW4SYbhAwbSBu(K9dzIt>jIDmH4 z57ojkZEY^$Oee7r6dX?7xtn9Z2clyW0mtygOOdxbw9WFFz)vLLN>F(xK=nR94g5bP jIyMogid^I(XOe#bcar7>5!BZNAbO2BDDhJPh=?1C zVjd9$3u|T|sXsQdSCq8^NDL$py515;Ki!qi6mIeYp4!8No1c#S%z2j*!A5*iEy zIYYZNfK7G8{_$_vMKaeG0}|%;x*+2$HaRKDdD^Eo;?42z7YhzBD_RU(tTNHnmdlp47{!O zkg!1Q^IESOfDlu_cB^Ryv1$Mmo+7sUTrbB!Hx1<2OYQX%8t4wdSZ=SYXCU9_3rg*i z-WoJ8E&gWQ``oLXYPMHqMY2~-_PRO%8n*pa|K}yU2f$WW0H1vP2ZS@fpM%|6Bme*a M07*qoM6N<$f@0)*5C8xG literal 0 HcmV?d00001 diff --git a/apps/aqhome-cgi/modules/html/style.css b/apps/aqhome-cgi/modules/html/style.css new file mode 100644 index 0000000..18a4b39 --- /dev/null +++ b/apps/aqhome-cgi/modules/html/style.css @@ -0,0 +1,63 @@ +body { + background-color: whitesmoke; +} + +table.datatable { + border: thin solid; + border-collapse: collapse; +} + + +table.datatable th, td { + border: thin solid; + border-collapse: collapse; + padding: 5px; +} + + +table.datatable tbody tr:nth-child(odd) { + background-color: #ffffff; +} + + + +table.formtable { + border: thin solid; + border-collapse: collapse; +} + + +table.formtable th, td { + border: thin solid; + border-collapse: collapse; + padding: 5px; +} + + + +ul.mainmenu { + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; + background-color: #333333; +} + + +ul.mainmenu li { + float: left; +} + +ul.mainmenu li a { + display: block; + color: white; + text-align: center; + padding: 14px 16px; + text-decoration: none; +} + +ul.mainmenu li a:hover { + background-color: #111111; +} + + From 2f694f983ae624b6a4324cd75ef285e960154db5 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 26 Oct 2025 16:58:29 +0100 Subject: [PATCH 21/24] simplify graph code. --- .../modules/devices/mdevices_vgraph.c | 209 +++++++----------- 1 file changed, 74 insertions(+), 135 deletions(-) diff --git a/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c index fad25d3..ed3c0ae 100644 --- a/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c +++ b/apps/aqhome-cgi/modules/devices/mdevices_vgraph.c @@ -53,6 +53,34 @@ enum { +/* ------------------------------------------------------------------------------------------------ + * vars + * ------------------------------------------------------------------------------------------------ + */ + +typedef struct MY_GRAPH_PARAMS MY_GRAPH_PARAMS; +struct MY_GRAPH_PARAMS { + const char *name; + const char *title; + const char *modifiers; + int startTimeDiff; + int acceptedAgeInSeconds; +}; + + + +static MY_GRAPH_PARAMS _graphParams[]={ + {"4h", "last 4 hours", "Lm5", 4*60*60, 2*60}, + {"1d", "last 24 hours", "Lm30", 24*60*60, 5*60}, + {"1w", "last 7 days", "Lm240", 7*24*60*60, 15*60}, + {"1m", "last 30 days", "Lm480", 30*24*60*60, 60*60}, + {"6m", "last 6 months", "Lm720", 182*24*60*60, 60*60}, + {"12m","last 12 months", "Lm1440", 365*24*60*60, 60*60}, + {NULL, NULL, NULL, 0, 0} +}; + + + /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ @@ -60,27 +88,22 @@ enum { 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 MY_GRAPH_PARAMS *graphParams, 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 AQDG_GRAPH *_mkGraphObjectWithTitle(const char *graphTitle, const MY_GRAPH_PARAMS *graphParams, int precision); +static void _mkPathForValueAndPeriod(AQH_MODULE *m, const AQH_VALUE *v, const MY_GRAPH_PARAMS *graphParams, GWEN_BUFFER *dbuf); 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); +static const MY_GRAPH_PARAMS *_getParamsByName(const char *s); @@ -95,11 +118,11 @@ void AQH_ModDevices_RunGraphValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION const char *sDeviceName; const char *sValueName; - DBG_ERROR(NULL, "GraphValue"); + DBG_DEBUG(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:""); + DBG_DEBUG(NULL, "Device=%s, value=%s", sDeviceName?sDeviceName:"", sValueName?sValueName:""); if (sDeviceName && *sDeviceName && sValueName && *sValueName) { GWEN_BUFFER *bufDeviceName; GWEN_BUFFER *bufValueName; @@ -108,7 +131,7 @@ void AQH_ModDevices_RunGraphValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION GWEN_Text_UnescapeToBufferTolerant(sDeviceName, bufDeviceName); bufValueName=GWEN_Buffer_new(0, 64, 0, 1); GWEN_Text_UnescapeToBufferTolerant(sValueName, bufValueName); - _runGraphValueWithArgs(m, rq, session, dc, + _runGraphValueWithArgs(m, rq, dc, GWEN_Buffer_GetStart(bufDeviceName), GWEN_Buffer_GetStart(bufValueName), dbuf); @@ -121,7 +144,6 @@ void AQH_ModDevices_RunGraphValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION void _runGraphValueWithArgs(AQH_MODULE *m, AQCGI_REQUEST *rq, - AQH_SESSION *session, AQH_DATACLIENT *dc, const char *sDeviceName, const char *sValueName, @@ -129,14 +151,16 @@ void _runGraphValueWithArgs(AQH_MODULE *m, { GWEN_DB_NODE *dbQuery; AQH_VALUE *value; + const MY_GRAPH_PARAMS *graphParams; const char *sPeriod; - int period; - DBG_ERROR(NULL, "GraphValue with args"); + DBG_DEBUG(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", + graphParams=_getParamsByName(sPeriod); + if (graphParams==NULL) + graphParams=&_graphParams[0]; + DBG_DEBUG(NULL, "Device=%s, value=%s, period=%s", sDeviceName?sDeviceName:"", sValueName?sValueName:"", sPeriod?sPeriod:""); @@ -146,12 +170,12 @@ void _runGraphValueWithArgs(AQH_MODULE *m, 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"); + _mkPathForValueAndPeriod(m, value, graphParams, fbuf); + if (!_fileIsCurrent(GWEN_Buffer_GetStart(fbuf), graphParams->acceptedAgeInSeconds)) { + DBG_DEBUG(NULL, "Creating graph"); _createGraph(dc, value, - period, + graphParams, sValueName, 2, AQH_ValueModality_toString(AQH_Value_GetModality(value)), @@ -167,7 +191,7 @@ void _runGraphValueWithArgs(AQH_MODULE *m, // return file rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fbuf), ibuf); if (rv<0) { - DBG_ERROR(NULL, "here (%d)", rv); + DBG_ERROR(NULL, "Error reading \"%s\" (%d)", GWEN_Buffer_GetStart(fbuf), rv); } else { GWEN_Buffer_Reset(dbuf); @@ -182,7 +206,7 @@ void _runGraphValueWithArgs(AQH_MODULE *m, AQH_Value_free(value); } else { - DBG_ERROR(NULL, "Could not get value"); + DBG_ERROR(NULL, "Could not get value \"%s/%s\"", sDeviceName, sValueName); } } @@ -199,7 +223,7 @@ int _fileIsCurrent(const char *sPath, int seconds) } t1=time(0); if ((t1-sb.st_mtime)<(time_t) seconds) { - DBG_ERROR(NULL, "File %s is current", sPath); + DBG_DEBUG(NULL, "File %s is current", sPath); return 1; } @@ -210,7 +234,7 @@ int _fileIsCurrent(const char *sPath, int seconds) void _createGraph(AQH_DATACLIENT *dc, const AQH_VALUE *v, - int period, + const MY_GRAPH_PARAMS *graphParams, const char *graphTitle, int precision, const char *curveLabel, const char *sImgFile, int imgWidth, int imgHeight, uint64_t numDataPoints) @@ -221,31 +245,27 @@ void _createGraph(AQH_DATACLIENT *dc, 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); + tsBegin=time(0)-(graphParams->startTimeDiff); + g=_mkGraphObjectWithTitle(graphTitle, graphParams, precision); - 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); + DBG_DEBUG(NULL, "Adding data for %s", sValue); + AQDG_TimeGraph_ModifyDataAndAddCurve(g, curveLabel?curveLabel:sValue, graphParams->modifiers, dpList); } else { - DBG_ERROR(NULL, "No data"); + DBG_ERROR(NULL, "No data for %s", sValue); 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); + DBG_DEBUG(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); @@ -261,25 +281,14 @@ void _createGraph(AQH_DATACLIENT *dc, -AQDG_GRAPH *_mkGraphObjectWithTitle(const char *graphTitle, int period, int precision) +AQDG_GRAPH *_mkGraphObjectWithTitle(const char *graphTitle, const MY_GRAPH_PARAMS *graphParams, 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 7 days"; break; - case VALUEGRAPH_PERIOD_1M: s="last 30 days"; break; - case VALUEGRAPH_PERIOD_6M: s="last 6 months"; break; - case VALUEGRAPH_PERIOD_12M: s="last 12 months"; break; - default: s="last 24 hours"; break; - } - - GBAA(tbuf, "%s - %s", graphTitle, s); + GBAA(tbuf, "%s - %s", graphTitle, graphParams->title); g=AQDG_TimeGraph_new(GWEN_Buffer_GetStart(tbuf), NULL, "Value", NULL, precision); GWEN_Buffer_free(tbuf); @@ -287,26 +296,7 @@ AQDG_GRAPH *_mkGraphObjectWithTitle(const char *graphTitle, int period, int prec } -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; - else if (strcasecmp(sPeriod, "6m")==0) - return VALUEGRAPH_PERIOD_6M; - else if (strcasecmp(sPeriod, "12m")==0) - return VALUEGRAPH_PERIOD_12M; - return VALUEGRAPH_PERIOD_1D; -} - - - -void _mkPathForValueAndPeriod(AQH_MODULE *m, const AQH_VALUE *v, int period, GWEN_BUFFER *dbuf) +void _mkPathForValueAndPeriod(AQH_MODULE *m, const AQH_VALUE *v, const MY_GRAPH_PARAMS *graphParams, GWEN_BUFFER *dbuf) { AQH_SERVICE *sv; const char *s; @@ -321,75 +311,11 @@ void _mkPathForValueAndPeriod(AQH_MODULE *m, const AQH_VALUE *v, int period, GWE 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; - case VALUEGRAPH_PERIOD_6M: s="6m"; break; - case VALUEGRAPH_PERIOD_12M: s="12m"; break; - default: s="1d"; break; - } - - GBAA(dbuf, "-%s.png", s); + GBAA(dbuf, "-%s.png", graphParams->name); } -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; - case VALUEGRAPH_PERIOD_6M: t-=182*24*60*60; break; - case VALUEGRAPH_PERIOD_12M: t-=365*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 "Lm5"; - case VALUEGRAPH_PERIOD_1D: return "Lm30"; - case VALUEGRAPH_PERIOD_1W: return "Lm240"; - case VALUEGRAPH_PERIOD_1M: return "Lm480"; - case VALUEGRAPH_PERIOD_6M: return "Lm720"; - case VALUEGRAPH_PERIOD_12M: return "Lm1440"; - default: return "Lm30"; - } -} - - - -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 */ - } -} - - - - AQDG_GRAPH_DATAPAIR_LIST *_requestDataPairList(AQH_DATACLIENT *dc, const char *valueName, uint64_t tsBegin, uint64_t tsEnd, uint64_t num) { @@ -407,7 +333,7 @@ AQDG_GRAPH_DATAPAIR_LIST *_requestDataPairList(AQH_DATACLIENT *dc, const char *v return dpList; } else { - DBG_ERROR(NULL, "No data received"); + DBG_ERROR(NULL, "No data received for %s", valueName); free(dataPoints); return NULL; } @@ -420,7 +346,7 @@ AQDG_GRAPH_DATAPAIR_LIST *_createDataPairListFromDataPoints(const uint64_t *data AQDG_GRAPH_DATAPAIR_LIST *dpList; uint64_t i; - DBG_ERROR(NULL, "Got %d datapoints", (int) numValues); + DBG_DEBUG(NULL, "Got %d datapoints", (int) numValues); dpList=AQDG_Graph_DataPair_List_new(); for(i=0; iname) { + if (strcasecmp(p->name, s)==0) + return p; + p++; + } + + return NULL; +} From bb9f86211d1d5a123c9e0098d260a7cdf454d1c5 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 26 Oct 2025 16:59:01 +0100 Subject: [PATCH 22/24] decreased verbosity. --- aqhome/events2/fdobject.c | 2 +- aqhome/ipc2/endpoint.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aqhome/events2/fdobject.c b/aqhome/events2/fdobject.c index b181988..73540c0 100644 --- a/aqhome/events2/fdobject.c +++ b/aqhome/events2/fdobject.c @@ -180,7 +180,7 @@ int AQH_FdObject_Read(AQH_OBJECT *o, uint8_t *ptrBuffer, uint32_t lenBuffer) return GWEN_ERROR_TRY_AGAIN; } else { - DBG_ERROR(AQH_LOGDOMAIN, "Error on read(%d): %s (%d)", xo->fd, strerror(errno), errno); + DBG_INFO(AQH_LOGDOMAIN, "Error on read(%d): %s (%d)", xo->fd, strerror(errno), errno); close(xo->fd); xo->fd=-1; return GWEN_ERROR_IO; diff --git a/aqhome/ipc2/endpoint.c b/aqhome/ipc2/endpoint.c index 4e25306..7787bd9 100644 --- a/aqhome/ipc2/endpoint.c +++ b/aqhome/ipc2/endpoint.c @@ -531,7 +531,7 @@ int _handleMsgSent(AQH_OBJECT *o) if (xo) { AQH_MESSAGE *msg; - DBG_INFO(AQH_LOGDOMAIN, "Messages in outlist: %d", AQH_Message_List_GetCount(xo->msgOutList)); + DBG_DEBUG(AQH_LOGDOMAIN, "Messages in outlist: %d", AQH_Message_List_GetCount(xo->msgOutList)); msg=AQH_Message_List_First(xo->msgOutList); if (msg) { /* remove sent message from list */ @@ -561,7 +561,7 @@ int _handleClosed(AQH_OBJECT *o) { AQH_ENDPOINT *xo; - DBG_ERROR(AQH_LOGDOMAIN, "Connection closed."); + DBG_INFO(AQH_LOGDOMAIN, "Connection closed."); xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_ENDPOINT, o); if (xo) { AQH_Object_Disable(xo->msgWriter); From 4fb9e2ecdf6fb863db6b9edfd06a091885e86491 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 26 Oct 2025 16:59:58 +0100 Subject: [PATCH 23/24] fixed example file for apache2. --- etc/aqhome-apache2.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/aqhome-apache2.conf b/etc/aqhome-apache2.conf index fe29a76..3727ecc 100644 --- a/etc/aqhome-apache2.conf +++ b/etc/aqhome-apache2.conf @@ -1,4 +1,4 @@ - + # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName From 31e677a4aefc1e6aef251e3f5f3406108471f687 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 26 Oct 2025 17:00:12 +0100 Subject: [PATCH 24/24] prepared release 0.0.19 --- 0BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0BUILD b/0BUILD index 3631e9d..dec59b0 100644 --- a/0BUILD +++ b/0BUILD @@ -2,7 +2,7 @@ - + $(project_name) $(project_vmajor).$(project_vminor).$(project_vpatchlevel)
"); + _addGraphLink(sDeviceName, sValueName, "4h", dbuf, 0); + GBAS(dbuf, ""); + _addGraphLink(sDeviceName, sValueName, "1d", dbuf, 0); + GBAS(dbuf, "
"); + _addGraphLink(sDeviceName, sValueName, "1w", dbuf, 0); + GBAS(dbuf, ""); + _addGraphLink(sDeviceName, sValueName, "12m", dbuf, 0); + GBAS(dbuf, "
"); - _addGraphLink(sDeviceName, sValueName, "1d", dbuf); + _addGraphLink(sDeviceName, sValueName, "1d", dbuf, 1); GBAS(dbuf, ""); - _addGraphLink(sDeviceName, sValueName, "1w", dbuf); + _addGraphLink(sDeviceName, sValueName, "1w", dbuf, 1); GBAS(dbuf, "