diff --git a/apps/aqhome-storage/0BUILD b/apps/aqhome-storage/0BUILD
index 7fe94e3..2d39297 100644
--- a/apps/aqhome-storage/0BUILD
+++ b/apps/aqhome-storage/0BUILD
@@ -50,6 +50,7 @@
u_rooms.h
u_devices.h
u_mqtttopics.h
+ u_values.h
u_static.h
u_static_p.h
aqhomehttp.h
@@ -72,6 +73,7 @@
u_rooms.c
u_devices.c
u_mqtttopics.c
+ u_values.c
u_static.c
main.c
aqhomehttp.c
diff --git a/apps/aqhome-storage/init_http.c b/apps/aqhome-storage/init_http.c
index 895be5b..51c9fbb 100644
--- a/apps/aqhome-storage/init_http.c
+++ b/apps/aqhome-storage/init_http.c
@@ -18,6 +18,7 @@
#include "./u_rooms.h"
#include "./u_devices.h"
#include "./u_mqtttopics.h"
+#include "./u_values.h"
#include "./u_static.h"
#include "aqhome/msg/endpoint_tty.h"
@@ -77,6 +78,7 @@ static int _createUrlHandler_login(AQHOME_STORAGE *aqh);
static int _createUrlHandler_rooms(AQHOME_STORAGE *aqh);
static int _createUrlHandler_devices(AQHOME_STORAGE *aqh);
static int _createUrlHandler_topics(AQHOME_STORAGE *aqh);
+static int _createUrlHandler_values(AQHOME_STORAGE *aqh);
static int _createUrlHandler_static(AQHOME_STORAGE *aqh);
@@ -128,12 +130,19 @@ int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
return rv;
}
+
rv=_createUrlHandler_topics(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
+ rv=_createUrlHandler_values(aqh);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ return rv;
+ }
+
rv=_createUrlHandler_static(aqh);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
@@ -291,6 +300,19 @@ int _createUrlHandler_topics(AQHOME_STORAGE *aqh)
+int _createUrlHandler_values(AQHOME_STORAGE *aqh)
+{
+ AQH_HTTP_URLHANDLER *uh;
+
+ uh=AQH_ValuesHttpUrlHandler_new(aqh->httpService);
+ AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
+ AQH_HttpUrlHandler_AddUrlPattern(uh, "/values/*");
+ AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
+ return 0;
+}
+
+
+
int _createUrlHandler_static(AQHOME_STORAGE *aqh)
{
AQH_HTTP_URLHANDLER *uh;
diff --git a/apps/aqhome-storage/u_objects.c b/apps/aqhome-storage/u_objects.c
index b8f5221..e385166 100644
--- a/apps/aqhome-storage/u_objects.c
+++ b/apps/aqhome-storage/u_objects.c
@@ -203,7 +203,7 @@ GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
const char *s;
protocol=AQH_HttpRequest_GetProtocol(rq);
- pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
+ pageBuf=GWEN_Buffer_new(0, 2048, 0, 1);
/* header */
rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
if (rv<0) {
diff --git a/apps/aqhome-storage/u_rooms.c b/apps/aqhome-storage/u_rooms.c
index 499a439..1027966 100644
--- a/apps/aqhome-storage/u_rooms.c
+++ b/apps/aqhome-storage/u_rooms.c
@@ -252,13 +252,13 @@ void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
id=(long unsigned int) AQH_Room_GetId(r);
name=AQH_Room_GetName(r);
descr=AQH_Room_GetDescription(r);
+
GWEN_Buffer_AppendArgs(pageBuf,
"
| %s | %s | "
""
" | "
"
",
name?name:"", descr?descr:"", id);
-
r=AQH_Room_List_Next(r);
}
}
diff --git a/apps/aqhome-storage/u_values.c b/apps/aqhome-storage/u_values.c
new file mode 100644
index 0000000..4b8ee43
--- /dev/null
+++ b/apps/aqhome-storage/u_values.c
@@ -0,0 +1,340 @@
+/****************************************************************************
+ * This file is part of the project AqHome.
+ * AqHome (c) by 2023 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 "./u_values.h"
+#include "./u_objects.h"
+#include "./aqhomehttp.h"
+
+#include
+#include
+#include
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * defines
+ * ------------------------------------------------------------------------------------------------
+ */
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * forward declarations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
+static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
+static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
+static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
+static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
+
+static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
+static void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue);
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * implementations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+AQH_HTTP_URLHANDLER *AQH_ValuesHttpUrlHandler_new(AQH_SERVICE *sv)
+{
+ AQH_HTTP_URLHANDLER *uh;
+
+ uh=AQH_ObjectsHttpUrlHandler_new(sv,
+ AQHOME_HTTP_PERMS_LIST_VALUES,
+ AQHOME_HTTP_PERMS_ADD_VALUE,
+ AQHOME_HTTP_PERMS_DEL_VALUE,
+ AQHOME_HTTP_PERMS_EDIT_VALUE,
+ "/values/list");
+ AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
+ AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
+ AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
+ AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
+ AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
+
+ return uh;
+}
+
+
+
+int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
+{
+ AQH_SERVICE *sv;
+ AQH_STORAGE *sto;
+ AQH_VALUE *newValue;
+ const char *valueName;
+ int rv;
+
+ sv=AQH_HttpUrlHandler_GetHttpService(uh);
+ sto=AqHomeHttpService_GetStorage(sv);
+
+ newValue=AQH_Value_fromDb(db);
+
+ valueName=AQH_Value_GetName(newValue);
+ if (!(valueName && *valueName)) {
+ DBG_INFO(NULL, "Missing value name");
+ AQH_Value_free(newValue);
+ return GWEN_ERROR_INVALID;
+ }
+
+ rv=AqHomeHttpService_LockStorage(sv);
+ if (rv<0) {
+ DBG_ERROR(NULL, "Error locking storage");
+ AQH_Value_free(newValue);
+ return GWEN_ERROR_IO;
+ }
+
+ if (id>0) {
+ AQH_VALUE *value;
+
+ DBG_INFO(NULL, "Edit existing value");
+ value=AQH_Storage_GetValueById(sto, id);
+ if (value==NULL) {
+ AqHomeHttpService_UnlockStorage(sv);
+ DBG_ERROR(NULL, "Value %d not found", id);
+ AQH_Value_free(newValue);
+ return GWEN_ERROR_NOT_FOUND;
+ }
+ AQH_Value_SetId(value, id);
+ _setFromObject(value, newValue);
+ AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
+ }
+ else {
+ AQH_VALUE *value;
+
+ DBG_INFO(NULL, "Adding new value");
+ value=AQH_Storage_GetValueByName(sto, valueName);
+ if (value) {
+ AqHomeHttpService_UnlockStorage(sv);
+ DBG_ERROR(NULL, "Value %s exists", valueName);
+ AQH_Value_free(newValue);
+ return GWEN_ERROR_FOUND;
+ }
+ value=AQH_Value_new();
+ AQH_Value_SetId(value, 0);
+ _setFromObject(value, newValue);
+ AQH_Storage_AddValue(sto, value);
+ AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
+ }
+ AQH_Value_free(newValue);
+
+ rv=AqHomeHttpService_UnlockStorage(sv);
+ if (rv<0) {
+ DBG_ERROR(NULL, "Error unlocking storage");
+ return GWEN_ERROR_IO;
+ }
+ return 0;
+}
+
+
+
+void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue)
+{
+ AQH_Value_SetName(value, AQH_Value_GetName(srcValue));
+ AQH_Value_SetTopicId(value, AQH_Value_GetTopicId(srcValue));
+ AQH_Value_SetValueType(value, AQH_Value_GetValueType(srcValue));
+ AQH_Value_SetValueUnits(value, AQH_Value_GetValueUnits(srcValue));
+ AQH_Value_SetDataPath(value, AQH_Value_GetDataPath(srcValue));
+}
+
+
+
+GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
+{
+ AQH_SERVICE *sv;
+ AQH_STORAGE *sto;
+ const AQH_VALUE *value;
+
+ sv=AQH_HttpUrlHandler_GetHttpService(uh);
+ sto=AqHomeHttpService_GetStorage(sv);
+
+ value=AQH_Storage_GetValueById(sto, id);
+ if (value) {
+ GWEN_DB_NODE *db;
+
+ db=GWEN_DB_Group_new("value");
+ AQH_Value_toDb(value, db);
+ return db;
+ }
+ return NULL;
+}
+
+
+
+int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
+{
+ GWEN_Buffer_AppendArgs(pageBuf,
+ "%s
\n"
+ "", I18N("Submit"));
+ return 0;
+}
+
+
+
+int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
+{
+
+ GWEN_Buffer_AppendArgs(pageBuf,
+ "%s
\n"
+ "", I18N("Submit"));
+ return 0;
+}
+
+
+
+void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
+{
+ AQH_SERVICE *sv;
+ AQH_STORAGE *sto;
+ const AQH_MQTT_TOPIC_LIST *topicList;
+ unsigned long int selectedTopicId=0;
+ char numbuf[16];
+
+ sv=AQH_HttpUrlHandler_GetHttpService(uh);
+ sto=AqHomeHttpService_GetStorage(sv);
+ topicList=AQH_Storage_GetMqttTopicList(sto);
+
+ selectedTopicId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "TopicId", 0, 0):0);
+ snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedTopicId);
+ numbuf[sizeof(numbuf)-1]=0;
+
+ GWEN_Buffer_AppendArgs(pageBuf,
+ " "
+ " "
+ " | "
+ " | "
+ "
",
+ I18N("Name"),
+ dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"");
+ GWEN_Buffer_AppendArgs(pageBuf,
+ " | "
+ " |
");
+
+ GWEN_Buffer_AppendArgs(pageBuf,
+ " "
+ " | "
+ " | "
+ "
",
+ I18N("Units"),
+ dbValues?GWEN_DB_GetCharValue(dbValues, "valueUnits", 0, ""):"");
+ GWEN_Buffer_AppendArgs(pageBuf,
+ " "
+ " | "
+ " | "
+ "
"
+ "
",
+ I18N("Data Path (JSON)"),
+ dbValues?GWEN_DB_GetCharValue(dbValues, "dataPath", 0, ""):"");
+}
+
+
+
+void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
+{
+ AQH_SERVICE *sv;
+ AQH_STORAGE *sto;
+ const AQH_VALUE_LIST *rl;
+
+ sv=AQH_HttpUrlHandler_GetHttpService(uh);
+ sto=AqHomeHttpService_GetStorage(sv);
+
+ GWEN_Buffer_AppendArgs(pageBuf,
+ "%s
"
+ ""
+ ""
+ " | %s | %s | %s | %s | |
"
+ "",
+ I18N("Values"),
+ I18N("Name"),
+ I18N("Topic"),
+ I18N("Units"),
+ I18N("Data Path"));
+ GWEN_Buffer_AppendString(pageBuf, "");
+ rl=AQH_Storage_GetValueList(sto);
+ if (rl) {
+ const AQH_VALUE *value;
+
+ value=AQH_Value_List_First(rl);
+ while(value) {
+ long unsigned int id;
+ int topicId;
+ const char *name;
+ const char *topicName=NULL;
+ const char *valueUnits;
+ const char *dataPath;
+ const AQH_MQTT_TOPIC *topic=NULL;
+
+ id=(long unsigned int) AQH_Value_GetId(value);
+ topicId=(long unsigned int) AQH_Value_GetTopicId(value);
+ if (topicId>0)
+ topic=AQH_Storage_GetMqttTopicById(sto, topicId);
+ if (topic)
+ topicName=AQH_MqttTopic_GetTopic(topic);
+
+ name=AQH_Value_GetName(value);
+ valueUnits=AQH_Value_GetValueUnits(value);
+ dataPath=AQH_Value_GetDataPath(value);
+ GWEN_Buffer_AppendArgs(pageBuf,
+ "| %s | %s | %s | %s | "
+ ""
+ " | "
+ "
",
+ name?name:"",
+ topicName?topicName:"",
+ valueUnits?valueUnits:"",
+ dataPath?dataPath:"",
+ id);
+ value=AQH_Value_List_Next(value);
+ }
+ }
+ GWEN_Buffer_AppendString(pageBuf, "");
+ GWEN_Buffer_AppendArgs(pageBuf, "
%s
", I18N("Add Value"));
+}
+
+
+
+
+
diff --git a/apps/aqhome-storage/u_values.h b/apps/aqhome-storage/u_values.h
new file mode 100644
index 0000000..b7b13f5
--- /dev/null
+++ b/apps/aqhome-storage/u_values.h
@@ -0,0 +1,23 @@
+/****************************************************************************
+ * This file is part of the project AqHome.
+ * AqHome (c) by 2023 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_STORAGE_U_VALUES_H
+#define AQHOME_STORAGE_U_VALUES_H
+
+
+#include "aqhome/http/urlhandler.h"
+
+
+
+AQH_HTTP_URLHANDLER *AQH_ValuesHttpUrlHandler_new(AQH_SERVICE *sv);
+
+
+
+#endif
+
+
diff --git a/aqhome/data/storage.c b/aqhome/data/storage.c
index 8146c08..d6dae45 100644
--- a/aqhome/data/storage.c
+++ b/aqhome/data/storage.c
@@ -211,6 +211,13 @@ AQH_VALUE *AQH_Storage_GetValueById(const AQH_STORAGE *sto, uint64_t id)
+AQH_VALUE *AQH_Storage_GetValueByName(const AQH_STORAGE *sto, const char *s)
+{
+ return sto?AQH_Value_List_GetByName(sto->valueList, s):NULL;
+}
+
+
+
uint32_t AQH_Storage_GetRuntimeFlags(const AQH_STORAGE *sto)
{
return sto?sto->runtimeFlags:0;
diff --git a/aqhome/data/storage.h b/aqhome/data/storage.h
index fb605c5..7679949 100644
--- a/aqhome/data/storage.h
+++ b/aqhome/data/storage.h
@@ -67,6 +67,7 @@ AQHOME_API AQH_MQTT_TOPIC *AQH_Storage_GetMqttTopicByTopic(const AQH_STORAGE *st
AQHOME_API void AQH_Storage_AddValue(AQH_STORAGE *sto, AQH_VALUE *value);
AQHOME_API AQH_VALUE_LIST *AQH_Storage_GetValueList(const AQH_STORAGE *sto);
AQHOME_API AQH_VALUE *AQH_Storage_GetValueById(const AQH_STORAGE *sto, uint64_t id);
+AQHOME_API AQH_VALUE *AQH_Storage_GetValueByName(const AQH_STORAGE *sto, const char *s);
AQHOME_API const char *AQH_Storage_GetStateFile(const AQH_STORAGE *sto);
AQHOME_API void AQH_Storage_SetStateFile(AQH_STORAGE *sto, const char *s);
diff --git a/aqhome/data/value.t2d b/aqhome/data/value.t2d
index fb7c6ea..23473cb 100644
--- a/aqhome/data/value.t2d
+++ b/aqhome/data/value.t2d
@@ -28,6 +28,18 @@
+
+
+
+ -
+ numeric type
+
+
+
+
+
+
+
@@ -37,6 +49,13 @@
with_getbymember
+
+ 0
+ 0
+ public
+ own with_getbymember
+
+
0
0