3 Commits

Author SHA1 Message Date
Martin Preuss
deddf42379 First try to unify ATTN handling. 2025-05-29 14:32:48 +02:00
Martin Preuss
e584245965 c01: added defs when using uart_bitbang2. 2025-05-29 14:32:29 +02:00
Martin Preuss
46720d791c avr: some ideas for autosync. 2025-05-29 12:47:41 +02:00
530 changed files with 12162 additions and 42815 deletions

6
0BUILD
View File

@@ -2,7 +2,7 @@
<gwbuild>
<project name="aqhome" version="0.0.22" so_current="0" so_age="0" so_revision="22" write_config_h="TRUE">
<project name="aqhome" version="0.0.10" so_current="0" so_age="0" so_revision="10" write_config_h="TRUE">
<setVar name="package">$(project_name)</setVar>
<setVar name="version">
$(project_vmajor).$(project_vminor).$(project_vpatchlevel)
@@ -51,8 +51,6 @@
<setVar name="pkgincludedir">$(includedir)/aqhome/$(package)</setVar>
<setVar name="pkgdatadir">$(datadir)/$(package)</setVar>
<setVar name="httpdatadir">/var/www</setVar>
<option id="enable_testcode" type="string">
<default>TRUE</default>
<choices>TRUE FALSE</choices>
@@ -128,7 +126,6 @@
</option>
<checkheaders>
signal.h
sys/stat.h
@@ -153,7 +150,6 @@
<variables>plugindir gwengui-fox16</variables>
</dep>
<dep id="aqcgi" name="aqcgi" minversion="0.0.1" required="TRUE" />
<dep id="aqdiagram" name="aqdiagram" minversion="0.0.1" required="TRUE" />
<!-- <dep id="aqdatabase" name="aqdatabase" minversion="1.99.1" required="TRUE" >
<variables>aqdatabase_typemakerdir</variables>
</dep>

View File

@@ -3,12 +3,11 @@
<gwbuild>
<target type="Program" name="aqhome-cgi" install="$(libdir)/cgi-bin" >
<target type="Program" name="aqhome-cgi" install="$(sbindir)" >
<includes type="c" >
$(gwenhywfar_cflags)
$(aqcgi_cflags)
$(aqdiagram_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
-I$(topsrcdir)/apps
@@ -22,8 +21,6 @@
--include=$(srcdir)
</includes>
<define name="AQHOME_CGI_WWWDIR" value="$(httpdatadir)/aqhome-cgi" quoted="TRUE" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags" >
@@ -50,16 +47,14 @@
</sources>
<useTargets>
aqhome
aqhomecgi
aqhcgi_service
aqhome
</useTargets>
<libraries>
$(gwenhywfar_libs)
-lm
$(aqcgi_libs)
$(aqdiagram_libs)
</libraries>
<subdirs>
@@ -122,19 +117,16 @@
<useTargets>
aqhome
aqhcgi_service
aqhcgi_modules
</useTargets>
<libraries>
$(gwenhywfar_libs)
-lm
$(aqcgi_libs)
$(aqdiagram_libs)
</libraries>
<subdirs>
service
modules
</subdirs>

View File

@@ -1,23 +0,0 @@
Modules:
- login
- signup
- main
- devices
- list
- show?name="nodes/12345678"
- add
- edit
- delete
- values
- rooms
- users
- list
- show?alias="admin"
- add
- edit
- delete
- dashboards

View File

@@ -1,264 +1,11 @@
#include "./service_file.h"
#include "aqhome-cgi/modules/mroot.h"
#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/devices/mdevices.h"
#include "aqhome/aqhome.h"
#include <aqcgi/cgi.h>
#include <aqcgi/request.h>
#include <aqdiagram/aqdiagram.h>
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/nogui.h>
#include <gwenhywfar/logger.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#define AQHOME_CGI_LOGFILE "/var/www/aqhome-cgi/log/aqhome-cgi.log"
#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"
/* ------------------------------------------------------------------------------------------------
* 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, 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))
sPathStaticFiles=AQHOME_CGI_DEFAULT_STATIC_FILES;
sPathRuntimeFiles=getenv("AQHOME_RUNTIME_FILES");
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);
logStart();
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);
GWEN_Logger_SetLevel(AQCGI_LOGDOMAIN, GWEN_LoggerLevel_Debug);
GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Debug);
GWEN_Logger_Close(GWEN_LOGDOMAIN);
GWEN_Logger_Open(GWEN_LOGDOMAIN, "gwenhywfar", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
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, sBaseUrl);
if (rv<0) {
fprintf(stderr, "Error on init (%d)\n", rv);
return 2;
}
}
}
else {
AQCGI_REQUEST *rq;
DBG_ERROR(NULL, "Init CGI");
AQCGI_Init();
rq=AQCGI_ReadRequest();
if (rq) {
_handleRequest(rq, sPathStaticFiles, sPathRuntimeFiles, sBaseUrl);
}
else {
fprintf(stdout, "Content-type: text/plain\n\n");
fprintf(stdout, "Error: No Request!\n");
}
AQCGI_Fini();
}
return 0;
}
void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles, const char *sBaseUrl)
{
AQH_SERVICE *sv;
int rv;
sv=AQH_ServiceFiles_new(sPathRuntimeFiles, sBaseUrl);
rv=_handlePath(sv, rq, sPathStaticFiles);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
}
AQH_Service_free(sv);
}
int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles)
{
AQH_MODULE *mRoot;
AQH_MODULE *mParent;
AQH_SESSION *session;
const GWEN_STRINGLIST *sl;
mRoot=AQH_ModRoot_new(sv, sPathStaticFiles);
mParent=mRoot;
session=AQH_ModService_ReadSession(mRoot, rq);
AQH_ModService_CalcSessionModPerms(mRoot, session);
sl=AQCGI_Request_GetStringlistPath(rq);
if (sl) {
GWEN_STRINGLISTENTRY *se;
se=GWEN_StringList_FirstEntry(sl);
while(se) {
GWEN_STRINGLISTENTRY *seNext;
const char *s;
seNext=GWEN_StringListEntry_Next(se);
s=GWEN_StringListEntry_Data(se);
if (s && *s) {
if (seNext) {
AQH_MODULE *m;
DBG_ERROR(NULL, "Entry: %s (%s)", s, seNext?"not last":"last");
m=AQH_ModService_LoadSubModule(mParent, rq, session, s);
if (m==NULL) {
AQH_Session_free(session);
AQH_Module_free(mRoot);
return GWEN_ERROR_GENERIC;
}
mParent=m;
}
else {
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);
AQH_Session_free(session);
AQH_Module_free(mRoot);
return rv;
}
break;
}
}
se=seNext;
}
AQH_Session_free(session);
AQH_Module_free(mRoot);
return 0;
}
else {
AQH_Session_free(session);
AQH_Module_free(mRoot);
return GWEN_ERROR_GENERIC;
}
}
void logStart()
{
FILE *f;
f=fopen(AQHOME_CGI_LOGFILE, "a+");
if (f!=NULL) {
fprintf(f, "Started.\n");
fclose(f);
}
}
int _init(const char *sPathRuntimeFiles, const char *sBaseUrl)
{
AQH_SERVICE *sv;
int rv;
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\"");
AQH_Service_free(sv);
return rv;
}
rv=AQH_ModAdmModules_Create(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error creating module \"modules\"");
AQH_Service_free(sv);
return rv;
}
rv=AQH_ModAdmUsers_Create(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error creating module \"users\"");
AQH_Service_free(sv);
return rv;
}
rv=AQH_ModDevices_Create(sv);
if (rv<0) {
DBG_ERROR(NULL, "Error creating module \"devices\"");
AQH_Service_free(sv);
return rv;
}
AQH_Service_free(sv);
return 0;
}

View File

@@ -1,87 +0,0 @@
<?xml?>
<gwbuild>
<target type="ConvenienceLibrary" name="aqhcgi_modules" >
<includes type="c" >
$(gwenhywfar_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
-I$(topsrcdir)/apps
-I$(topbuilddir)/apps
-I$(builddir)
-I$(srcdir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<define name="not_BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags-INACTIVE" >
--api=AQHOME_API
</setVar>
<setVar name="local/typefiles" >
</setVar>
<setVar name="local/built_sources" >
</setVar>
<setVar name="local/built_headers_pub">
</setVar>
<setVar name="local/built_headers_priv" >
</setVar>
<headers dist="false" install="$(pkgincludedir)/service" >
$(local/built_headers_pub)
</headers>
<headers dist="true" install="$(pkgincludedir)/service" >
mdataclient.h
mroot.h
</headers>
<headers dist="true" >
mroot_p.h
</headers>
<sources>
$(local/typefiles)
mdataclient.c
mroot.c
</sources>
<extradist>
</extradist>
<useTargets>
aqhcgi_modcom
aqhcgi_mdevices
</useTargets>
<subdirs>
common
devices
static
</subdirs>
</target>
</gwbuild>

View File

@@ -1,86 +0,0 @@
<?xml?>
<gwbuild>
<target type="ConvenienceLibrary" name="aqhcgi_modcom" >
<includes type="c" >
$(gwenhywfar_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
-I$(topsrcdir)/apps
-I$(topbuilddir)/apps
-I$(builddir)
-I$(srcdir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<define name="not_BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags-INACTIVE" >
--api=AQHOME_API
</setVar>
<setVar name="local/typefiles" >
</setVar>
<setVar name="local/built_sources" >
</setVar>
<setVar name="local/built_headers_pub">
</setVar>
<setVar name="local/built_headers_priv" >
</setVar>
<headers dist="false" install="$(pkgincludedir)/service" >
$(local/built_headers_pub)
</headers>
<headers dist="true" install="$(pkgincludedir)/service" >
mservice.h
madmin.h
mmodules.h
musers.h
</headers>
<headers dist="true" >
mservice_p.h
</headers>
<sources>
$(local/typefiles)
mservice.c
madmin.c
mmodules.c
musers.c
</sources>
<extradist>
</extradist>
<useTargets>
</useTargets>
<subdirs>
</subdirs>
</target>
</gwbuild>

View File

@@ -1,217 +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 <config.h>
#endif
#include "./madmin.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/common/mmodules.h"
#include "aqhome-cgi/modules/common/musers.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* global vars
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* 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 int _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModAdmin_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_ModAdmin_Create(AQH_SERVICE *sv)
{
AQH_MODULE *m;
int rv;
m=AQH_Module_new();
AQH_Module_SetName(m, "admin");
AQH_Module_SetDescr(m, "administration 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, "AdminUsers", 0x001, "User Administration");
AQH_ModService_AddPermDef(permDefList, "AdminModules", 0x002, "Module Administration");
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++, "userAdmin", AQH_MODADM_PERMS_ADMINUSERS, "User administrator");
AQH_ModService_AddRole(roleList, id++, "moduleAdmin", AQH_MODADM_PERMS_ADMINMODULES, "Module administrator");
AQH_Module_SetRoleList(m, roleList);
}
AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName)
{
AQH_SERVICE *sv;
sv=AQH_ModService_GetService(m);
if (strcasecmp(sModuleName, "modules")==0) {
AQH_MODULE *mSub;
mSub=AQH_Service_LoadModule(sv, sModuleName);
if (mSub) {
const char *s;
GWEN_BUFFER *nbuf;
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
s=AQH_ModService_GetBaseFolder(m);
GWEN_Buffer_AppendArgs(nbuf, "%s/modules", s?s:".");
AQH_ModAdmModules_Extend(mSub, AQH_ModService_GetService(m), GWEN_Buffer_GetStart(nbuf));
AQH_Module_Tree2_AddChild(m, mSub);
GWEN_Buffer_free(nbuf);
return mSub;
}
}
else if (strcasecmp(sModuleName, "users")==0) {
AQH_MODULE *mSub;
mSub=AQH_Service_LoadModule(sv, sModuleName);
if (mSub) {
const char *s;
GWEN_BUFFER *nbuf;
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
s=AQH_ModService_GetBaseFolder(m);
GWEN_Buffer_AppendArgs(nbuf, "%s/modules", s?s:".");
AQH_ModAdmUsers_Extend(mSub, AQH_ModService_GetService(m), GWEN_Buffer_GetStart(nbuf));
AQH_Module_Tree2_AddChild(m, mSub);
GWEN_Buffer_free(nbuf);
return mSub;
}
}
return NULL;
}
int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem)
{
GWEN_BUFFER *dbuf;
int rv=0;
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
AQH_ModService_AddHeader(m, "en", dbuf);
if (strcasecmp(sLastPathElem, "index.html")==0) {
if (AQH_ModService_GetUserPerms(m) & (AQH_MODADM_PERMS_ADMINUSERS | AQH_MODADM_PERMS_ADMINMODULES))
rv=_handleRqIndex(m, rq, dbuf);
else {
AQCGI_Request_SetResponseCode(rq, 403);
AQCGI_Request_SetResponseText(rq, "Forbidden");
}
}
else {
AQCGI_Request_SetResponseCode(rq, 404);
AQCGI_Request_SetResponseText(rq, "Not Found");
}
AQH_ModService_AddFooter(m, "en", dbuf);
AQCGI_Request_SetBufferResponseBody(rq, dbuf);
AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html");
return AQCGI_SendResponse(rq);
}
int _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf)
{
if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_GET) {
uint32_t userPerms;
GWEN_Buffer_AppendString(dbuf, "<table>");
userPerms=AQH_ModService_GetUserPerms(m);
if (userPerms & AQH_MODADM_PERMS_ADMINUSERS)
GWEN_Buffer_AppendString(dbuf,
"<tr>"
"<td><a href=\"users/index.html\" >User administration</a></td>"
"<td>Add, remove or modify users</td>"
"</tr>\n");
if (userPerms & AQH_MODADM_PERMS_ADMINMODULES)
GWEN_Buffer_AppendString(dbuf,
"<tr>"
"<td><a href=\"modules/index.html\" >Module administration</a></td>"
"<td>Add, remove or modify modules</td>"
"</tr>\n");
GWEN_Buffer_AppendString(dbuf, "</table>\n");
AQCGI_Request_SetResponseCode(rq, 200);
AQCGI_Request_SetResponseText(rq, "Ok");
return 0;
}
AQCGI_Request_SetResponseCode(rq, 405);
AQCGI_Request_SetResponseText(rq, "Method Not Allowed");
return 0;
}

View File

@@ -1,31 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MADMIN_H
#define AQHOME_CGI_MADMIN_H
#include <aqhome-cgi/modules/common/mservice.h>
#include <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
#define AQH_MODADM_PERMS_ADMINUSERS 0x001
#define AQH_MODADM_PERMS_ADMINMODULES 0x002
void AQH_ModAdmin_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder);
int AQH_ModAdmin_Create(AQH_SERVICE *sv);
#endif

View File

@@ -1,745 +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 <config.h>
#endif
#include "./mmodules.h"
#include "aqhome-cgi/service/module.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* 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 _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqEditModGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqEditModPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqAddRoleGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqAddRolePost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqEditRoleGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqEditRolePost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static int _getHighestUsedRoleId(const AQH_ROLE_LIST *roleList);
static void _handleRqDeleteRole(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _writeEditModForm(const AQH_MODULE *currentMod, const char *sModName, GWEN_BUFFER *dbuf);
static void _writeRoleListToForm(const AQH_ROLE_LIST *roleList,
const char *sModName,
const AQH_PERMDEF_LIST *permDefList,
GWEN_BUFFER *dbuf);
static void _setLocationHeaderForMod(AQCGI_REQUEST *rq, const char *page, const char *sModName);
static void _writeEnabledPermissions(const AQH_PERMDEF_LIST *permDefList, uint32_t perms, GWEN_BUFFER *dbuf);
/* ------------------------------------------------------------------------------------------------
* vars
* ------------------------------------------------------------------------------------------------
*/
static AQH_MODSERVICE_HANDLER_ENTRY _requestTable[]={
{"index.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMMODULES_PERMS_MODULESREAD, _handleRqIndex},
{"editmodule.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqEditModGet},
{"editmodule.html", AQCGI_REQUEST_METHOD_POST, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqEditModPost},
{"addrole.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqAddRoleGet},
{"addrole.html", AQCGI_REQUEST_METHOD_POST, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqAddRolePost},
{"editrole.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqEditRoleGet},
{"editrole.html", AQCGI_REQUEST_METHOD_POST, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqEditRolePost},
{"delrole.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMMODULES_PERMS_MODULESWRITE, _handleRqDeleteRole},
{NULL, 0, 0, NULL}
};
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModAdmModules_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_ModAdmModules_Create(AQH_SERVICE *sv)
{
AQH_MODULE *m;
int rv;
m=AQH_Module_new();
AQH_Module_SetName(m, "modules");
AQH_Module_SetDescr(m, "modules administration 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, "ModuleRead", 0x001, "Read modules");
AQH_ModService_AddPermDef(permDefList, "ModuleWrite", 0x002, "Modify modules");
AQH_ModService_AddPermDef(permDefList, "ModuleAdd", 0x004, "Add modules");
AQH_ModService_AddPermDef(permDefList, "ModuleDel", 0x008, "Remove modules");
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++, "admin",
AQH_MODADMMODULES_PERMS_MODULESREAD |
AQH_MODADMMODULES_PERMS_MODULESWRITE |
AQH_MODADMMODULES_PERMS_MODULESADD |
AQH_MODADMMODULES_PERMS_MODULESDEL,
"Administrator Role");
AQH_Module_SetRoleList(m, roleList);
}
AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName)
{
/* no sub-modules */
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 _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_STRINGLIST *slModules;
uint32_t perms;
perms=AQH_ModService_GetUserPerms(m);
sv=AQH_ModService_GetService(m);
slModules=AQH_Service_ListModules(sv);
if (slModules) {
GWEN_STRINGLISTENTRY *se;
GBAS(dbuf, "<h1>Modules</h1>\n");
GBAS(dbuf,
"<table class=\"datatable\">\n"
"<thead>"
"<tr><th>Id</th><th>Name</th><th>Description</th><th>Actions</th></tr>\n"
"</thead>\n"
"<tbody>\n");
se=GWEN_StringList_FirstEntry(slModules);
while(se) {
const char *sModName;
sModName=GWEN_StringListEntry_Data(se);
if (sModName && *sModName) {
AQH_MODULE *currentMod;
currentMod=AQH_Service_LoadModule(sv, sModName);
if (currentMod) {
const char *s;
const char *sName;
sName=AQH_Module_GetName(currentMod);
GBAS(dbuf, "<tr>");
GBAA(dbuf, "<td>%lu</td>", (unsigned long int) AQH_Module_GetId(currentMod));
GBAA(dbuf, "<td>%s</td>", sName?sName:"");
s=AQH_Module_GetDescr(currentMod);
GBAA(dbuf, "<td>%s</td>", s?s:"");
GBAS(dbuf, "<td>");
if (perms & AQH_MODADMMODULES_PERMS_MODULESWRITE)
GBAA(dbuf, "<a href=\"editmodule.html?name=%s\"><img src=\"/pics/edit.png\"></a>", sName?sName:"");
GBAA(dbuf, "</td>\n");
GBAA(dbuf, "</tr>\n");
AQH_Module_free(currentMod);
}
}
se=GWEN_StringListEntry_Next(se);
}
GBAS(dbuf,
"</tbody>\n"
"</table>\n");
GWEN_StringList_free(slModules);
}
if (perms & AQH_MODADMMODULES_PERMS_MODULESADD)
GBAS(dbuf, "<hr><a href=\"addmodule.html\">Add Module</a>");
}
void _handleRqEditModGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbQuery;
const char *sModName;
AQH_MODULE *currentMod;
sv=AQH_ModService_GetService(m);
dbQuery=AQCGI_Request_GetDbQuery(rq);
sModName=dbQuery?GWEN_DB_GetCharValue(dbQuery, "name", 0, NULL):NULL;
currentMod=(sModName && *sModName)?AQH_Service_LoadModule(sv, sModName):NULL;
if (currentMod) {
_writeEditModForm(currentMod, sModName, dbuf);
AQH_Module_free(currentMod);
}
else {
AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html");
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See other");
}
}
void _handleRqEditModPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbPost;
const char *sModName;
AQH_MODULE *currentMod;
sv=AQH_ModService_GetService(m);
dbPost=AQCGI_Request_GetDbPostBody(rq);
sModName=dbPost?GWEN_DB_GetCharValue(dbPost, "module", 0, NULL):NULL;
currentMod=(sModName && *sModName)?AQH_Service_LoadModule(sv, sModName):NULL;
if (currentMod) {
const char *sNewModName;
const char *sDescr;
int rv;
uint32_t perms;
const AQH_PERMDEF_LIST *permDefList;
permDefList=AQH_Module_GetPermDefList(currentMod);
sNewModName=GWEN_DB_GetCharValue(dbPost, "name", 0, NULL);
sDescr=GWEN_DB_GetCharValue(dbPost, "descr", 0, NULL);
perms=AQH_ModService_ReadPermsFromForm(dbPost, permDefList, NULL);
if (sNewModName && *sNewModName)
AQH_Module_SetName(currentMod, sNewModName);
AQH_Module_SetDescr(currentMod, sDescr);
AQH_Module_SetGuestPerms(currentMod, perms);
rv=AQH_Service_SaveModule(sv, currentMod);
if (rv<0) {
GBAS(dbuf, "<h2>Error</h2><p>Error saving module</p>");
DBG_ERROR(NULL, "Could not save module \"%s\"", sModName);
AQH_Module_free(currentMod);
return;
}
DBG_ERROR(NULL, "Module \"%s\" saved", sModName);
AQH_Module_free(currentMod);
AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html");
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See other");
}
else {
DBG_ERROR(NULL, "Could not load module \"%s\"", sModName?sModName:"<no name>");
GBAS(dbuf, "<p>Error loading module.</p>\n");
}
}
void _handleRqAddRoleGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbQuery;
const char *sModName;
AQH_MODULE *currentMod;
const AQH_PERMDEF_LIST *permDefList;
uint32_t guestPerms;
sv=AQH_ModService_GetService(m);
dbQuery=AQCGI_Request_GetDbQuery(rq);
sModName=dbQuery?GWEN_DB_GetCharValue(dbQuery, "mod", 0, NULL):NULL;
currentMod=(sModName && *sModName)?AQH_Service_LoadModule(sv, sModName):NULL;
guestPerms=currentMod?AQH_Module_GetGuestPerms(currentMod):0;
permDefList=currentMod?AQH_Module_GetPermDefList(currentMod):NULL;
if (currentMod) {
if (permDefList) {
GBAA(dbuf, "<h2>Add Role for Module %s</h2>\n", sModName?sModName:"");
GBAS(dbuf,
"<form action=\"addrole.html\" method=\"post\">\n"
"<table class=\"formtable\">\n"
"<tr><td><label for=\"name\">Name:</label></td><td><input type=\"text\" name=\"name\"></td>"
"<tr><td><label for=\"descr\">Description:</label></td><td><input type=\"text\" name=\"descr\"></td></tr>\n");
GBAS(dbuf, "<tr><td><label>Permissions:</label></td><td>");
AQH_ModService_WritePermsToForm(guestPerms, permDefList, NULL, dbuf);
GBAS(dbuf, "</td></tr>\n");
GBAS(dbuf, "</table>\n");
GBAA(dbuf, "<input type=\"hidden\" name=\"mod\" value=\"%s\">\n", sModName?sModName:"");
GBAS(dbuf, "<input type=\"submit\" value=\"Add\">\n");
GBAS(dbuf, "</form>\n\n");
}
else {
GBAS(dbuf, "<p>Please add permission definitions first.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
}
AQH_Module_free(currentMod);
}
else {
GBAS(dbuf, "<p>Error loading module.</p>\n");
GBAS(dbuf, "<p><a href=\"index.html\"> back to module list</p>\n");
}
}
void _handleRqAddRolePost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbPost;
const char *sModName;
AQH_MODULE *currentMod;
int newId;
const char *sName;
const char *sDescr;
uint32_t perms;
AQH_PERMDEF_LIST *permDefList;
AQH_ROLE_LIST *roleList;
int rv;
/* sample data */
DBG_ERROR(NULL, "Handling POST request");
sv=AQH_ModService_GetService(m);
dbPost=AQCGI_Request_GetDbPostBody(rq);
sModName=dbPost?GWEN_DB_GetCharValue(dbPost, "mod", 0, NULL):NULL;
currentMod=(sModName && *sModName)?AQH_Service_LoadModule(sv, sModName):NULL;
permDefList=currentMod?AQH_Module_GetPermDefList(currentMod):NULL;
roleList=currentMod?AQH_Module_GetRoleList(currentMod):NULL;
/* read role values */
newId=(roleList?_getHighestUsedRoleId(roleList):0)+1;
sName=dbPost?GWEN_DB_GetCharValue(dbPost, "name", 0, NULL):NULL;
sDescr=dbPost?GWEN_DB_GetCharValue(dbPost, "descr", 0, NULL):NULL;
perms=(dbPost && permDefList)?AQH_ModService_ReadPermsFromForm(dbPost, permDefList, NULL):0;
/* validate */
if (!(sName && *sName)) {
DBG_ERROR(NULL, "Missing value for \"name\"");
GBAS(dbuf, "<p>Missing name.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
return;
}
if (currentMod) {
AQH_ROLE *role;
/* set new values */
role=AQH_Role_new();
AQH_Role_SetId(role, newId);
AQH_Role_SetName(role, sName);
AQH_Role_SetDescr(role, sDescr);
AQH_Role_SetPerms(role, perms);
/* add role */
if (roleList==NULL) {
roleList=AQH_Role_List_new();
AQH_Module_SetRoleList(currentMod, roleList);
}
AQH_Role_List_Add(role, roleList);
/* save module */
rv=AQH_Service_SaveModule(sv, currentMod);
if (rv<0) {
GBAS(dbuf, "<p>Error saving module.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
AQH_Module_free(currentMod);
return;
}
_setLocationHeaderForMod(rq, "editmodule.html", sModName);
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See Other");
AQH_Module_free(currentMod);
}
else {
GBAS(dbuf, "<p>Error loading module.</p>\n");
GBAS(dbuf, "<p><a href=\"index.html\"> back to module list</p>\n");
}
}
void _handleRqEditRoleGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbQuery;
const char *sModName;
int id;
const char *sName;
const char *sDescr;
uint32_t perms;
AQH_MODULE *currentMod;
const AQH_PERMDEF_LIST *permDefList;
const AQH_ROLE_LIST *roleList;
const AQH_ROLE *role;
sv=AQH_ModService_GetService(m);
dbQuery=AQCGI_Request_GetDbQuery(rq);
sModName=dbQuery?GWEN_DB_GetCharValue(dbQuery, "mod", 0, NULL):NULL;
id=dbQuery?GWEN_DB_GetIntValue(dbQuery, "id", 0, 0):0;
currentMod=(sModName && *sModName)?AQH_Service_LoadModule(sv, sModName):NULL;
permDefList=currentMod?AQH_Module_GetPermDefList(currentMod):NULL;
roleList=currentMod?AQH_Module_GetRoleList(currentMod):NULL;
role=roleList?AQH_Role_List_GetById(roleList, id):NULL;
sName=role?AQH_Role_GetName(role):NULL;
sDescr=role?AQH_Role_GetDescr(role):NULL;
perms=role?AQH_Role_GetPerms(role):0;
if (role) {
GBAA(dbuf, "<h2>Edit Role for Module %s</h2>\n", sModName?sModName:"");
GBAA(dbuf,
"<form action=\"editrole.html\" method=\"post\">\n"
"<table class=\"formtable\">\n"
"<tr><td><label for=\"name\">Name:</label></td><td><input type=\"text\" name=\"name\" value=\"%s\"></td></tr>\n"
"<tr><td><label for=\"descr\">Description:</label></td><td><input type=\"text\" name=\"descr\" value=\"%s\"></td></tr>\n",
sName, sDescr?sDescr:"");
GBAS(dbuf, "<tr><td><label>Permissions:</label></td><td>");
AQH_ModService_WritePermsToForm(perms, permDefList, NULL, dbuf);
GBAS(dbuf, "</td></tr>\n");
GBAS(dbuf, "</table>\n");
GBAA(dbuf, "<input type=\"hidden\" name=\"mod\" value=\"%s\">\n", sModName?sModName:"");
GBAA(dbuf, "<input type=\"hidden\" name=\"oldId\" value=\"%d\">\n", id);
GBAS(dbuf, "<input type=\"submit\" value=\"Save\">\n");
GBAS(dbuf, "</form>\n\n");
}
else {
GBAS(dbuf, "<p>Role not found.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
}
}
void _handleRqEditRolePost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbPost;
const char *sModName;
AQH_MODULE *currentMod;
int oldId;
const char *sName;
const char *sDescr;
uint32_t perms;
AQH_PERMDEF_LIST *permDefList;
AQH_ROLE_LIST *roleList;
AQH_ROLE *role;
int rv;
/* sample data */
sv=AQH_ModService_GetService(m);
dbPost=AQCGI_Request_GetDbPostBody(rq);
sModName=dbPost?GWEN_DB_GetCharValue(dbPost, "mod", 0, NULL):NULL;
currentMod=(sModName && *sModName)?AQH_Service_LoadModule(sv, sModName):NULL;
permDefList=currentMod?AQH_Module_GetPermDefList(currentMod):NULL;
roleList=currentMod?AQH_Module_GetRoleList(currentMod):NULL;
/* read role data */
oldId=dbPost?GWEN_DB_GetIntValue(dbPost, "oldId", 0, -1):-1;
sName=dbPost?GWEN_DB_GetCharValue(dbPost, "name", 0, NULL):NULL;
sDescr=dbPost?GWEN_DB_GetCharValue(dbPost, "descr", 0, NULL):NULL;
role=roleList?AQH_Role_List_GetById(roleList, oldId):NULL;
perms=(dbPost && permDefList)?AQH_ModService_ReadPermsFromForm(dbPost, permDefList, NULL):0;
/* validate */
if (!(sName && *sName)) {
DBG_ERROR(NULL, "Missing value for \"name\"");
GBAS(dbuf, "<p>Missing name.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
return;
}
if (role==NULL) {
DBG_ERROR(NULL, "Role %d not found", oldId);
GBAS(dbuf, "<p>Role not found.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
return;
}
if (currentMod) {
/* set new values */
AQH_Role_SetName(role, sName);
AQH_Role_SetDescr(role, sDescr);
AQH_Role_SetPerms(role, perms);
/* save module */
rv=AQH_Service_SaveModule(sv, currentMod);
if (rv<0) {
GBAS(dbuf, "<p>Error saving module.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
AQH_Module_free(currentMod);
return;
}
_setLocationHeaderForMod(rq, "editmodule.html", sModName);
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See Other");
AQH_Module_free(currentMod);
}
else {
GBAS(dbuf, "<p>Error loading module.</p>\n");
GBAS(dbuf, "<p><a href=\"index.html\"> back to module list</p>\n");
}
}
void _handleRqDeleteRole(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbQuery;
const char *sModName;
int id;
AQH_MODULE *currentMod;
const AQH_ROLE_LIST *roleList;
AQH_ROLE *role;
sv=AQH_ModService_GetService(m);
dbQuery=AQCGI_Request_GetDbQuery(rq);
sModName=dbQuery?GWEN_DB_GetCharValue(dbQuery, "mod", 0, NULL):NULL;
id=dbQuery?GWEN_DB_GetIntValue(dbQuery, "id", 0, 0):0;
currentMod=(sModName && *sModName)?AQH_Service_LoadModule(sv, sModName):NULL;
if (currentMod) {
roleList=currentMod?AQH_Module_GetRoleList(currentMod):NULL;
role=roleList?AQH_Role_List_GetById(roleList, id):NULL;
if (role) {
int rv;
AQH_Role_List_Del(role);
AQH_Role_free(role);
/* save module */
rv=AQH_Service_SaveModule(sv, currentMod);
if (rv<0) {
GBAS(dbuf, "<p>Error saving module.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
AQH_Module_free(currentMod);
return;
}
_setLocationHeaderForMod(rq, "editmodule.html", sModName);
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See Other");
}
else {
GBAS(dbuf, "<p>Role not found.</p>\n");
GBAA(dbuf, "<p><a href=\"editmodule.html?name=\"%s\"> back to module</p>\n", sModName?sModName:"");
}
AQH_Module_free(currentMod);
}
else {
GBAS(dbuf, "<p>Error loading module.</p>\n");
GBAS(dbuf, "<p><a href=\"index.html\"> back to module list</p>\n");
}
}
void _setLocationHeaderForMod(AQCGI_REQUEST *rq, const char *page, const char *sModName)
{
GWEN_BUFFER *tbuf;
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GBAA(tbuf, "Location: %s?name=%s", page?page:"", sModName?sModName:"");
AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
}
int _getHighestUsedRoleId(const AQH_ROLE_LIST *roleList)
{
int id=0;
if (roleList) {
const AQH_ROLE *role;
role=AQH_Role_List_First(roleList);
while(role) {
int rid;
rid=AQH_Role_GetId(role);
id=(rid>id)?rid:id;
role=AQH_Role_List_Next(role);
}
}
return id;
}
void _writeEditModForm(const AQH_MODULE *currentMod, const char *sModName, GWEN_BUFFER *dbuf)
{
const char *sName;
const char *sDescr;
const AQH_PERMDEF_LIST *permDefList;
const AQH_ROLE_LIST *roleList;
permDefList=AQH_Module_GetPermDefList(currentMod);
roleList=AQH_Module_GetRoleList(currentMod);
sName=AQH_Module_GetName(currentMod);
sDescr=AQH_Module_GetDescr(currentMod);
/* write module info */
GBAS(dbuf, "<h2>Module Info</h2>\n");
GBAA(dbuf,
"<form action=\"editmodule.html\" method=\"post\">\n"
"<table class=\"formtable\">\n"
"<tr><td><label for=\"name\">Name:</label></td><td><input type=\"text\" name=\"name\" value=\"%s\"></td></tr>\n"
"<tr><td><label for=\"descr\">Description:</label></td><td><input type=\"text\" name=\"descr\" value=\"%s\"></td></tr>\n",
sName?sName:"", sDescr?sDescr:"");
if (permDefList) {
GBAA(dbuf, "<tr><td><label>Guest Permissions:</label></td>\n<td>");
AQH_ModService_WritePermsToForm(AQH_Module_GetGuestPerms(currentMod), permDefList, NULL, dbuf);
GBAA(dbuf, "</td></tr>");
}
GBAS(dbuf, "</table>\n");
GBAA(dbuf, "<input type=\"hidden\" name=\"module\" value=\"%s\">\n", sModName?sModName:"");
GBAS(dbuf, "<input type=\"submit\" value=\"Save\">\n</form>\n\n");
/* write role list */
GBAS(dbuf, "<h2>User Roles</h2>\n");
if (roleList)
_writeRoleListToForm(roleList, sModName, permDefList, dbuf);
else
GBAS(dbuf, "<p>none</p>");
GBAA(dbuf, "<a href=\"addrole.html?mod=%s\"><img src=\"/pics/plus.png\">Add Role</a>\n", sModName?sModName:"");
}
void _writeRoleListToForm(const AQH_ROLE_LIST *roleList,
const char *sModName,
const AQH_PERMDEF_LIST *permDefList,
GWEN_BUFFER *dbuf)
{
const AQH_ROLE *role;
GBAS(dbuf,
"<table class=\"datatable\">\n"
"<thead><tr><th>Id</th><th>Name</th><th>Permissions</th><th>Description</th><th>Actions</th></tr>\n</thead>\n"
"<tbody>\n");
role=AQH_Role_List_First(roleList);
while(role) {
uint8_t id;
const char *s;
GBAS(dbuf, "<tr>");
/* id */
id=AQH_Role_GetId(role);
GBAA(dbuf, "<td>%d</td>", id);
/* name */
s=AQH_Role_GetName(role);
GBAA(dbuf, "<td>%s</td>", s?s:"");
/* permissions */
GBAS(dbuf, "<td>");
if (permDefList)
_writeEnabledPermissions(permDefList, AQH_Role_GetPerms(role), dbuf);
GBAS(dbuf, "</td>");
/* description */
s=AQH_Role_GetDescr(role);
GBAA(dbuf, "<td>%s</td>", s?s:"");
/* actions */
GBAA(dbuf, "<td>");
GBAA(dbuf, "<a href=\"editrole.html?mod=%s&id=%d\"><img src=\"/pics/edit.png\"></a>", sModName?sModName:"", id);
GBAA(dbuf, "<a href=\"delrole.html?mod=%s&id=%d\"><img src=\"/pics/minus.png\"></a>", sModName?sModName:"", id);
GBAA(dbuf, "</td>");
GBAS(dbuf, "</tr>\n");
role=AQH_Role_List_Next(role);
}
GBAS(dbuf, "</tbody>\n</table>\n");
}
void _writeEnabledPermissions(const AQH_PERMDEF_LIST *permDefList, uint32_t perms, GWEN_BUFFER *dbuf)
{
if (permDefList) {
const AQH_PERMDEF *permDef;
permDef=AQH_PermDef_List_First(permDefList);
while(permDef) {
const char *s;
uint32_t mask;
s=AQH_PermDef_GetId(permDef);
mask=AQH_PermDef_GetMask(permDef);
if (perms & mask)
GBAA(dbuf, "%s ", s?s:"");
permDef=AQH_PermDef_List_Next(permDef);
}
}
}

View File

@@ -1,35 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MMODULES_H
#define AQHOME_CGI_MMODULES_H
#include <aqhome-cgi/modules/common/mservice.h>
#include <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
#define AQH_MODADMMODULES_PERMS_MODULESREAD 0x001
#define AQH_MODADMMODULES_PERMS_MODULESWRITE 0x002
#define AQH_MODADMMODULES_PERMS_MODULESADD 0x004
#define AQH_MODADMMODULES_PERMS_MODULESDEL 0x008
void AQH_ModAdmModules_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder);
int AQH_ModAdmModules_Create(AQH_SERVICE *sv);
#endif

View File

@@ -1,820 +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 <config.h>
#endif
#include "./mservice_p.h"
#include "aqhome-cgi/service/module.h"
#include <gwenhywfar/debug.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define AQH_MOD_SERVICE_HEADERFILE "header.html"
#define AQH_MOD_SERVICE_FOOTERFILE "footer.html"
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* global vars
* ------------------------------------------------------------------------------------------------
*/
GWEN_INHERIT(AQH_MODULE, AQH_MOD_SERVICE)
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
static void _calcUserModPerms(AQH_MODULE *m, const AQH_USER *user);
static uint32_t _calcRolePerms(const AQH_MODULE *m, const AQH_MODULE_PERMS *modPerms);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModService_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder)
{
AQH_MOD_SERVICE *xm;
GWEN_NEW_OBJECT(AQH_MOD_SERVICE, xm);
GWEN_INHERIT_SETDATA(AQH_MODULE, AQH_MOD_SERVICE, m, xm, _freeData);
xm->service=sv;
xm->baseFolder=(baseFolder && *baseFolder)?strdup(baseFolder):NULL;
}
void _freeData(GWEN_UNUSED void *bp, void *p)
{
AQH_MOD_SERVICE *xm;
xm=(AQH_MOD_SERVICE*) p;
free(xm->baseFolder);
GWEN_FREE_OBJECT(xm);
}
AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
return xm->service;
}
}
return NULL;
}
const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
return xm->baseFolder;
}
}
return NULL;
}
uint32_t AQH_ModService_GetUserPerms(const AQH_MODULE *m)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
return xm->userPerms;
}
}
return 0;
}
void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->handleRequestFn=fn;
}
}
}
void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->loadSubModuleFn=fn;
}
}
}
void AQH_ModService_SetAddHeaderFn(AQH_MODULE *m, AQH_MODSERVICE_ADDHEADER_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->addHeaderFn=fn;
}
}
}
void AQH_ModService_SetAddFooterFn(AQH_MODULE *m, AQH_MODSERVICE_ADDFOOTER_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->addFooterFn=fn;
}
}
}
void AQH_ModService_AddHeader(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf)
{
if (m && dbuf) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
if (xm->addHeaderFn)
xm->addHeaderFn(m, lang, dbuf);
else {
AQH_MODULE *mParent;
mParent=AQH_Module_Tree2_GetParent(m);
if (mParent)
AQH_ModService_AddHeader(mParent, lang, dbuf);
AQH_ModService_ReadStaticFile(m, lang, AQH_MOD_SERVICE_HEADERFILE, dbuf);
}
}
}
}
void AQH_ModService_AddFooter(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf)
{
if (m && dbuf) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
if (xm->addFooterFn)
xm->addFooterFn(m, lang, dbuf);
else {
AQH_MODULE *mParent;
AQH_ModService_ReadStaticFile(m, lang, AQH_MOD_SERVICE_FOOTERFILE, dbuf);
mParent=AQH_Module_Tree2_GetParent(m);
if (mParent)
AQH_ModService_AddFooter(mParent, lang, dbuf);
}
}
}
}
int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *lang, const char *sFilename, GWEN_BUFFER *dbuf)
{
int rv;
rv=AQH_ModService_ReadStaticFile(m, lang, sFilename, dbuf);
if (rv<0) {
AQCGI_Request_SetResponseCode(rq, 500);
AQCGI_Request_SetResponseText(rq, "Internal Error");
return GWEN_ERROR_INTERNAL;
}
AQCGI_Request_SetResponseCode(rq, 200);
AQCGI_Request_SetResponseText(rq, "Ok");
return 0;
}
int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm && xm->handleRequestFn)
return xm->handleRequestFn(m, rq, session, sLastPathElem);
}
return GWEN_ERROR_NOT_IMPLEMENTED;
}
AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm && xm->loadSubModuleFn) {
AQH_MODULE *mReturn;
mReturn=xm->loadSubModuleFn(m, rq, session, sModuleName);
if (mReturn)
AQH_ModService_CalcSessionModPerms(mReturn, session);
return mReturn;
}
}
return NULL;
}
int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *lang, const char *filename, GWEN_BUFFER *dbuf)
{
if (m && filename && dbuf) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
GWEN_BUFFER *fbuf;
int rv;
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(fbuf, xm->baseFolder);
GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S);
GWEN_Buffer_AppendString(fbuf, (lang && *lang)?lang:"en");
GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S);
GWEN_Buffer_AppendString(fbuf, filename);
DBG_ERROR(NULL, "Reading file \"%s\"", GWEN_Buffer_GetStart(fbuf));
rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fbuf), dbuf);
if (rv<0) {
DBG_ERROR(NULL, "Read(%s): %d", GWEN_Buffer_GetStart(fbuf), rv);
GWEN_Buffer_free(fbuf);
return rv;
}
GWEN_Buffer_free(fbuf);
return 0;
}
}
DBG_ERROR(NULL, "Any arg is missing (or is not a AQH_MOD_SERVICE object)");
return GWEN_ERROR_INTERNAL;
}
AQH_SESSION *AQH_ModService_ReadSession(AQH_MODULE *m, AQCGI_REQUEST *rq)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *db;
const char *s;
sv=AQH_ModService_GetService(m);
db=AQCGI_Request_GetDbRequestHeader(rq);
s=GWEN_DB_GetCharValue(db, "cookies/session", 0, NULL);
if (s && *s) {
AQH_SESSION *session;
session=AQH_Service_LoadSession(sv, s);
if (session==NULL) {
DBG_ERROR(NULL, "Session \"%s\" not found", s);
return NULL;
}
else {
const char *sUserName;
GWEN_BUFFER *tbuf;
sUserName=AQH_Session_GetUserAlias(session);
if (sUserName && *sUserName) {
AQH_USER *user;
user=AQH_Service_LoadUser(sv, sUserName);
if (user==NULL) {
DBG_ERROR(NULL, "User \"%s\" not found", sUserName);
AQH_Session_free(session);
return NULL;
}
else {
DBG_ERROR(NULL, "User is \"%s\"", sUserName);
}
AQH_Session_SetUser(session, user);
}
/* renew session cookie */
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(tbuf, "Set-Cookie: session=%s; max-age=86400", AQH_Session_GetUid(session));
AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(tbuf));
DBG_ERROR(NULL, "Renew session cookie");
GWEN_Buffer_free(tbuf);
return session;
}
}
else {
DBG_ERROR(NULL, "No session cookie");
}
return NULL;
}
void AQH_ModService_CalcSessionModPerms(AQH_MODULE *m, const AQH_SESSION *session)
{
const AQH_USER *user;
user=session?AQH_Session_GetUser(session):NULL;
_calcUserModPerms(m, user);
}
void _calcUserModPerms(AQH_MODULE *m, const AQH_USER *user)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
uint32_t perms=0;
if (user) {
if (AQH_User_GetFlags(user) & AQH_USER_FLAGS_ADMIN)
perms=0xffffffff;
else {
const char *sModName;
const AQH_MODULE_PERMS_LIST *modPermsList;
AQH_MODULE_PERMS *modPerms;
sModName=AQH_Module_GetName(m);
modPermsList=AQH_User_GetModulePermList(user);
modPerms=(sModName && modPermsList)?AQH_ModulePerms_List_GetByModuleId(modPermsList, sModName):NULL;
if (modPerms)
perms=_calcRolePerms(m, modPerms);
else
perms=AQH_Module_GetGuestPerms(m);
}
} /* if (user) */
else
perms=AQH_Module_GetGuestPerms(m);
xm->userPerms=perms;
}
} /* if (m) */
}
uint32_t _calcRolePerms(const AQH_MODULE *m, const AQH_MODULE_PERMS *modPerms)
{
uint32_t perms=0;
const AQH_ROLE_LIST *roleList;
roleList=AQH_Module_GetRoleList(m);
if (roleList) {
int roleArraySize;
int i;
uint32_t explAddPerms=0;
uint32_t explDelPerms=0;
roleArraySize=AQH_ModulePerms_GetRoleArrayArraySize();
for (i=0; i<roleArraySize; i++) {
int roleId;
roleId=AQH_ModulePerms_GetRoleArrayAt(modPerms, i);
if (roleId) {
const AQH_ROLE *role;
role=AQH_Role_List_GetById(roleList, roleId);
if (role) {
perms|=AQH_Role_GetPerms(role);
explAddPerms|=AQH_Role_GetExplAddPerms(role);
explAddPerms|=AQH_Role_GetExplDelPerms(role);
}
}
} /* for */
/* collate permissions */
perms|=explAddPerms;
perms|=AQH_ModulePerms_GetExplAddPerms(modPerms);
perms&=~explDelPerms;
perms&=~AQH_ModulePerms_GetExplDelPerms(modPerms);
}
return perms;
}
void AQH_ModService_AddPermDef(AQH_PERMDEF_LIST *permDefList, const char *id, uint32_t mask, const char *descr)
{
AQH_PERMDEF *permDef;
permDef=AQH_PermDef_new();
AQH_PermDef_SetId(permDef, id);
AQH_PermDef_SetMask(permDef, mask);
AQH_PermDef_SetDescr(permDef, descr);
AQH_PermDef_List_Add(permDef, permDefList);
}
void AQH_ModService_AddRole(AQH_ROLE_LIST *roleList, int id, const char *name, uint32_t perms, const char *descr)
{
AQH_ROLE *role;
role=AQH_Role_new();
AQH_Role_SetId(role, id);
AQH_Role_SetName(role, name);
AQH_Role_SetPerms(role, perms);
AQH_Role_SetDescr(role, descr);
AQH_Role_List_Add(role, roleList);
}
void AQH_ModService_HandleRequestWithTable(AQH_MODULE *m,
AQCGI_REQUEST *rq,
AQH_SESSION *session,
const char *page,
const AQH_MODSERVICE_HANDLER_ENTRY *e)
{
uint32_t perms;
GWEN_BUFFER *dbuf;
int i;
perms=AQH_ModService_GetUserPerms(m);
DBG_ERROR(NULL, "Perms=%08x", perms);
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
AQH_ModService_AddHeader(m, "en", dbuf);
for (i=0; ; i++) {
if (e[i].page==NULL) {
AQCGI_Request_SetResponseCode(rq, 404);
AQCGI_Request_SetResponseText(rq, "Not Found");
break;
}
if ((AQCGI_Request_GetRequestMethod(rq)==e[i].httpMethod) &&
(strcasecmp(page, e[i].page)==0)) {
/* preset result */
AQCGI_Request_SetResponseCode(rq, 200);
AQCGI_Request_SetResponseText(rq, "Ok");
if ((perms & e[i].perms)==e[i].perms)
(e[i].handlerFn)(m, rq, session, dbuf);
else {
GWEN_Buffer_AppendString(dbuf, "<h1>Error</h1><p>No permissions for this request.</p>");
AQCGI_Request_SetResponseCode(rq, 403);
AQCGI_Request_SetResponseText(rq, "Forbidden");
}
break;
}
}
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);
if (AQCGI_Request_GetFlags(rq) & AQCGI_FLAGS_HAS_CONTENT_HEADER)
AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html");
}
void AQH_ModService_WritePermsToForm(uint32_t perms, const AQH_PERMDEF_LIST *permDefList, const char *sPrefix, GWEN_BUFFER *dbuf)
{
if (permDefList) {
const AQH_PERMDEF *permDef;
GWEN_BUFFER *tbuf;
uint32_t pos;
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
if (sPrefix && *sPrefix)
GBAA(tbuf, "%s:", sPrefix);
pos=GWEN_Buffer_GetPos(tbuf);
permDef=AQH_PermDef_List_First(permDefList);
while(permDef) {
const char *s;
s=AQH_PermDef_GetId(permDef);
if (s && *s) {
uint32_t mask;
GBAS(tbuf, s);
mask=AQH_PermDef_GetMask(permDef);
if (perms & mask)
GBAA(dbuf, "<input type=\"checkbox\" name=\"%s\" checked>", GWEN_Buffer_GetStart(tbuf));
else
GBAA(dbuf, "<input type=\"checkbox\" name=\"%s\">", s?s:"");
GBAA(dbuf, "<label for=\"%s\">%s</label>", GWEN_Buffer_GetStart(tbuf), s?s:"");
GWEN_Buffer_Crop(tbuf, 0, pos);
}
permDef=AQH_PermDef_List_Next(permDef);
}
GWEN_Buffer_free(tbuf);
}
}
uint32_t AQH_ModService_ReadPermsFromForm(GWEN_DB_NODE *dbPost, const AQH_PERMDEF_LIST *permDefList, const char *sPrefix)
{
uint32_t result=0;
if (permDefList) {
const AQH_PERMDEF *permDef;
GWEN_BUFFER *tbuf;
uint32_t pos;
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
if (sPrefix && *sPrefix)
GBAA(tbuf, "%s:", sPrefix);
pos=GWEN_Buffer_GetPos(tbuf);
permDef=AQH_PermDef_List_First(permDefList);
while(permDef) {
const char *id;
id=AQH_PermDef_GetId(permDef);
if (id && *id) {
uint32_t mask;
const char *s;
GBAS(tbuf, id);
mask=AQH_PermDef_GetMask(permDef);
s=GWEN_DB_GetCharValue(dbPost, GWEN_Buffer_GetStart(tbuf), 0, NULL);
if (s && *s)
result|=mask;
GWEN_Buffer_Crop(tbuf, 0, pos);
}
permDef=AQH_PermDef_List_Next(permDef);
}
GWEN_Buffer_free(tbuf);
}
return result;
}
AQH_MODULE_LIST *AQH_ModService_LoadRawModules(AQH_MODULE *m)
{
AQH_SERVICE *sv;
GWEN_STRINGLIST *slModuleNames;
sv=AQH_ModService_GetService(m);
slModuleNames=AQH_Service_ListModules(sv);
if (slModuleNames) {
AQH_MODULE_LIST *modList;
GWEN_STRINGLISTENTRY *se;
modList=AQH_Module_List_new();
se=GWEN_StringList_FirstEntry(slModuleNames);
while(se) {
const char *sModName;
sModName=GWEN_StringListEntry_Data(se);
if (sModName && *sModName) {
AQH_MODULE *currentMod;
currentMod=AQH_Service_LoadModule(sv, sModName);
if (currentMod)
AQH_Module_List_Add(currentMod, modList);
}
se=GWEN_StringListEntry_Next(se);
}
GWEN_StringList_free(slModuleNames);
if (AQH_Module_List_GetCount(modList))
return modList;
AQH_Module_List_free(modList);
}
return NULL;
}
AQH_USER_LIST *AQH_ModService_LoadRawUsers(AQH_MODULE *m)
{
AQH_SERVICE *sv;
GWEN_STRINGLIST *slUserNames;
sv=AQH_ModService_GetService(m);
slUserNames=AQH_Service_ListUsers(sv);
if (slUserNames) {
AQH_USER_LIST *userList;
GWEN_STRINGLISTENTRY *se;
userList=AQH_User_List_new();
se=GWEN_StringList_FirstEntry(slUserNames);
while(se) {
const char *sModName;
sModName=GWEN_StringListEntry_Data(se);
if (sModName && *sModName) {
AQH_USER *u;
u=AQH_Service_LoadUser(sv, sModName);
if (u)
AQH_User_List_Add(u, userList);
}
se=GWEN_StringListEntry_Next(se);
}
GWEN_StringList_free(slUserNames);
if (AQH_User_List_GetCount(userList))
return userList;
AQH_User_List_free(userList);
}
return NULL;
}
void AQH_ModService_EscapeToBuffer(const char *src, GWEN_BUFFER *buf)
{
while (*src) {
unsigned char x;
x=(unsigned char)*src;
if (!(
(x>='A' && x<='Z') ||
(x>='a' && x<='z') ||
(x>='0' && x<='9') ||
NULL!=strchr("-_", x)
)) {
unsigned char c;
GWEN_Buffer_AppendByte(buf, '%');
c=(((unsigned char)(*src))>>4)&0xf;
if (c>9)
c+=7;
c+='0';
GWEN_Buffer_AppendByte(buf, c);
c=((unsigned char)(*src))&0xf;
if (c>9)
c+=7;
c+='0';
GWEN_Buffer_AppendByte(buf, c);
}
else
GWEN_Buffer_AppendByte(buf, *src);
src++;
} /* while */
}
void AQH_ModService_UnescapeToBuffer(const char *src, GWEN_BUFFER *buf)
{
while (*src) {
int charHandled=0;
if (*src=='%') {
if (strlen(src)>2) {
unsigned char d1, d2;
unsigned char c;
if (isxdigit((int)src[1]) && isxdigit((int)src[2])) {
/* skip '%' */
src++;
/* read first digit */
d1=(unsigned char)(toupper(*src));
/* get second digit */
src++;
d2=(unsigned char)(toupper(*src));
/* compute character */
d1-='0';
if (d1>9)
d1-=7;
c=(d1<<4)&0xf0;
d2-='0';
if (d2>9)
d2-=7;
c+=(d2&0xf);
/* store character */
GWEN_Buffer_AppendByte(buf, (char)c);
charHandled=1;
}
}
}
if (!charHandled)
GWEN_Buffer_AppendByte(buf, *src);
src++;
} /* while */
}
int AQH_ModService_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_DEBUG(NULL, "File %s is current", sPath);
return 1;
}
return 0;
}
int AQH_ModService_RespondWithMimeFile(AQCGI_REQUEST *rq, const char *sFilename, const char *sMimeType, GWEN_BUFFER *dbuf)
{
GWEN_BUFFER *ibuf;
int rv;
ibuf=GWEN_Buffer_new(0, 1024, 0, 1);
/* read file */
rv=GWEN_SyncIo_Helper_ReadFile(sFilename, ibuf);
if (rv<0) {
DBG_ERROR(NULL, "Error reading \"%s\" (%d)", sFilename, rv);
return rv;
}
else {
GWEN_Buffer_Reset(dbuf);
GWEN_Buffer_AppendBytes(dbuf, GWEN_Buffer_GetStart(ibuf), GWEN_Buffer_GetUsedBytes(ibuf));
if (sMimeType && *sMimeType) {
GWEN_BUFFER *tbuf;
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GBAA(tbuf, "Content-type: %s", sMimeType);
AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
}
AQCGI_Request_AddFlags(rq, AQH_MODSERVICE_RQFLAGS_RAWFILE);
}
GWEN_Buffer_free(ibuf);
return 0;
}

View File

@@ -1,91 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MSERVICE_H
#define AQHOME_CGI_MSERVICE_H
#include <aqhome-cgi/service/module.h>
#include <aqhome-cgi/service/service.h>
#include <aqhome-cgi/service/session.h>
#include <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
#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);
typedef void (*AQH_MODSERVICE_ADDFOOTER_FN)(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf);
typedef struct AQH_MODSERVICE_HANDLER_ENTRY AQH_MODSERVICE_HANDLER_ENTRY;
struct AQH_MODSERVICE_HANDLER_ENTRY {
const char *page;
int httpMethod;
uint32_t perms;
void (*handlerFn)(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
};
void AQH_ModService_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder);
AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m);
const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m);
uint32_t AQH_ModService_GetUserPerms(const AQH_MODULE *m);
void AQH_ModService_AddHeader(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf);
void AQH_ModService_AddFooter(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf);
AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName);
int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem);
AQH_SESSION *AQH_ModService_ReadSession(AQH_MODULE *m, AQCGI_REQUEST *rq);
void AQH_ModService_CalcSessionModPerms(AQH_MODULE *m, const AQH_SESSION *session);
void AQH_ModService_HandleRequestWithTable(AQH_MODULE *m,
AQCGI_REQUEST *rq,
AQH_SESSION *session,
const char *page,
const AQH_MODSERVICE_HANDLER_ENTRY *e);
int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *lang, const char *sFilename, GWEN_BUFFER *dbuf);
int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *lang, const char *filename, GWEN_BUFFER *dbuf);
void AQH_ModService_AddPermDef(AQH_PERMDEF_LIST *permDefList, const char *id, uint32_t mask, const char *descr);
void AQH_ModService_AddRole(AQH_ROLE_LIST *roleList, int id, const char *name, uint32_t perms, const char *descr);
void AQH_ModService_WritePermsToForm(uint32_t perms, const AQH_PERMDEF_LIST *permDefList, const char *sPrefix, GWEN_BUFFER *dbuf);
uint32_t AQH_ModService_ReadPermsFromForm(GWEN_DB_NODE *dbPost, const AQH_PERMDEF_LIST *permDefList, const char *sPrefix);
AQH_MODULE_LIST *AQH_ModService_LoadRawModules(AQH_MODULE *m);
AQH_USER_LIST *AQH_ModService_LoadRawUsers(AQH_MODULE *m);
void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn);
void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn);
void AQH_ModService_SetAddHeaderFn(AQH_MODULE *m, AQH_MODSERVICE_ADDHEADER_FN fn);
void AQH_ModService_SetAddFooterFn(AQH_MODULE *m, AQH_MODSERVICE_ADDFOOTER_FN fn);
void AQH_ModService_EscapeToBuffer(const char *src, GWEN_BUFFER *buf);
void AQH_ModService_UnescapeToBuffer(const char *src, GWEN_BUFFER *buf);
int AQH_ModService_FileIsCurrent(const char *sPath, int seconds);
int AQH_ModService_RespondWithMimeFile(AQCGI_REQUEST *rq, const char *sFilename, const char *sMimeType, GWEN_BUFFER *dbuf);
#endif

View File

@@ -1,30 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MSERVICE_P_H
#define AQHOME_CGI_MSERVICE_P_H
#include "aqhome-cgi/modules/common/mservice.h"
typedef struct AQH_MOD_SERVICE AQH_MOD_SERVICE;
struct AQH_MOD_SERVICE {
AQH_SERVICE *service;
char *baseFolder;
uint32_t userPerms;
AQH_MODSERVICE_HANDLEREQUEST_FN handleRequestFn;
AQH_MODSERVICE_LOADSUBMODULE_FN loadSubModuleFn;
AQH_MODSERVICE_ADDHEADER_FN addHeaderFn;
AQH_MODSERVICE_ADDFOOTER_FN addFooterFn;
};
#endif

View File

@@ -1,640 +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 <config.h>
#endif
#include "./musers.h"
#include "aqhome-cgi/service/module.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _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 _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqEditUserGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqEditUserPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqAddUserGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqAddUserPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static int _getHighestUserId(const AQH_USER_LIST *userList);
static int _modulePermsHasRole(const AQH_MODULE_PERMS *modPerms, uint8_t rid);
static void _writeEditUserForm(AQH_MODULE *m,
const AQH_USER *u,
const char *sAlias,
const char *sUrl,
const char *sSubmitText,
GWEN_BUFFER *dbuf);
static void _writeUserModRolesToForm(const AQH_ROLE_LIST *roles, const AQH_MODULE_PERMS *perms, const char *sModName, GWEN_BUFFER *dbuf);
static void _readAllModRolesForUserFromForm(AQH_MODULE *m, GWEN_DB_NODE *dbPost, AQH_USER *u);
static void _readModRolesFromForm(GWEN_DB_NODE *dbPost,
const AQH_ROLE_LIST *roleList,
const char *sPrefix,
AQH_MODULE_PERMS *modPerms);
static void _addLabelAndInputToFormTableH(const char *title, const char *name, const char *value, const char *xxtra, GWEN_BUFFER *dbuf);
static void _addUserStateLabelAndSelectionToFormTableH(const char *sTitle, const char *sName, int st, GWEN_BUFFER *dbuf);
static void _setLocationHeaderForMod(AQCGI_REQUEST *rq, const char *page, const char *sModName);
/* ------------------------------------------------------------------------------------------------
* vars
* ------------------------------------------------------------------------------------------------
*/
static AQH_MODSERVICE_HANDLER_ENTRY _requestTable[]={
{"index.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMUSERS_PERMS_USERSREAD, _handleRqIndex},
{"edituser.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMUSERS_PERMS_USERSWRITE, _handleRqEditUserGet},
{"edituser.html", AQCGI_REQUEST_METHOD_POST, AQH_MODADMUSERS_PERMS_USERSWRITE, _handleRqEditUserPost},
{"adduser.html", AQCGI_REQUEST_METHOD_GET, AQH_MODADMUSERS_PERMS_USERSWRITE, _handleRqAddUserGet},
{"adduser.html", AQCGI_REQUEST_METHOD_POST, AQH_MODADMUSERS_PERMS_USERSWRITE, _handleRqAddUserPost},
{NULL, 0, 0, NULL}
};
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModAdmUsers_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_ModAdmUsers_Create(AQH_SERVICE *sv)
{
AQH_MODULE *m;
int rv;
m=AQH_Module_new();
AQH_Module_SetName(m, "users");
AQH_Module_SetDescr(m, "user administration 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, "UserRead", 0x001, "Read users");
AQH_ModService_AddPermDef(permDefList, "UserWrite", 0x002, "Modify users");
AQH_ModService_AddPermDef(permDefList, "UserAdd", 0x004, "Add users");
AQH_ModService_AddPermDef(permDefList, "UserDel", 0x008, "Remove users");
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++, "admin",
AQH_MODADMUSERS_PERMS_USERSREAD |
AQH_MODADMUSERS_PERMS_USERSWRITE |
AQH_MODADMUSERS_PERMS_USERSADD |
AQH_MODADMUSERS_PERMS_USERSDEL,
"Administrator Role");
AQH_Module_SetRoleList(m, roleList);
}
AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName)
{
/* no sub-modules */
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 _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_USER_LIST *userList;
uint32_t perms;
perms=AQH_ModService_GetUserPerms(m);
userList=AQH_ModService_LoadRawUsers(m);
GBAS(dbuf, "<h1>Users</h1>\n");
GBAS(dbuf,
"<table class=\"datatable\">\n"
"<thead>"
"<tr><th>Id</th><th>Alias</th><th>Name</th><th>Status</th><th>Email</th><th>Notes</th><th>Actions</th></tr>\n"
"</thead>\n"
"<tbody>\n");
if (userList) {
const AQH_USER *u;
AQH_User_List_SortByAlias(userList, 1);
u=AQH_User_List_First(userList);
while(u) {
const char *sUserAlias;
sUserAlias=AQH_User_GetAlias(u);
if (sUserAlias && *sUserAlias) {
uint32_t id;
const char *s;
const char *sAlias;
id=AQH_User_GetId(u);
sAlias=AQH_User_GetAlias(u);
GBAS(dbuf, "<tr>");
GBAA(dbuf, "<td>%lu</td>", (unsigned long int) id);
GBAA(dbuf, "<td>%s</td>", sAlias?sAlias:"");
s=AQH_User_GetName(u);
GBAA(dbuf, "<td>%s</td>", s?s:"");
s=AQH_UserState_toString(AQH_User_GetState(u));
GBAA(dbuf, "<td>%s</td>", s?s:"");
s=AQH_User_GetEmail(u);
GBAA(dbuf, "<td>%s</td>", s?s:"");
s=AQH_User_GetNotes(u);
GBAA(dbuf, "<td>%s</td>", s?s:"");
GBAS(dbuf, "<td>");
if (perms & AQH_MODADMUSERS_PERMS_USERSWRITE) {
DBG_ERROR(NULL, "User=%s", sAlias?sAlias:"");
GBAS(dbuf, "<a href=\"edituser.html?alias=");
GWEN_Text_EscapeToBufferTolerant(sAlias?sAlias:"", dbuf);
GBAS(dbuf, "\"><img src=\"/pics/edit.png\"></a>");
}
GBAA(dbuf, "</td>\n");
GBAA(dbuf, "</tr>\n");
}
u=AQH_User_List_Next(u);
}
GBAS(dbuf,
"</tbody>\n"
"</table>\n");
AQH_User_List_free(userList);
}
if (perms & AQH_MODADMUSERS_PERMS_USERSADD)
GBAS(dbuf, "<hr><a href=\"adduser.html\">Add User</a>");
}
void _handleRqEditUserGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbQuery;
const char *sAlias;
AQH_USER *user;
sv=AQH_ModService_GetService(m);
dbQuery=AQCGI_Request_GetDbQuery(rq);
sAlias=dbQuery?GWEN_DB_GetCharValue(dbQuery, "alias", 0, NULL):NULL;
user=(sAlias && *sAlias)?AQH_Service_LoadUser(sv, sAlias):NULL;
if (user) {
_writeEditUserForm(m, user, sAlias, "edituser.html", "Save", dbuf);
AQH_User_free(user);
}
else {
AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html");
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See other");
}
}
void _handleRqEditUserPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbPost;
const char *sAlias;
AQH_USER *u;
sv=AQH_ModService_GetService(m);
dbPost=AQCGI_Request_GetDbPostBody(rq);
sAlias=dbPost?GWEN_DB_GetCharValue(dbPost, "alias", 0, NULL):NULL;
u=(sAlias && *sAlias)?AQH_Service_LoadUser(sv, sAlias):NULL;
if (u) {
const char *s;
int state;
int rv;
s=GWEN_DB_GetCharValue(dbPost, "name", 0, NULL);
AQH_User_SetName(u, s);
s=GWEN_DB_GetCharValue(dbPost, "email", 0, NULL);
AQH_User_SetEmail(u, s);
s=GWEN_DB_GetCharValue(dbPost, "notes", 0, NULL);
AQH_User_SetNotes(u, s);
s=GWEN_DB_GetCharValue(dbPost, "status", 0, NULL);
state=(s && *s)?AQH_UserState_fromString(s):AQH_UserState_Unknown;
if (state!=AQH_UserState_Unknown)
AQH_User_SetState(u, state);
_readAllModRolesForUserFromForm(m, dbPost, u);
rv=AQH_Service_SaveUser(sv, u);
if (rv<0) {
GBAS(dbuf, "<h2>Error</h2><p>Error saving user</p>");
DBG_ERROR(NULL, "Could not save user \"%s\"", sAlias);
AQH_User_free(u);
return;
}
DBG_ERROR(NULL, "User \"%s\" saved", sAlias);
AQH_User_free(u);
AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html");
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See other");
}
else {
DBG_ERROR(NULL, "Could not load user \"%s\"", sAlias?sAlias:"<no name>");
GBAS(dbuf, "<p>Error loading user.</p>\n");
}
}
void _handleRqAddUserGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
DBG_ERROR(NULL, "AddUser");
_writeEditUserForm(m, NULL, NULL, "adduser.html", "Add", dbuf);
}
void _handleRqAddUserPost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *dbPost;
const char *sAlias;
sv=AQH_ModService_GetService(m);
dbPost=AQCGI_Request_GetDbPostBody(rq);
sAlias=dbPost?GWEN_DB_GetCharValue(dbPost, "alias", 0, NULL):NULL;
// TODO: check alias validity
if (sAlias) {
AQH_USER *u;
const char *s;
int state;
int rv;
uint32_t userId;
AQH_USER_LIST *userList;
u=AQH_User_new();
userList=AQH_ModService_LoadRawUsers(m);
userId=_getHighestUserId(userList)+1;
AQH_User_SetId(u, userId);
AQH_User_SetAlias(u, sAlias);
s=GWEN_DB_GetCharValue(dbPost, "name", 0, NULL);
AQH_User_SetName(u, s);
s=GWEN_DB_GetCharValue(dbPost, "email", 0, NULL);
AQH_User_SetEmail(u, s);
s=GWEN_DB_GetCharValue(dbPost, "notes", 0, NULL);
AQH_User_SetNotes(u, s);
s=GWEN_DB_GetCharValue(dbPost, "status", 0, NULL);
state=(s && *s)?AQH_UserState_fromString(s):AQH_UserState_Unknown;
if (state!=AQH_UserState_Unknown)
AQH_User_SetState(u, state);
rv=AQH_Service_AddUser(sv, u);
if (rv<0) {
GBAS(dbuf, "<h2>Error</h2><p>Error saving user</p>");
DBG_ERROR(NULL, "Could not save user \"%s\" (%d)", sAlias, rv);
AQH_User_free(u);
AQH_User_List_free(userList);
return;
}
DBG_ERROR(NULL, "User \"%s\" saved", sAlias);
AQH_User_free(u);
AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html");
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See other");
AQH_User_List_free(userList);
}
else {
DBG_ERROR(NULL, "Missing alias");
GBAS(dbuf, "<p>Missing alias.</p>\n");
}
}
int _getHighestUserId(const AQH_USER_LIST *userList)
{
int id=0;
if (userList) {
const AQH_USER *user;
user=AQH_User_List_First(userList);
while(user) {
int uid;
uid=AQH_User_GetId(user);
id=(uid>id)?uid:id;
user=AQH_User_List_Next(user);
}
}
return id;
}
int _modulePermsHasRole(const AQH_MODULE_PERMS *modPerms, uint8_t rid)
{
if (modPerms) {
int arraySize;
int i;
arraySize=AQH_ModulePerms_GetRoleArrayArraySize();
for(i=0; i<arraySize; i++) {
if (AQH_ModulePerms_GetRoleArrayAt(modPerms, i)==rid)
return 1;
}
}
return 0;
}
void _writeEditUserForm(AQH_MODULE *m,
const AQH_USER *u,
const char *sAlias,
const char *sUrl,
const char *sSubmitText,
GWEN_BUFFER *dbuf)
{
AQH_MODULE_LIST *moduleList;
/* write user info */
GBAS(dbuf, "<h2>User Info</h2>\n");
GBAA(dbuf,
"<form action=\"%s\" method=\"post\">\n"
"<table class=\"formtable\">\n",
sUrl?sUrl:"");
_addLabelAndInputToFormTableH("Alias", "alias", sAlias, "required", dbuf);
_addLabelAndInputToFormTableH("Name", "name", u?AQH_User_GetName(u):NULL, NULL, dbuf);
_addLabelAndInputToFormTableH("Email", "email", u?AQH_User_GetEmail(u):NULL, NULL, dbuf);
_addLabelAndInputToFormTableH("Notes", "notes", u?AQH_User_GetNotes(u):NULL, NULL, dbuf);
_addUserStateLabelAndSelectionToFormTableH("Status", "status", u?AQH_User_GetState(u):AQH_UserState_Unknown, dbuf);
GBAS(dbuf, "</table>\n");
/* module permissions */
GBAS(dbuf, "<h2>Module Roles</h2>\n");
GBAS(dbuf,
"<table class=\"datatable\">\n"
"<thead>"
"<tr><th>Module</th><th>Roles</th></tr>\n"
"</thead>\n"
"<tbody>\n");
moduleList=AQH_ModService_LoadRawModules(m);
if (moduleList) {
const AQH_MODULE_PERMS_LIST *modPermsList;
const AQH_MODULE *currentMod;
modPermsList=u?AQH_User_GetModulePermList(u):NULL;
currentMod=AQH_Module_List_First(moduleList);
while(currentMod) {
const char *sModName;
const AQH_MODULE_PERMS *modPerms;
sModName=AQH_Module_GetName(currentMod);
GBAA(dbuf, "<tr><td>%s</td><td>", sModName);
modPerms=modPermsList?AQH_ModulePerms_List_GetByModuleId(modPermsList, sModName):NULL;
_writeUserModRolesToForm(AQH_Module_GetRoleList(currentMod), modPerms, sModName, dbuf);
GBAS(dbuf, "</td></tr>\n");
GBAS(dbuf, "<td>");
currentMod=AQH_Module_List_Next(currentMod);
} /* while */
AQH_Module_List_free(moduleList);
}
GBAS(dbuf,
"</tbody>\n"
"</table>\n");
GBAA(dbuf, "<input type=\"hidden\" name=\"alias\" value=\"%s\">\n", sAlias?sAlias:"");
GBAA(dbuf, "<input type=\"submit\" value=\"%s\">\n</form>\n\n", sSubmitText?sSubmitText:"Save");
}
void _readAllModRolesForUserFromForm(AQH_MODULE *m, GWEN_DB_NODE *dbPost, AQH_USER *u)
{
AQH_MODULE_LIST *moduleList;
moduleList=AQH_ModService_LoadRawModules(m);
if (moduleList) {
AQH_MODULE_PERMS_LIST *permsList;
const AQH_MODULE *module;
permsList=AQH_User_GetModulePermList(u);
if (permsList==NULL) {
DBG_ERROR(NULL, "Creating module perms list for user");
permsList=AQH_ModulePerms_List_new();
AQH_User_SetModulePermList(u, permsList);
}
module=AQH_Module_List_First(moduleList);
while(module) {
const char *sModName;
const AQH_ROLE_LIST *roleList;
sModName=AQH_Module_GetName(module);
roleList=AQH_Module_GetRoleList(module);
if (sModName && *sModName && roleList) {
AQH_MODULE_PERMS *modPerms;
modPerms=AQH_ModulePerms_List_GetByModuleId(permsList, sModName);
if (modPerms==NULL) {
modPerms=AQH_ModulePerms_new();
AQH_ModulePerms_SetModuleId(modPerms, sModName);
AQH_ModulePerms_List_Add(modPerms, permsList);
}
_readModRolesFromForm(dbPost, roleList, sModName, modPerms);
}
module=AQH_Module_List_Next(module);
}
AQH_Module_List_free(moduleList);
}
}
void _writeUserModRolesToForm(const AQH_ROLE_LIST *roleList, const AQH_MODULE_PERMS *modPerms, const char *sModName, GWEN_BUFFER *dbuf)
{
if (roleList) {
const AQH_ROLE *role;
role=AQH_Role_List_First(roleList);
while(role) {
const char *sRoleName;
uint8_t roleId;
roleId=AQH_Role_GetId(role);
sRoleName=AQH_Role_GetName(role);
if (sRoleName && *sRoleName) {
int isChecked;
isChecked=(modPerms && _modulePermsHasRole(modPerms, roleId));
if (sModName && *sModName) {
GBAA(dbuf, "<input type=\"checkbox\" name=\"%s:%s\" %s>", sModName, sRoleName, isChecked?"checked":"");
GBAA(dbuf, "<label for=\"%s:%s\">%s</label>", sModName, sRoleName, sRoleName);
}
else {
GBAA(dbuf, "<input type=\"checkbox\" name=\"%s\" %s>", sRoleName, isChecked?"checked":"");
GBAA(dbuf, "<label for=\"%s\">%s</label>", sRoleName, sRoleName);
}
}
role=AQH_Role_List_Next(role);
}
}
}
void _readModRolesFromForm(GWEN_DB_NODE *dbPost,
const AQH_ROLE_LIST *roleList,
const char *sPrefix,
AQH_MODULE_PERMS *modPerms)
{
AQH_ModulePerms_PresetRoleArray(modPerms, 0);
if (roleList) {
GWEN_BUFFER *tbuf;
uint32_t pos;
const AQH_ROLE *role;
int nextRolePos=0;
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
if (sPrefix && *sPrefix)
GBAA(tbuf, "%s:", sPrefix);
pos=GWEN_Buffer_GetPos(tbuf);
role=AQH_Role_List_First(roleList);
while(role) {
const char *roleName;
roleName=AQH_Role_GetName(role);
if (roleName && *roleName) {
const char *s;
GBAS(tbuf, roleName);
s=GWEN_DB_GetCharValue(dbPost, GWEN_Buffer_GetStart(tbuf), 0, NULL);
if (s && *s) {
if (nextRolePos<AQH_ModulePerms_GetRoleArrayArraySize())
AQH_ModulePerms_SetRoleArrayAt(modPerms, nextRolePos++, AQH_Role_GetId(role));
}
GWEN_Buffer_Crop(tbuf, 0, pos);
}
role=AQH_Role_List_Next(role);
} /* while */
GWEN_Buffer_free(tbuf);
}
}
void _addUserStateLabelAndSelectionToFormTableH(const char *sTitle, const char *sName, int st, GWEN_BUFFER *dbuf)
{
int i;
GBAA(dbuf, "<tr><td><label for=\"%s\">%s:</label></td>", sName?sName:"", sTitle?sTitle:"");
GBAA(dbuf, "<td><select name=\"%s\">", sName?sName:"");
for(i=AQH_UserState_Unknown; i<=AQH_UserState_Active; i++) {
const char *s;
s=AQH_UserState_toString(i);
GBAA(dbuf, "<option value=\"%s\" %s>%s</option>", s, (i==st)?"selected":"", s);
}
GBAS(dbuf, "</select></td></tr>");
}
void _addLabelAndInputToFormTableH(const char *sTitle, const char *sName, const char *sValue, const char *sExtra, GWEN_BUFFER *dbuf)
{
GBAS(dbuf, "<tr>");
GBAA(dbuf, "<td><label for=\"%s:\">%s</label></td>", sName?sName:"", sTitle?sTitle:"");
GBAA(dbuf, "<td><input type=\"text\" name=\"%s\"", sName?sName:"");
if (sValue && *sValue)
GBAA(dbuf, " value=\"%s\"", sValue);
if (sExtra && *sExtra)
GBAA(dbuf, " %s", sExtra);
GBAS(dbuf, "></td>");
GBAS(dbuf, "</tr>\n");
}

View File

@@ -1,35 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MUSERS_H
#define AQHOME_CGI_MUSERS_H
#include <aqhome-cgi/modules/common/mservice.h>
#include <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
#define AQH_MODADMUSERS_PERMS_USERSREAD 0x001
#define AQH_MODADMUSERS_PERMS_USERSWRITE 0x002
#define AQH_MODADMUSERS_PERMS_USERSADD 0x004
#define AQH_MODADMUSERS_PERMS_USERSDEL 0x008
void AQH_ModAdmUsers_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder);
int AQH_ModAdmUsers_Create(AQH_SERVICE *sv);
#endif

View File

@@ -1,101 +0,0 @@
<?xml?>
<gwbuild>
<target type="ConvenienceLibrary" name="aqhcgi_mdevices" >
<includes type="c" >
$(gwenhywfar_cflags)
$(aqcgi_cflags)
$(aqdiagram_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
-I$(topsrcdir)/apps
-I$(topbuilddir)/apps
-I$(builddir)
-I$(srcdir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<define name="not_BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<setVar name="tm2flags-INACTIVE" >
--api=AQHOME_API
</setVar>
<setVar name="local/typefiles" >
</setVar>
<setVar name="local/built_sources" >
</setVar>
<setVar name="local/built_headers_pub">
</setVar>
<setVar name="local/built_headers_priv" >
</setVar>
<headers dist="false" install="$(pkgincludedir)/service" >
$(local/built_headers_pub)
</headers>
<headers dist="true" install="$(pkgincludedir)/service" >
mdevices.h
mdevices_init.h
mdevices_index.h
mdevices_valuestable.h
mdevices_valuesgraph.h
mdevices_value.h
mdevices_setdata.h
mdevices_vgraph.h
mdevices_device.h
mdevices_setdevice.h
mdevices_page.h
</headers>
<headers dist="true" >
</headers>
<sources>
$(local/typefiles)
mdevices.c
mdevices_init.c
mdevices_index.c
mdevices_valuestable.c
mdevices_valuesgraph.c
mdevices_value.c
mdevices_setdata.c
mdevices_vgraph.c
mdevices_device.c
mdevices_setdevice.c
mdevices_page.c
</sources>
<extradist>
</extradist>
<useTargets>
</useTargets>
<subdirs>
</subdirs>
</target>
</gwbuild>

View File

@@ -1,565 +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 <config.h>
#endif
#include "./mdevices.h"
#include "aqhome-cgi/modules/devices/mdevices_index.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"
#include "aqhome-cgi/modules/devices/mdevices_device.h"
#include "aqhome-cgi/modules/devices/mdevices_setdevice.h"
#include "aqhome-cgi/modules/devices/mdevices_page.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
#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
/* ------------------------------------------------------------------------------------------------
* 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 _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);
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 _handleRqPageGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqPagePost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static void _handleRqPageGraphGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf);
static AQDG_GRAPH_DATAPAIR_LIST *_createDataPairListFromDataPoints(const uint64_t *dataPoints, uint64_t numValues);
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},
{"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},
{"setdata.html", AQCGI_REQUEST_METHOD_POST, P_VALUEWRITE, _handleRqSetDataPost},
{"graph.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqGraphGet},
{"page.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqPageGet},
{"page.html", AQCGI_REQUEST_METHOD_POST, P_VALUEWRITE, _handleRqPagePost},
{"pgraph.html", AQCGI_REQUEST_METHOD_GET, P_DEVICEREAD | P_VALUEREAD, _handleRqPageGraphGet},
{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 _handleRqValuesTableGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *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);
}
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);
}
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);
}
void _handleRqPageGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunPageGet, dbuf);
}
void _handleRqPagePost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunPagePost, dbuf);
}
void _handleRqPageGraphGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, GWEN_BUFFER *dbuf)
{
AQH_ModDataClient_HandleRequest(m, rq, session, AQH_ModDevices_RunPageGraph, 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;
}
uint32_t AQH_ModDevices_RgbwFromComponents(int r, int g, int b, int w)
{
uint32_t colorOut;
colorOut=((r & 0xff)<<16) | ((g & 0xff)<<24) | (b & 0xff) | ((w & 0xff)<<8);
return colorOut;
}
int AQH_ModDevices_RgbwGetR(uint32_t color)
{ /* GGRRWWBB */
return (color & 0x00ff0000)>>16;
}
int AQH_ModDevices_RgbwGetG(uint32_t color)
{ /* GGRRWWBB */
return (color & 0xff000000)>>24;
}
int AQH_ModDevices_RgbwGetB(uint32_t color)
{ /* GGRRWWBB */
return (color & 0x000000ff);
}
int AQH_ModDevices_RgbwGetW(uint32_t color)
{ /* GGRRWWBB */
return (color & 0x0000ff00)>>8;
}
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, "<input type=\"color\" name=\"%s\" value=\"refresh\"/>", sValueName);
break;
case AQH_ValueModality_OnOff:
GBAA(dbuf,
"<select name=\"%s\">"
"<option value=\"unchanged\">unchanged</option>"
"<option value=\"off\">off</option>"
"<option value=\"on\">on</option>"
"</select>",
sValueName);
break;
case AQH_ValueModality_OnOffAuto:
GBAA(dbuf,
"<select name=\"%s\">"
"<option value=\"unchanged\">unchanged</option>"
"<option value=\"off\">off</option>"
"<option value=\"on\">on</option>"
"<option value=\"auto\">auto</option>"
"</select>",
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, "<input type=\"text\" name=\"%s\" value=\"#%08x\"/>", sValueName, (uint32_t) (u.f));
#else
GBAA(dbuf, "<input type=\"color\" name=\"%s\" value=\"#%08x\"/>#%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, "<select name=\"%s\">" "<option value=\"unchanged\" >unchanged</option>", sValueName);
GBAA(dbuf, "<option value=\"off\" %s>off</option>", (intVal==0)?"selected":"");
GBAA(dbuf, "<option value=\"on\" %s>on</option>", (intVal==1)?"selected":"");
GBAS(dbuf, "</select>");
break;
case AQH_ValueModality_OnOffAuto:
GBAA(dbuf, "<select name=\"%s\">" "<option value=\"unchanged\" >unchanged</option>", sValueName);
GBAA(dbuf, "<option value=\"off\" %s>off</option>", (intVal==0)?"selected":"");
GBAA(dbuf, "<option value=\"on\" %s>on</option>", (intVal==1)?"selected":"");
GBAA(dbuf, "<option value=\"auto\" %s>auto</option>", (intVal==2)?"selected":"");
GBAS(dbuf, "</select>");
break;
default:
// GBAA(dbuf, "<input type=\"text\" name=\"%s\" value=\"%.2f\"/>", 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);
}
}
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;
}
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;
}
int AQH_ModDevices_ValueGetLastDataAsInt(AQH_DATACLIENT *dc, const AQH_VALUE *value, int defaultValue)
{
const char *sValueSystemName;
uint64_t dataPoints[2];
uint64_t recvdNum;
// uint64_t timestamp;
union {double f; uint64_t i;} u;
int intVal;
sValueSystemName=AQH_Value_GetNameForSystem(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 {
DBG_INFO(NULL, "No last value for \"%s\"", sValueSystemName);
intVal=defaultValue;
}
return intVal;
}
uint32_t AQH_ModDevices_ValueGetLastDataAsUint32(AQH_DATACLIENT *dc, const AQH_VALUE *value, uint32_t defaultValue)
{
const char *sValueSystemName;
uint64_t dataPoints[2];
uint64_t recvdNum;
// uint64_t timestamp;
union {double f; uint64_t i;} u;
uint32_t uintVal;
sValueSystemName=AQH_Value_GetNameForSystem(value);
recvdNum=AQH_DataClient_GetLastData(dc, sValueSystemName, &dataPoints[0], 1);
if (recvdNum>0) {
// timestamp=dataPoints[0];
u.i=dataPoints[1];
uintVal=(uint32_t) u.f;
DBG_ERROR(NULL, "Transformed value %.2f -> %08x", u.f, uintVal);
}
else {
DBG_INFO(NULL, "No last value for \"%s\"", sValueSystemName);
uintVal=defaultValue;
}
return uintVal;
}
AQDG_GRAPH_DATAPAIR_LIST *AQH_ModDevices_RequestDataPairList(AQH_DATACLIENT *dc, const char *systemValueName,
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, systemValueName, 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 for %s", systemValueName);
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_DEBUG(NULL, "Got %d datapoints", (int) numValues);
dpList=AQDG_Graph_DataPair_List_new();
for(i=0; i<numValues; i++) {
AQDG_GRAPH_DATAPAIR *dp;
double timestamp;
union {double f; uint64_t i;} u;
timestamp=(double)(*(dataPoints++));
u.i=*(dataPoints++);
dp=AQDG_Graph_DataPair_new();
AQDG_Graph_DataPair_SetValueX(dp, timestamp);
AQDG_Graph_DataPair_SetValueY(dp, u.f);
AQDG_Graph_DataPair_List_Add(dp, dpList);
}
AQDG_Graph_DataPair_List_SortByValueX(dpList, 1);
return dpList;
}

View File

@@ -1,71 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MODULES_DEVICES_H
#define AQHOME_CGI_MODULES_DEVICES_H
#include "aqhome-cgi/modules/mdataclient.h"
#include "aqhome/aqhome.h"
#include "aqhome/dataclient/client.h"
#include <aqcgi/request.h>
#include <aqdiagram/graph/datapair.h>
#include <gwenhywfar/buffer.h>
#define AQH_MODDEVICES_PERMS_DEVICEREAD 0x001
#define AQH_MODDEVICES_PERMS_DEVICEWRITE 0x002
#define AQH_MODDEVICES_PERMS_DEVICEADD 0x004
#define AQH_MODDEVICES_PERMS_DEVICEDEL 0x008
#define AQH_MODDEVICES_PERMS_VALUEREAD 0x010
#define AQH_MODDEVICES_PERMS_VALUEWRITE 0x020
#define AQH_MODDEVICES_PERMS_VALUEADD 0x040
#define AQH_MODDEVICES_PERMS_VALUEDEL 0x080
#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);
uint32_t AQH_ModDevices_ColorFromHexString(const char *s);
uint32_t AQH_ModDevices_HtmlColorToValueRGBW(uint32_t colorIn);
uint32_t AQH_ModDevices_RgbwToHtmlColor(uint32_t colorIn);
uint32_t AQH_ModDevices_RgbwFromComponents(int r, int g, int b, int w);
int AQH_ModDevices_RgbwGetR(uint32_t color);
int AQH_ModDevices_RgbwGetG(uint32_t color);
int AQH_ModDevices_RgbwGetB(uint32_t color);
int AQH_ModDevices_RgbwGetW(uint32_t color);
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);
int AQH_ModDevices_ValueGetLastDataAsInt(AQH_DATACLIENT *dc, const AQH_VALUE *value, int defaultValue);
uint32_t AQH_ModDevices_ValueGetLastDataAsUint32(AQH_DATACLIENT *dc, const AQH_VALUE *value, uint32_t defaultValue);
AQDG_GRAPH_DATAPAIR_LIST *AQH_ModDevices_RequestDataPairList(AQH_DATACLIENT *dc, const char *systemValueName,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num);
#endif

View File

@@ -1,131 +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 <config.h>
#endif
#include "./mdevices_device.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
#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:"<empty>");
GBAA(dbuf,"<h1>Device %s</h1>\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,"<form action=\"device.html\" method=\"post\">\n");
GBAA(dbuf, "<input type=\"hidden\" name=\"device\" value=\"%s\">\n", sDeviceName);
GBAS(dbuf,"<table>\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,"</table>\n");
GBAS(dbuf,"<br>\n");
GBAS(dbuf,"<input type=\"submit\" name=\"action\" value=\"Send\"/>");
GBAS(dbuf, "</form>\n\n");
}
void _addFieldToForm(const char *sFieldTitle, const char *sFieldName, const char *sFieldContent, GWEN_BUFFER *dbuf)
{
GBAS(dbuf, "<tr>");
GBAA(dbuf, "<td><label for=\"%s\">%s</label></td>", sFieldName, sFieldTitle);
GBAA(dbuf, "<td><input type=\"text\" name=\"%s\" value=\"%s\"/></td>", sFieldName, sFieldContent?sFieldContent:"");
GBAS(dbuf, "</tr>");
}

View File

@@ -1,27 +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.
****************************************************************************/
#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 <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
void AQH_ModDevices_RunDevice(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
#endif

View File

@@ -1,135 +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 <config.h>
#endif
#include "./mdevices_index.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _addLinkForDevice(const char *page, const char *sDevice, const char *action, const char *imgName, GWEN_BUFFER *dbuf);
/* ------------------------------------------------------------------------------------------------
* 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, "<p>No devices.</p>");
return;
}
GBAS(dbuf, "<h1>Devices</h1>\n");
GBAS(dbuf,
"<table class=\"datatable\">\n"
"<thead>\n"
"<tr>"
"<th>Name For System</th>"
"<th>Name For GUI</th>"
"<th>Room</th>"
"<th>Location</th>"
"<th>Description</th>"
"<th>Actions</th>"
"</tr>\n"
"</thead>\n"
"<tbody>\n");
device=AQH_Device_List_First(deviceList);
while(device) {
const char *s;
const char *sDevice;
GBAA(dbuf, "<tr>");
/* name for system */
sDevice=AQH_Device_GetNameForSystem(device);
GBAA(dbuf,"<td>%s</td>", sDevice?sDevice:"");
/* nameForGui */
s=AQH_Device_GetNameForGui(device);
GBAA(dbuf, "<td>%s</td>", s?s:"");
/* room */
s=AQH_Device_GetRoomName(device);
GBAA(dbuf, "<td>%s</td>", s?s:"");
/* location */
s=AQH_Device_GetLocation(device);
GBAA(dbuf, "<td>%s</td>", s?s:"");
/* description */
s=AQH_Device_GetDescription(device);
GBAA(dbuf, "<td>%s</td>", s?s:"");
GBAS(dbuf, "<td>");
if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) {
_addLinkForDevice("vtable.html", sDevice, "table view", "/pics/document-table.png", dbuf);
_addLinkForDevice("vgraph.html", sDevice, "graph view", "/pics/graph.png", dbuf);
}
if (perms & AQH_MODDEVICES_PERMS_DEVICEWRITE) {
_addLinkForDevice("device.html", sDevice, "edit device", "/pics/edit.png", dbuf);
}
GBAS(dbuf, "</td>");
GBAA(dbuf, "</tr>");
device=AQH_Device_List_Next(device);
}
GBAS(dbuf,
"</tbody>\n"
"</table>\n");
AQH_Device_List_free(deviceList);
}
void _addLinkForDevice(const char *page, const char *sDevice, const char *action, const char *imgName, GWEN_BUFFER *dbuf)
{
GBAA(dbuf,"<a href=\"%s?device=", page);
GWEN_Text_EscapeToBufferTolerant(sDevice, dbuf);
GBAS(dbuf,"\">");
GBAA(dbuf,"<img src=\"%s\" alt=\"%s\" title=\"%s\" />", imgName, action, action);
GBAS(dbuf,"</a>");
}

View File

@@ -1,27 +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.
****************************************************************************/
#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 <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
void AQH_ModDevices_RunIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
#endif

View File

@@ -1,129 +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 <config.h>
#endif
#include "./mdevices_init.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
#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);
}

View File

@@ -1,27 +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.
****************************************************************************/
#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 <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
int AQH_ModDevices_Create(AQH_SERVICE *sv);
#endif

View File

@@ -1,961 +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 <config.h>
#endif
#include "./mdevices_page.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <aqdiagram/graph/timegraph.h>
#include <aqdiagram/graph/w_graph.h>
#include <aqdiagram/draw/context_cairo.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/directory.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
enum {
MY_LAYOUT_NONE=0,
MY_LAYOUT_HORIZONTAL,
MY_LAYOUT_VERTICAL
};
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _writePage(AQH_MODULE *m, AQH_DATACLIENT *dc, GWEN_XMLNODE *nPage, GWEN_BUFFER *dbuf);
static void _writeItem(AQH_MODULE *m, AQH_DATACLIENT *dc, const char *sPageId, GWEN_XMLNODE *nItem, GWEN_BUFFER *dbuf);
static void _writeActor(AQH_DATACLIENT *dc, const char *sPageId, GWEN_XMLNODE *n, int layout, GWEN_BUFFER *dbuf);
static void _writeGraph(const char *sPageId, GWEN_XMLNODE *n, int layout, GWEN_BUFFER *dbuf);
static void _handlePageActor(AQCGI_REQUEST *rq, AQH_DATACLIENT *dc, const char *sActorId, GWEN_XMLNODE *nActor);
static void _handlePageGraph(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_DATACLIENT *dc, const char *sGraphId, GWEN_XMLNODE *nGraph, GWEN_BUFFER *dbuf);
static void _genPageGraph(AQH_DATACLIENT *dc, const char *sGraphId, const char *sFilename, GWEN_XMLNODE *nGraph);
static void _addCurves(AQH_DATACLIENT *dc, AQDG_GRAPH *g, GWEN_XMLNODE *nGraph, uint64_t tsBegin, uint64_t tsEnd);
static AQDG_GRAPH_DATAPAIR_LIST *_readCurveData(AQH_DATACLIENT *dc, GWEN_XMLNODE *nCurve, uint64_t tsBegin, uint64_t tsEnd);
static uint64_t _parseTime(const char *s);
static GWEN_XMLNODE *_getSubItemNode(GWEN_XMLNODE *nPage, const char *sId, const char *sElementName);
static void _mkPathForGraph(AQH_MODULE *m, const char *sGraphId, GWEN_BUFFER *dbuf);
static void _addGraphLink(const char *sPageId, const char *sGraphId, int w, int h, 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);
static void _setRgbwData(AQH_DATACLIENT *dc, GWEN_DB_NODE *dbPost, const char *sValueName, const AQH_VALUE *value);
static int _getColorComponent(GWEN_DB_NODE *dbPost, const char *sValueName, const char *sComponent, int defaultValue);
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 _sendPageList(AQH_MODULE *m, GWEN_BUFFER *dbuf);
static GWEN_STRINGLIST *_listPageFiles(AQH_MODULE *m);
static GWEN_XMLNODE *_readPage(AQH_MODULE *m, const char *sPageName);
static GWEN_XMLNODE *_readPageFile(const char *sFilename);
static int _layoutFromString(const char *s);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModDevices_RunPageGet(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf)
{
GWEN_DB_NODE *dbQuery;
const char *sPageId;
DBG_INFO(NULL, "RunPageGet");
dbQuery=AQCGI_Request_GetDbQuery(rq);
sPageId=dbQuery?GWEN_DB_GetCharValue(dbQuery, "page", 0, NULL):NULL;
if (sPageId && *sPageId) {
GWEN_XMLNODE *fileNode;
fileNode=_readPage(m, sPageId);
if (fileNode) {
GWEN_XMLNODE *nPage;
nPage=GWEN_XMLNode_FindFirstTag(fileNode, "page", NULL, NULL);
if (nPage) {
_writePage(m, dc, nPage, dbuf);
AQCGI_Request_AddResponseHeaderData(rq, "Refresh: 120");
}
else {
DBG_ERROR(NULL, "No page element in file for \"%s\"", sPageId);
}
GWEN_XMLNode_free(fileNode);
}
else {
DBG_INFO(NULL, "here");
}
}
else {
DBG_ERROR(NULL, "Reading page list");
_sendPageList(m, dbuf);
}
}
void AQH_ModDevices_RunPageGraph(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf)
{
GWEN_DB_NODE *dbQuery;
const char *sPageId;
const char *sGraphId;
DBG_INFO(NULL, "RunPageGraphGet");
dbQuery=AQCGI_Request_GetDbQuery(rq);
sPageId=GWEN_DB_GetCharValue(dbQuery, "page", 0, NULL);
sGraphId=GWEN_DB_GetCharValue(dbQuery, "graph", 0, NULL);
if (sPageId && *sPageId && sGraphId && *sGraphId) {
GWEN_XMLNODE *fileNode;
fileNode=_readPage(m, sPageId);
if (fileNode) {
GWEN_XMLNODE *nPage;
GWEN_XMLNODE *nGraph;
nPage=GWEN_XMLNode_FindFirstTag(fileNode, "page", "id", sPageId);
nGraph=_getSubItemNode(nPage, sGraphId, "graph");
if (nPage && nGraph)
_handlePageGraph(m, rq, dc, sGraphId, nGraph, dbuf);
else {
DBG_ERROR(NULL, "Graph %s/%s not found", sPageId, sGraphId);
}
GWEN_XMLNode_free(fileNode);
}
else {
DBG_INFO(NULL, "here");
}
}
}
void AQH_ModDevices_RunPagePost(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf)
{
GWEN_DB_NODE *dbPost;
const char *sPageId;
const char *sActorId;
DBG_INFO(NULL, "RunPagePost");
dbPost=AQCGI_Request_GetDbPostBody(rq);
sPageId=GWEN_DB_GetCharValue(dbPost, "page", 0, NULL);
sActorId=GWEN_DB_GetCharValue(dbPost, "actor", 0, NULL);
if (sPageId && *sPageId && sActorId && *sActorId) {
GWEN_XMLNODE *fileNode;
fileNode=_readPage(m, sPageId);
if (fileNode) {
GWEN_XMLNODE *nPage;
GWEN_XMLNODE *nActor;
nPage=GWEN_XMLNode_FindFirstTag(fileNode, "page", "id", sPageId);
nActor=_getSubItemNode(nPage, sActorId, "actor");
if (nPage && nActor) {
_handlePageActor(rq, dc, sActorId, nActor);
}
else {
DBG_ERROR(NULL, "Actor %s/%s not found", sPageId, sActorId);
}
GWEN_XMLNode_free(fileNode);
}
else {
DBG_INFO(NULL, "here");
}
}
if (sPageId && *sPageId) {
GWEN_BUFFER *pbuf;
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
GBAS(pbuf, "Location: page.html?page=");
GWEN_Text_EscapeToBuffer(sPageId, 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 _handlePageActor(AQCGI_REQUEST *rq, AQH_DATACLIENT *dc, const char *sActorId, GWEN_XMLNODE *nActor)
{
GWEN_DB_NODE *dbPost;
const char *sDeviceName;
const char *sValueName;
dbPost=AQCGI_Request_GetDbPostBody(rq);
sDeviceName=GWEN_XMLNode_GetProperty(nActor, "device", NULL);
sValueName=GWEN_XMLNode_GetProperty(nActor, "value", NULL);
if (sDeviceName && *sDeviceName && sValueName && *sValueName) {
AQH_VALUE *value;
value=AQH_ModDevices_GetValueForDevice(dc, sDeviceName, sValueName);
if (value) {
const char *sSystemValueName;
sSystemValueName=AQH_Value_GetNameForSystem(value);
if (sSystemValueName) {
const char *sData;
sData=GWEN_DB_GetCharValue(dbPost, sActorId, 0, NULL);
DBG_INFO(NULL, "Setting value %s to %s", sSystemValueName, sData?sData:"empty/no value");
switch(AQH_Value_GetModality(value)) {
case AQH_ValueModality_RGBW: _setRgbwData(dc, dbPost, sActorId, value); break;
case AQH_ValueModality_OnOff: _setOnOffData(dc, value, sData); break;
case AQH_ValueModality_OnOffAuto: _setOnOffAutoData(dc, value, sData); break;
default:
break;
} /* switch */
}
}
}
}
void _handlePageGraph(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_DATACLIENT *dc, const char *sGraphId, GWEN_XMLNODE *nGraph, GWEN_BUFFER *dbuf)
{
GWEN_BUFFER *fbuf;
int refreshTime;
refreshTime=GWEN_XMLNode_GetIntProperty(nGraph, "refreshTime", 120);
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
_mkPathForGraph(m, sGraphId, fbuf);
if (!AQH_ModService_FileIsCurrent(GWEN_Buffer_GetStart(fbuf), refreshTime)) {
_genPageGraph(dc, sGraphId, GWEN_Buffer_GetStart(fbuf), nGraph);
}
AQH_ModService_RespondWithMimeFile(rq, GWEN_Buffer_GetStart(fbuf), "image/png", dbuf);
GWEN_Buffer_free(fbuf);
}
void _genPageGraph(AQH_DATACLIENT *dc, const char *sGraphId, const char *sFilename, GWEN_XMLNODE *nGraph)
{
const char *s;
const char *sTitle;
int w;
int h;
int precision;
uint64_t tsBegin;
uint64_t tsEnd;
AQDG_GRAPH *g;
AQDG_DRAW_CONTEXT *drawContext;
AQDG_OBJECT *graphObject;
uint32_t tickFlags=0;
double upperLimit;
double lowerLimit;
sTitle=GWEN_XMLNode_GetProperty(nGraph, "title", "untitled");
w=GWEN_XMLNode_GetIntProperty(nGraph, "width", AQH_MODDEVICES_GRAPH_WIDTH);
h=GWEN_XMLNode_GetIntProperty(nGraph, "height", AQH_MODDEVICES_GRAPH_HEIGHT);
precision=GWEN_XMLNode_GetIntProperty(nGraph, "precision", 2);
tsBegin=_parseTime(GWEN_XMLNode_GetProperty(nGraph, "begin", "-4h"));
tsEnd=_parseTime(GWEN_XMLNode_GetProperty(nGraph, "end", "0"));
s=GWEN_XMLNode_GetProperty(nGraph, "lowerLimit", NULL);
if (s && *s) {
if (1==sscanf(s, "%lf", &lowerLimit))
tickFlags|=AQDG_TIMEGRAPH_SETUPTICKS_FLAGS_MINY;
else {
DBG_ERROR(NULL, "Ignoring invalid lowerLimit (%s)", s);
}
}
s=GWEN_XMLNode_GetProperty(nGraph, "upperLimit", NULL);
if (s && *s) {
if (1==sscanf(s, "%lf", &upperLimit))
tickFlags|=AQDG_TIMEGRAPH_SETUPTICKS_FLAGS_MAXY;
else {
DBG_ERROR(NULL, "Ignoring invalid upperLimit (%s)", s);
}
}
g=AQDG_TimeGraph_new(sTitle, NULL, "Value", NULL, precision);
_addCurves(dc, g, nGraph, tsBegin, tsEnd);
AQDG_TimeGraph_SetupTicks(g, tickFlags, lowerLimit, upperLimit);
DBG_DEBUG(NULL, "Draw graph for %s", sGraphId);
drawContext=AQDG_Draw_ContextCairo_Png_new(sFilename, w, h);
graphObject=AQDG_GraphWidget_new(NULL, AQDG_OBJECT_OPTIONS_STRETCHX | AQDG_OBJECT_OPTIONS_STRETCHY, drawContext);
AQDG_Object_SetWidth(graphObject, w);
AQDG_Object_SetHeight(graphObject, h);
AQDG_GraphWidget_SetupDefaultPens(graphObject);
AQDG_GraphWidget_SetupDefaultFonts(graphObject);
AQDG_GraphWidget_FinishWithGraph(graphObject, g);
AQDG_Object_free(graphObject);
}
void _addCurves(AQH_DATACLIENT *dc, AQDG_GRAPH *g, GWEN_XMLNODE *nGraph, uint64_t tsBegin, uint64_t tsEnd)
{
GWEN_XMLNODE *nCurve;
nCurve=GWEN_XMLNode_FindFirstTag(nGraph, "curve", NULL, NULL);
while(nCurve) {
const char *sModifier;
sModifier=GWEN_XMLNode_GetProperty(nCurve, "modifier", NULL);
if (sModifier && *sModifier) {
AQDG_GRAPH_DATAPAIR_LIST *dpList;
dpList=_readCurveData(dc, nCurve, tsBegin, tsEnd);
if (dpList) {
const char *sCurveLabel;
sCurveLabel=GWEN_XMLNode_GetProperty(nCurve, "title", NULL);
DBG_DEBUG(NULL, "Adding data for %s", sCurveLabel?sCurveLabel:"<no title>");
AQDG_TimeGraph_ModifyDataAndAddCurve(g, sCurveLabel?sCurveLabel:"<no title>", sModifier, dpList);
}
}
nCurve=GWEN_XMLNode_FindNextTag(nCurve, "curve", NULL, NULL);
}
}
AQDG_GRAPH_DATAPAIR_LIST *_readCurveData(AQH_DATACLIENT *dc, GWEN_XMLNODE *nCurve, uint64_t tsBegin, uint64_t tsEnd)
{
const char *sDeviceName;
const char *sValueName;
sDeviceName=GWEN_XMLNode_GetProperty(nCurve, "device", NULL);
sValueName=GWEN_XMLNode_GetProperty(nCurve, "value", NULL);
if (sDeviceName && *sDeviceName && sValueName && *sValueName) {
AQDG_GRAPH_DATAPAIR_LIST *dpList;
GWEN_BUFFER *vbuf;
vbuf=GWEN_Buffer_new(0, 64, 0, 1);
GBAA(vbuf, "%s/%s", sDeviceName, sValueName);
dpList=AQH_ModDevices_RequestDataPairList(dc, GWEN_Buffer_GetStart(vbuf), tsBegin, tsEnd, 100000);
if (dpList) {
GWEN_Buffer_free(vbuf);
return dpList;
}
GWEN_Buffer_free(vbuf);
}
return NULL;
}
// TODO: move to aqhome.{c,h}
uint64_t _parseTime(const char *s)
{
if (s && *s) {
if (*s=='-') {
uint64_t x=0;
uint64_t now=time(NULL);
s++;
while(*s && isdigit(*s)) {
unsigned int i;
i=*(s++)-'0';
x*=10;
x+=i;
}
if (*s) {
switch(*s) {
case 0:
case 'm': x*=60; break;
case 'h': x*=(60*60); break;
case 'd': x*=(60*60*24); break;
case 'w': x*=(60*60*24*7); break;
case 'M': x*=(60*60*24*30); break;
case 'y': x*=(60*60*24*365); break;
default: break;
}
}
return (now-x);
}
if (*s=='@') {
int y, m, d, H, M, S;
if (6==sscanf(s+1, "%d/%d/%d-%d:%d:%d", &y, &m, &d, &H, &M, &S)) {
GWEN_TIMESTAMP *ts;
uint64_t x=0;
ts=GWEN_Timestamp_new(y, m, d, H, M, S);
x=GWEN_Timestamp_toTimeT(ts);
GWEN_Timestamp_free(ts);
return x;
}
else {
DBG_ERROR(NULL, "Invalid timespec [%s], expected: @YYYY/MM/DD-HH:MM:SS", s);
return (uint64_t) (-1);
}
}
else {
unsigned long int x;
if (1!=sscanf(s, "%lu", &x)) {
DBG_ERROR(NULL, "ERROR: Invalid timestamp");
return (uint64_t) (-1);
}
return (uint64_t) x;
}
}
return 0;
}
GWEN_XMLNODE *_getSubItemNode(GWEN_XMLNODE *nPage, const char *sId, const char *sElementName)
{
GWEN_XMLNODE *nItem;
nItem=GWEN_XMLNode_FindFirstTag(nPage, "item", NULL, NULL);
while(nItem) {
GWEN_XMLNODE *nGraph;
nGraph=GWEN_XMLNode_FindFirstTag(nItem, sElementName, "id", sId);
if (nGraph)
return nGraph;
nItem=GWEN_XMLNode_FindNextTag(nItem, "item", NULL, NULL);
}
return NULL;
}
void _mkPathForGraph(AQH_MODULE *m, const char *sGraphId, GWEN_BUFFER *buf)
{
AQH_SERVICE *sv;
const char *s;
sv=AQH_ModService_GetService(m);
s=AQH_Service_GetCacheFolder(sv);
GBAA(buf, "%s%s%s", s, GWEN_DIR_SEPARATOR_S, sGraphId);
AQH_ModService_EscapeToBuffer(s, buf);
GBAS(buf, ".png");
}
void _writePage(AQH_MODULE *m, AQH_DATACLIENT *dc, GWEN_XMLNODE *nPage, GWEN_BUFFER *dbuf)
{
const char *sPageId;
GWEN_XMLNODE *nItem;
int layout;
const char *s;
sPageId=GWEN_XMLNode_GetProperty(nPage, "id", NULL);
/* title */
s=GWEN_XMLNode_GetProperty(nPage, "title", NULL);
if (s && *s)
GBAA(dbuf, "<h1>%s</h1>\n", s);
layout=_layoutFromString(GWEN_XMLNode_GetProperty(nPage, "layout", "none"));
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "<table class=\"pageTable\">\n");
if (layout==MY_LAYOUT_HORIZONTAL)
GBAS(dbuf, "<tr>\n");
nItem=GWEN_XMLNode_FindFirstTag(nPage, "item", NULL, NULL);
while(nItem) {
if (layout==MY_LAYOUT_VERTICAL)
GBAS(dbuf, "<tr>\n");
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "<td>");
_writeItem(m, dc, sPageId, nItem, dbuf);
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "</td>");
if (layout==MY_LAYOUT_VERTICAL)
GBAS(dbuf, "</tr>\n");
nItem=GWEN_XMLNode_FindNextTag(nItem, "item", NULL, NULL);
} /* while */
if (layout==MY_LAYOUT_HORIZONTAL)
GBAS(dbuf, "</tr>\n");
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "</table> <!-- pageTable -->\n");
}
void _writeItem(AQH_MODULE *m, AQH_DATACLIENT *dc, const char *sPageId, GWEN_XMLNODE *nItem, GWEN_BUFFER *dbuf)
{
GWEN_XMLNODE *n;
uint32_t perms;
int layout;
perms=AQH_ModService_GetUserPerms(m);
layout=_layoutFromString(GWEN_XMLNode_GetProperty(nItem, "layout", "none"));
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "<table class=\"itemTable\">\n");
if (layout==MY_LAYOUT_HORIZONTAL)
GBAS(dbuf, "<tr>\n");
n=GWEN_XMLNode_GetFirstTag(nItem);
while(n) {
const char *sName;
if (layout==MY_LAYOUT_VERTICAL)
GBAS(dbuf, "<tr>\n");
sName=GWEN_XMLNode_GetData(n);
if (sName && *sName) {
if (strcasecmp(sName, "actor")==0) {
if (perms && AQH_MODDEVICES_PERMS_VALUEWRITE)
_writeActor(dc, sPageId, n, layout, dbuf);
else {
DBG_ERROR(NULL, "No permissions to write values");
}
}
else if (strcasecmp(sName, "graph")==0)
_writeGraph(sPageId, n, layout, dbuf);
else {
DBG_ERROR(NULL, "Ignoring element \"%s\"", sName);
}
}
if (layout==MY_LAYOUT_VERTICAL)
GBAS(dbuf, "</tr>\n");
n=GWEN_XMLNode_GetNextTag(n);
}
if (layout==MY_LAYOUT_HORIZONTAL)
GBAS(dbuf, "</tr>\n");
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "</table> <!-- itemTable -->\n");
}
void _writeActor(AQH_DATACLIENT *dc, const char *sPageId, GWEN_XMLNODE *n, int layout, GWEN_BUFFER *dbuf)
{
const char *sActorId;
const char *sDeviceName;
const char *sValueName;
const char *sLabel;
sActorId=GWEN_XMLNode_GetProperty(n, "id", NULL);
sLabel=GWEN_XMLNode_GetProperty(n, "label", NULL);
sDeviceName=GWEN_XMLNode_GetProperty(n, "device", NULL);
sValueName=GWEN_XMLNode_GetProperty(n, "value", NULL);
if (sActorId && *sActorId && sDeviceName && *sDeviceName && sValueName && *sValueName) {
AQH_VALUE *value;
value=AQH_ModDevices_GetValueForDevice(dc, sDeviceName, sValueName);
if (value) {
uint32_t lastData;
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "<td>\n");
lastData=AQH_ModDevices_ValueGetLastDataAsUint32(dc, value, 0);
GBAS(dbuf,"<form action=\"page.html\" method=\"post\">\n");
GBAA(dbuf, "<input type=\"hidden\" name=\"page\" value=\"%s\">\n", sPageId);
GBAA(dbuf, "<input type=\"hidden\" name=\"actor\" value=\"%s\">\n", sActorId);
DBG_INFO(NULL, "Adding actor");
if (sLabel && *sLabel)
GBAA(dbuf,"<label for=\"%s\">%s</label>", sActorId, sLabel);
if (layout!=MY_LAYOUT_NONE) {
GBAS(dbuf, "</td>\n");
GBAS(dbuf, "<td>\n");
}
switch(AQH_Value_GetModality(value)) {
case AQH_ValueModality_RGBW: _writeRgbwToForm(sActorId, lastData, dbuf); break;
case AQH_ValueModality_OnOff: _writeOnOffToForm(sActorId, lastData, dbuf); break;
case AQH_ValueModality_OnOffAuto: _writeOnOffAutoToForm(sActorId, lastData, dbuf); break;
default: GBAA(dbuf, "%d", lastData); break;
} /* switch */
if (layout!=MY_LAYOUT_NONE) {
GBAS(dbuf, "</td>\n");
GBAS(dbuf, "<td>\n");
}
GBAS(dbuf,"<input type=\"submit\" name=\"action\" value=\"Send\"/>");
GBAS(dbuf, "</form>\n\n");
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "</td>\n");
}
}
}
void _writeGraph(const char *sPageId, GWEN_XMLNODE *n, int layout, GWEN_BUFFER *dbuf)
{
const char *sGraphId;
int w;
int h;
w=GWEN_XMLNode_GetIntProperty(n, "width", AQH_MODDEVICES_GRAPH_WIDTH);
h=GWEN_XMLNode_GetIntProperty(n, "height", AQH_MODDEVICES_GRAPH_HEIGHT);
sGraphId=GWEN_XMLNode_GetProperty(n, "id", NULL);
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "<td colspan=\"3\">\n");
if (sGraphId && *sGraphId)
_addGraphLink(sPageId, sGraphId, w, h, dbuf);
if (layout!=MY_LAYOUT_NONE)
GBAS(dbuf, "</td>\n");
}
void _addGraphLink(const char *sPageId, const char *sGraphId, int w, int h, GWEN_BUFFER *dbuf)
{
GBAS(dbuf, "<img src=\"pgraph.html?page=");
AQH_ModService_EscapeToBuffer(sPageId, dbuf);
GBAS(dbuf, "&graph=");
AQH_ModService_EscapeToBuffer(sGraphId, dbuf);
GBAA(dbuf, "\" alt=\"%s\" width=\"%d\" height=\"%d\"", sGraphId, w, h);
GBAS(dbuf, "/>");
}
void _writeRgbwToForm(const char *sValueName, uint32_t color, GWEN_BUFFER *dbuf)
{
#if 1
DBG_ERROR(NULL, "Color=%08x (%d, %d, %d, %d)",
color,
AQH_ModDevices_RgbwGetR(color),
AQH_ModDevices_RgbwGetG(color),
AQH_ModDevices_RgbwGetB(color),
AQH_ModDevices_RgbwGetW(color));
GBAA(dbuf, "<label for=\"%s_r\">R:</label>", sValueName);
GBAA(dbuf, "<input type=\"number\" min=\"0\" max=\"255\" name=\"%s_r\" id=name=\"%s_r\" value=\"%d\">",
sValueName, sValueName, AQH_ModDevices_RgbwGetR(color));
GBAA(dbuf, "<label for=\"%s_g\">G:</label>", sValueName);
GBAA(dbuf, "<input type=\"number\" min=\"0\" max=\"255\" name=\"%s_g\" id=name=\"%s_g\" value=\"%d\">",
sValueName, sValueName, AQH_ModDevices_RgbwGetG(color));
GBAA(dbuf, "<label for=\"%s_b\">B:</label>", sValueName);
GBAA(dbuf, "<input type=\"number\" min=\"0\" max=\"255\" name=\"%s_b\" id=name=\"%s_b\" value=\"%d\">",
sValueName, sValueName, AQH_ModDevices_RgbwGetB(color));
GBAA(dbuf, "<label for=\"%s_w\">W:</label>", sValueName);
GBAA(dbuf, "<input type=\"number\" min=\"0\" max=\"255\" name=\"%s_w\" id=name=\"%s_w\" value=\"%d\">",
sValueName, sValueName, AQH_ModDevices_RgbwGetW(color));
#else
GBAA(dbuf, "<input type=\"text\" name=\"%s\" id=\"%s\" value=\"#%08x\"/>", sValueName, sValueName, color);
// else
GBAA(dbuf, "<input type=\"color\" name=\"%s\" id=\"%s\" value=\"#%08x\"/>#%08x (#%08x)",
sValueName, sValueName,
AQH_ModDevices_RgbwToHtmlColor(color),
AQH_ModDevices_RgbwToHtmlColor(color),
color);
#endif
}
void _setRgbwData(AQH_DATACLIENT *dc, GWEN_DB_NODE *dbPost, const char *sValueName, const AQH_VALUE *value)
{
const char *sValueSystemName;
uint32_t color;
int rv;
sValueSystemName=AQH_Value_GetNameForSystem(value);
DBG_INFO(NULL, "Set value %s", sValueName);
color=AQH_ModDevices_RgbwFromComponents(_getColorComponent(dbPost, sValueName, "r", 0),
_getColorComponent(dbPost, sValueName, "g", 0),
_getColorComponent(dbPost, sValueName, "b", 0),
_getColorComponent(dbPost, sValueName, "w", 0));
DBG_INFO(NULL, "Send value [#%08x] to %s", color, sValueSystemName);
rv=AQH_DataClient_SetData(dc, value, (double) color);
if (rv<0) {
DBG_INFO(NULL, "Error sending data: %d", rv);
}
}
int _getColorComponent(GWEN_DB_NODE *dbPost, const char *sValueName, const char *sComponent, int defaultValue)
{
GWEN_BUFFER *buf;
const char *sData;
int result;
buf=GWEN_Buffer_new(0, 64, 0, 1);
GBAA(buf, "%s_%s", sValueName, sComponent);
DBG_INFO(NULL, "Read value %s", GWEN_Buffer_GetStart(buf));
sData=GWEN_DB_GetCharValue(dbPost, GWEN_Buffer_GetStart(buf), 0, NULL);
GWEN_Buffer_free(buf);
if (sData) {
if (1==sscanf(sData, "%u", &result))
return result;
}
return defaultValue;
}
void _writeOnOffToForm(const char *sValueName, int intVal, GWEN_BUFFER *dbuf)
{
GBAA(dbuf, "<select name=\"%s\" id=\"%s\">" "<option value=\"unchanged\" >unchanged</option>", sValueName, sValueName);
GBAA(dbuf, "<option value=\"off\" %s>off</option>", (intVal==0)?"selected":"");
GBAA(dbuf, "<option value=\"on\" %s>on</option>", (intVal==1)?"selected":"");
GBAS(dbuf, "</select>");
}
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_INFO(NULL, "Value %s unchanged", sValueSystemName);
}
else if (strcasecmp(sValue, "on")==0) {
DBG_INFO(NULL, "Send value 1 to %s", sValueSystemName);
rv=AQH_DataClient_SetData(dc, value, 1.0);
if (rv<0) {
DBG_INFO(NULL, "Error sending data: %d", rv);
}
}
else if (strcasecmp(sValue, "off")==0) {
DBG_INFO(NULL, "Send value 0 to %s", sValueSystemName);
rv=AQH_DataClient_SetData(dc, value, 0.0);
if (rv<0) {
DBG_INFO(NULL, "Error sending data: %d", rv);
}
}
else {
}
}
}
void _writeOnOffAutoToForm(const char *sValueName, int intVal, GWEN_BUFFER *dbuf)
{
GBAA(dbuf, "<select name=\"%s\" id=\"%s\" >" "<option value=\"unchanged\" >unchanged</option>", sValueName, sValueName);
GBAA(dbuf, "<option value=\"off\" %s>off</option>", (intVal==0)?"selected":"");
GBAA(dbuf, "<option value=\"on\" %s>on</option>", (intVal==1)?"selected":"");
GBAA(dbuf, "<option value=\"auto\" %s>auto</option>", (intVal==2)?"selected":"");
GBAS(dbuf, "</select>");
}
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_INFO(NULL, "Value %s unchanged", sValueSystemName);
}
else if (strcasecmp(sValue, "on")==0) {
DBG_INFO(NULL, "Send value 1 to %s", sValueSystemName);
rv=AQH_DataClient_SetData(dc, value, 1.0);
if (rv<0) {
DBG_INFO(NULL, "Error sending data: %d", rv);
}
}
else if (strcasecmp(sValue, "off")==0) {
DBG_INFO(NULL, "Send value 0 to %s", sValueSystemName);
rv=AQH_DataClient_SetData(dc, value, 0.0);
if (rv<0) {
DBG_INFO(NULL, "Error sending data: %d", rv);
}
}
else if (strcasecmp(sValue, "auto")==0) {
DBG_INFO(NULL, "Send value 2 to %s", sValueSystemName);
rv=AQH_DataClient_SetData(dc, value, 2.0);
if (rv<0) {
DBG_INFO(NULL, "Error sending data: %d", rv);
}
}
else {
DBG_INFO(NULL, "Invalid value [%s] for %s", sValue, sValueSystemName);
}
}
}
void _sendPageList(AQH_MODULE *m, GWEN_BUFFER *dbuf)
{
GWEN_STRINGLIST *sl;
GBAS(dbuf, "<h1>Page List</h1>\n");
sl=_listPageFiles(m);
if (sl) {
GWEN_STRINGLISTENTRY *se;
GBAS(dbuf,
"<table class=\"datatable\">\n"
"<thead><tr><th>Page</th><th>Title</th></tr></thead>\n"
"<tbody>\n");
se=GWEN_StringList_FirstEntry(sl);
while(se) {
const char *filename;
filename=GWEN_StringListEntry_Data(se);
if (filename && *filename) {
GWEN_XMLNODE *node;
DBG_ERROR(NULL, "Reading file \"%s\"", filename);
node=_readPageFile(filename);
if (node) {
GWEN_XMLNODE *nPage;
nPage=GWEN_XMLNode_FindFirstTag(node, "page", NULL, NULL);
if (nPage) {
const char *sId;
const char *sTitle;
sId=GWEN_XMLNode_GetProperty(nPage, "id", NULL);
sTitle=GWEN_XMLNode_GetProperty(nPage, "title", sId);
if (sId && *sId)
GBAA(dbuf, "<tr><td><a href=\"page.html?page=%s\">%s</a></td><td>%s</td></tr>\n", sId, sId, sTitle);
}
GWEN_XMLNode_free(node);
}
}
se=GWEN_StringListEntry_Next(se);
}
GBAS(dbuf, "</tbody></table>");
GWEN_StringList_free(sl);
}
else {
GBAS(dbuf, "No pages.");
}
}
GWEN_STRINGLIST *_listPageFiles(AQH_MODULE *m)
{
GWEN_BUFFER *fbuf;
AQH_SERVICE *sv;
GWEN_STRINGLIST *sl;
int rv;
sv=AQH_ModService_GetService(m);
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
GBAA(fbuf, "%s%spages", AQH_Service_GetRuntimeFolder(sv), GWEN_DIR_SEPARATOR_S);
sl=GWEN_StringList_new();
rv=GWEN_Directory_GetMatchingFilesRecursively(GWEN_Buffer_GetStart(fbuf), sl, "*.xml");
if (rv<0) {
DBG_INFO(NULL, "Error reading pages (%d)", rv);
GWEN_StringList_free(sl);
GWEN_Buffer_free(fbuf);
return NULL;
}
if (GWEN_StringList_Count(sl)<1) {
GWEN_StringList_free(sl);
GWEN_Buffer_free(fbuf);
return NULL;
}
GWEN_Buffer_free(fbuf);
return sl;
}
GWEN_XMLNODE *_readPage(AQH_MODULE *m, const char *sPageName)
{
GWEN_BUFFER *fbuf;
AQH_SERVICE *sv;
GWEN_XMLNODE *fileNode;
sv=AQH_ModService_GetService(m);
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
GBAA(fbuf, "%s%spages%s", AQH_Service_GetRuntimeFolder(sv), GWEN_DIR_SEPARATOR_S, GWEN_DIR_SEPARATOR_S);
AQH_ModService_EscapeToBuffer(sPageName, fbuf);
GBAS(fbuf, ".xml");
fileNode=_readPageFile(GWEN_Buffer_GetStart(fbuf));
if (fileNode==NULL) {
DBG_INFO(NULL, "here");
GWEN_Buffer_free(fbuf);
return NULL;
}
GWEN_Buffer_free(fbuf);
return fileNode;
}
GWEN_XMLNODE *_readPageFile(const char *sFilename)
{
GWEN_XMLNODE *fileNode;
int rv;
fileNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, sFilename);
rv=GWEN_XML_ReadFile(fileNode, sFilename, GWEN_XML_FLAGS_DEFAULT);
if (rv<0) {
DBG_ERROR(NULL, "Error reading \"%s\": %s (%d)", sFilename?sFilename:"<no name>", strerror(errno), errno);
GWEN_XMLNode_free(fileNode);
return NULL;
}
return fileNode;
}
int _layoutFromString(const char *s)
{
if (s && *s) {
if (strcasecmp(s, "none")==0)
return MY_LAYOUT_NONE;
else if (strcasecmp(s, "horizontal")==0)
return MY_LAYOUT_HORIZONTAL;
else if (strcasecmp(s, "vertical")==0)
return MY_LAYOUT_VERTICAL;
}
return MY_LAYOUT_NONE;
}

View File

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

View File

@@ -1,194 +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 <config.h>
#endif
#include "./mdevices_setdata.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _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;
const AQH_VALUE *value;
/* 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:"");
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) */
}
if (sDeviceName && *sDeviceName) {
GWEN_BUFFER *pbuf;
pbuf=GWEN_Buffer_new(0, 256, 0, 1);
if (sValueName && *sValueName) {
GBAS(pbuf, "Location: value.html?device=");
GWEN_Text_EscapeToBuffer(sDeviceName, pbuf);
GBAS(pbuf, "&value=");
GWEN_Text_EscapeToBuffer(sValueName, pbuf);
}
else {
GBAS(pbuf, "Location: 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);
}
}
}

View File

@@ -1,27 +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.
****************************************************************************/
#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 <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
void AQH_ModDevices_RunSetData(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
#endif

View File

@@ -1,105 +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 <config.h>
#endif
#include "./mdevices_setdevice.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _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: 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));
}

View File

@@ -1,27 +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.
****************************************************************************/
#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 <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
void AQH_ModDevices_RunSetDevice(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
#endif

View File

@@ -1,245 +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 <config.h>
#endif
#include "./mdevices_value.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _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:"<empty>", sValueName?sValueName:"<empty>");
GBAA(dbuf,"<h1>Value %s/%s</h1>\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, "<table>\n");
GBAS(dbuf, "<tr><td>");
GBAS(dbuf, "<img src=\"graph.html?device=");
GWEN_Text_EscapeToBufferTolerant(sDeviceName, dbuf);
GBAS(dbuf, "&value=");
GWEN_Text_EscapeToBufferTolerant(sValueName, dbuf);
GBAS(dbuf, "&period=4h\"/>");
GBAS(dbuf, "</td></tr>");
GBAS(dbuf, "<tr><td>");
GBAS(dbuf, "<img src=\"graph.html?device=");
GWEN_Text_EscapeToBufferTolerant(sDeviceName, dbuf);
GBAS(dbuf, "&value=");
GWEN_Text_EscapeToBufferTolerant(sValueName, dbuf);
GBAS(dbuf, "&period=1d\"/>");
GBAS(dbuf, "</td></tr>");
GBAS(dbuf, "<tr><td>");
GBAS(dbuf, "<img src=\"graph.html?device=");
GWEN_Text_EscapeToBufferTolerant(sDeviceName, dbuf);
GBAS(dbuf, "&value=");
GWEN_Text_EscapeToBufferTolerant(sValueName, dbuf);
GBAS(dbuf, "&period=1w\"/>");
GBAS(dbuf, "</td></tr>");
GBAS(dbuf, "</table>");
}
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,"<form action=\"setdata.html\" method=\"post\">\n");
GBAA(dbuf, "<input type=\"hidden\" name=\"device\" value=\"%s\">\n", sDeviceName);
GBAA(dbuf, "<input type=\"hidden\" name=\"value\" value=\"%s\">\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,"<input type=\"submit\" name=\"action\" value=\"Send\"/>");
GBAS(dbuf, "</form>\n\n");
}
void _writeRgbwToForm(const char *sValueName, uint32_t color, GWEN_BUFFER *dbuf)
{
#if 1
GBAA(dbuf, "<input type=\"text\" name=\"%s\" value=\"#%08x\"/>", sValueName, color);
#else
GBAA(dbuf, "<input type=\"color\" name=\"%s\" value=\"#%08x\"/>#%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, "<select name=\"%s\">" "<option value=\"unchanged\" >unchanged</option>", sValueName);
GBAA(dbuf, "<option value=\"off\" %s>off</option>", (intVal==0)?"selected":"");
GBAA(dbuf, "<option value=\"on\" %s>on</option>", (intVal==1)?"selected":"");
GBAS(dbuf, "</select>");
}
void _writeOnOffAutoToForm(const char *sValueName, int intVal, GWEN_BUFFER *dbuf)
{
GBAA(dbuf, "<select name=\"%s\">" "<option value=\"unchanged\" >unchanged</option>", sValueName);
GBAA(dbuf, "<option value=\"off\" %s>off</option>", (intVal==0)?"selected":"");
GBAA(dbuf, "<option value=\"on\" %s>on</option>", (intVal==1)?"selected":"");
GBAA(dbuf, "<option value=\"auto\" %s>auto</option>", (intVal==2)?"selected":"");
GBAS(dbuf, "</select>");
}

View File

@@ -1,27 +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.
****************************************************************************/
#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 <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
void AQH_ModDevices_RunValue(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
#endif

View File

@@ -1,175 +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 <config.h>
#endif
#include "./mdevices_valuesgraph.h"
#include "./mdevices_index.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _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, int withLink);
/* ------------------------------------------------------------------------------------------------
* 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 {
const char *sValueName;
sValueName=GWEN_DB_GetCharValue(dbQuery, "value", 0, NULL);
if (sValueName && *sValueName) {
AQH_VALUE *value;
GBAA(dbuf,"<h1>Value %s/%s</h1>\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 {
AQH_VALUE_LIST *valueList;
valueList=AQH_DataClient_GetValues(dc, sDeviceName, 0);
if (valueList && AQH_Value_List_GetCount(valueList)) {
GBAA(dbuf,"<h1>Values for Device %s</h1>\n", sDeviceName);
_writeValueListToTable(sDeviceName, valueList, dbuf);
GBAS(dbuf, "\n");
}
else {
GBAS(dbuf,"<p>No values.</p>\n");
}
AQH_Value_List_free(valueList);
AQCGI_Request_AddResponseHeaderData(rq, "Refresh: 305");
}
}
}
void _writeValueToDetailedTable(const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf)
{
const char *sValueName;
GBAS(dbuf, "<table>\n");
sValueName=AQH_Value_GetName(value);
GBAS(dbuf, "<tr><td>");
_addGraphLink(sDeviceName, sValueName, "4h", dbuf, 0);
GBAS(dbuf, "</td><td>");
_addGraphLink(sDeviceName, sValueName, "1d", dbuf, 0);
GBAS(dbuf, "</td></tr><tr><td>");
_addGraphLink(sDeviceName, sValueName, "1w", dbuf, 0);
GBAS(dbuf, "</td><td>");
_addGraphLink(sDeviceName, sValueName, "12m", dbuf, 0);
GBAS(dbuf, "</td></tr>\n");
}
void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, GWEN_BUFFER *dbuf)
{
const AQH_VALUE *value;
GBAS(dbuf, "<table>\n");
value=AQH_Value_List_First(valueList);
while(value) {
if (AQH_Value_GetValueType(value)!=AQH_ValueType_Actor)
_writeValueToTable(sDeviceName, value, dbuf);
value=AQH_Value_List_Next(value);
}
GBAS(dbuf, "</table>\n");
}
void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, GWEN_BUFFER *dbuf)
{
const char *sValueName;
/* name */
sValueName=AQH_Value_GetName(value);
GBAS(dbuf, "<tr><td>");
_addGraphLink(sDeviceName, sValueName, "1d", dbuf, 1);
GBAS(dbuf, "</td><td>");
_addGraphLink(sDeviceName, sValueName, "1w", dbuf, 1);
GBAS(dbuf, "</td></tr>\n");
}
void _addGraphLink(const char *sDeviceName, const char *sValueName, const char *sPeriod, GWEN_BUFFER *dbuf, int withLink)
{
if (withLink) {
GBAS(dbuf, "<a href=\"vgraph.html?device=");
GWEN_Text_EscapeToBufferTolerant(sDeviceName, dbuf);
GBAS(dbuf, "&value=");
GWEN_Text_EscapeToBufferTolerant(sValueName, dbuf);
GBAS(dbuf, "\">");
}
GBAS(dbuf, "<img src=\"graph.html?device=");
GWEN_Text_EscapeToBufferTolerant(sDeviceName, dbuf);
GBAS(dbuf, "&value=");
GWEN_Text_EscapeToBufferTolerant(sValueName, dbuf);
GBAA(dbuf, "&period=%s\"", sPeriod);
GBAA(dbuf, " alt=\"%s\" width=\"%d\" height=\"%d\"", sValueName, AQH_MODDEVICES_GRAPH_WIDTH, AQH_MODDEVICES_GRAPH_HEIGHT);
GBAS(dbuf, "/>");
if (withLink) {
GBAS(dbuf, "</a>");
}
}

View File

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

View File

@@ -1,145 +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 <config.h>
#endif
#include "./mdevices_valuestable.h"
#include "./mdevices_index.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, 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_RunValuesAsTable(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,"<h1>Values for Device %s</h1>\n", sDeviceName);
_writeValueListToTable(sDeviceName, valueList, perms, dbuf);
GBAS(dbuf, "\n");
}
else {
GBAS(dbuf,"<p>No values.</p>\n");
}
AQH_Value_List_free(valueList);
}
}
void _writeValueListToTable(const char *sDeviceName, const AQH_VALUE_LIST *valueList, uint32_t perms, GWEN_BUFFER *dbuf)
{
const AQH_VALUE *value;
GBAS(dbuf,
"<table class=\"datatable\">\n"
"<thead>"
"<tr>"
"<th>Name</th>"
"<th>Type</th>"
"<th>Modality</th>"
#if 0
"<th>Driver</th>"
"<th>Device</th>"
"<th>Name for System</th>"
#endif
"</tr>"
"</thead>\n"
"<tbody>\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,
"</tbody>\n"
"</table>\n");
}
void _writeValueToTable(const char *sDeviceName, const AQH_VALUE *value, uint32_t perms, GWEN_BUFFER *dbuf)
{
const char *s;
GBAS(dbuf, "<tr>");
/* name for system */
s=AQH_Value_GetName(value);
if (perms & AQH_MODDEVICES_PERMS_VALUEREAD) {
uint32_t pos;
pos=GWEN_Buffer_GetPos(dbuf);
GBAS(dbuf,"<td><a href=\"value.html?device=");
GWEN_Text_EscapeToBuffer(sDeviceName, dbuf);
GBAS(dbuf,"&value=");
GWEN_Text_EscapeToBuffer(s, dbuf);
GBAA(dbuf,"\">%s</a></td>", s);
}
else
GBAA(dbuf,"<td>%s</td>", s?s:"");
s=AQH_ValueType_toString(AQH_Value_GetValueType(value));
GBAA(dbuf, "<td>%s</td>", s?s:"");
s=AQH_ValueModality_toString(AQH_Value_GetModality(value));
GBAA(dbuf, "<td>%s</td>", s?s:"");
GBAA(dbuf, "</tr>\n");
}

View File

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

View File

@@ -1,279 +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 <config.h>
#endif
#include "./mdevices_vgraph.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/mdataclient.h"
#include <aqdiagram/graph/timegraph.h>
#include <aqdiagram/graph/w_graph.h>
#include <aqdiagram/draw/context_cairo.h>
//#include <aqdiagram/data/date.h>
//#include <aqdiagram/data/floatingavg.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define GBAS GWEN_Buffer_AppendString
#define GBAA GWEN_Buffer_AppendArgs
/* ------------------------------------------------------------------------------------------------
* 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
* ------------------------------------------------------------------------------------------------
*/
static void _runGraphValueWithArgs(AQH_MODULE *m,
AQCGI_REQUEST *rq,
AQH_DATACLIENT *dc,
const char *sDeviceName,
const char *sValueName,
GWEN_BUFFER *dbuf);
static void _createGraph(AQH_DATACLIENT *dc,
const AQH_VALUE *v,
const MY_GRAPH_PARAMS *graphParams,
const char *graphTitle, int precision, const char *curveLabel,
const char *sImgFile, int imgWidth, int imgHeight, uint64_t numDataPoints);
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 const MY_GRAPH_PARAMS *_getParamsByName(const char *s);
/* ------------------------------------------------------------------------------------------------
* 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_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_DEBUG(NULL, "Device=%s, value=%s", sDeviceName?sDeviceName:"<empty>", sValueName?sValueName:"<empty>");
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, 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_DATACLIENT *dc,
const char *sDeviceName,
const char *sValueName,
GWEN_BUFFER *dbuf)
{
GWEN_DB_NODE *dbQuery;
AQH_VALUE *value;
const MY_GRAPH_PARAMS *graphParams;
const char *sPeriod;
DBG_DEBUG(NULL, "GraphValue with args");
dbQuery=AQCGI_Request_GetDbQuery(rq);
sPeriod=GWEN_DB_GetCharValue(dbQuery, "period", 0, NULL);
graphParams=_getParamsByName(sPeriod);
if (graphParams==NULL)
graphParams=&_graphParams[0];
DBG_DEBUG(NULL, "Device=%s, value=%s, period=%s",
sDeviceName?sDeviceName:"<empty>", sValueName?sValueName:"<empty>",
sPeriod?sPeriod:"<empty>");
value=AQH_ModDevices_GetValueForDevice(dc, sDeviceName, sValueName);
if (value) {
GWEN_BUFFER *fbuf;
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
_mkPathForValueAndPeriod(m, value, graphParams, fbuf);
if (!AQH_ModService_FileIsCurrent(GWEN_Buffer_GetStart(fbuf), graphParams->acceptedAgeInSeconds)) {
DBG_DEBUG(NULL, "Creating graph");
_createGraph(dc,
value,
graphParams,
sValueName,
2,
AQH_ValueModality_toString(AQH_Value_GetModality(value)),
GWEN_Buffer_GetStart(fbuf),
AQH_MODDEVICES_GRAPH_WIDTH, AQH_MODDEVICES_GRAPH_HEIGHT,
100000);
}
AQH_ModService_RespondWithMimeFile(rq, GWEN_Buffer_GetStart(fbuf), "image/png", dbuf);
GWEN_Buffer_free(fbuf);
AQH_Value_free(value);
}
else {
DBG_ERROR(NULL, "Could not get value \"%s/%s\"", sDeviceName, sValueName);
}
}
void _createGraph(AQH_DATACLIENT *dc,
const AQH_VALUE *v,
const MY_GRAPH_PARAMS *graphParams,
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;
AQDG_GRAPH_DATAPAIR_LIST *dpList;
sValue=AQH_Value_GetNameForSystem(v);
tsEnd=time(0);
tsBegin=time(0)-(graphParams->startTimeDiff);
g=_mkGraphObjectWithTitle(graphTitle, graphParams, precision);
dpList=AQH_ModDevices_RequestDataPairList(dc, sValue, tsBegin, tsEnd, numDataPoints);
if (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 for %s", sValue);
AQDG_Graph_free(g);
return;
}
AQDG_TimeGraph_SetupTicks(g, 0, 0.0, 0.0);
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);
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, const MY_GRAPH_PARAMS *graphParams, int precision)
{
AQDG_GRAPH *g;
GWEN_BUFFER *tbuf;
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GBAA(tbuf, "%s - %s", graphTitle, graphParams->title);
g=AQDG_TimeGraph_new(GWEN_Buffer_GetStart(tbuf), NULL, "Value", NULL, precision);
GWEN_Buffer_free(tbuf);
return g;
}
void _mkPathForValueAndPeriod(AQH_MODULE *m, const AQH_VALUE *v, const MY_GRAPH_PARAMS *graphParams, 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);
AQH_ModService_EscapeToBuffer(s, dbuf);
GBAA(dbuf, "-%s.png", graphParams->name);
}
const MY_GRAPH_PARAMS *_getParamsByName(const char *s)
{
const MY_GRAPH_PARAMS *p;
p=_graphParams;
while(p->name) {
if (strcasecmp(p->name, s)==0)
return p;
p++;
}
return NULL;
}

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1013 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 834 B

View File

@@ -1,63 +0,0 @@
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;
}

View File

@@ -1,102 +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 <config.h>
#endif
#include "./mdataclient.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* global vars
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModDataClient_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder)
{
AQH_ModService_Extend(m, sv, baseFolder);
}
void AQH_ModDataClient_HandleRequest(AQH_MODULE *m,
AQCGI_REQUEST *rq,
AQH_SESSION *session,
AQH_MODDATACLIENT_RUN_FN runFn,
GWEN_BUFFER *dbuf)
{
AQH_EVENT_LOOP *eventLoop;
AQH_DATACLIENT *dc;
int rv;
rv=AQH_Init();
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQCGI_Request_SetResponseCode(rq, 500);
AQCGI_Request_SetResponseText(rq, "Internal Error");
return;
}
eventLoop=AQH_EventLoop_new();
dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION);
rv=AQH_DataClient_ReadConfigFile(dc);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQCGI_Request_SetResponseCode(rq, 500);
AQCGI_Request_SetResponseText(rq, "Internal Error");
return;
}
rv=AQH_DataClient_ConnectWithArgs(dc, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
AQCGI_Request_SetResponseCode(rq, 500);
AQCGI_Request_SetResponseText(rq, "Internal Error");
return;
}
if (runFn)
runFn(m, rq, session, dc, dbuf);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
AQH_Fini();
}

View File

@@ -1,37 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MDATACLIENT_H
#define AQHOME_CGI_MDATACLIENT_H
#include <aqhome-cgi/modules/common/mservice.h>
#include <aqcgi/request.h>
#include "aqhome/aqhome.h"
#include "aqhome/dataclient/client.h"
#include <gwenhywfar/buffer.h>
typedef void (*AQH_MODDATACLIENT_RUN_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, AQH_DATACLIENT *dc, GWEN_BUFFER *dbuf);
void AQH_ModDataClient_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder);
void AQH_ModDataClient_HandleRequest(AQH_MODULE *m,
AQCGI_REQUEST *rq,
AQH_SESSION *session,
AQH_MODDATACLIENT_RUN_FN runFn,
GWEN_BUFFER *dbuf);
#endif

View File

@@ -1,326 +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 <config.h>
#endif
#include "./mroot_p.h"
#include "aqhome-cgi/service/module.h"
#include "aqhome-cgi/modules/devices/mdevices.h"
#include "aqhome-cgi/modules/common/madmin.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/timestamp.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* global vars
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* 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 int _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf);
static int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf);
static int _handleRqLoginPost(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf);
static AQH_USER *_getAndCheckUser(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder)
{
AQH_MODULE *m;
m=AQH_Module_new();
AQH_ModService_Extend(m, sv, baseFolder);
AQH_ModService_SetHandleRequestFn(m, _handleRequest);
AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule);
return m;
}
AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName)
{
AQH_SERVICE *sv;
sv=AQH_ModService_GetService(m);
if (strcasecmp(sModuleName, "devices")==0) {
AQH_MODULE *mSub;
mSub=AQH_Service_LoadModule(sv, sModuleName);
if (mSub) {
const char *s;
GWEN_BUFFER *nbuf;
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
s=AQH_ModService_GetBaseFolder(m);
GWEN_Buffer_AppendArgs(nbuf, "%s/devices", s?s:".");
AQH_ModDevices_Extend(mSub, AQH_ModService_GetService(m), GWEN_Buffer_GetStart(nbuf));
AQH_Module_Tree2_AddChild(m, mSub);
GWEN_Buffer_free(nbuf);
return mSub;
}
}
else if (strcasecmp(sModuleName, "admin")==0) {
AQH_MODULE *mSub;
mSub=AQH_Service_LoadModule(sv, sModuleName);
if (mSub) {
const char *s;
GWEN_BUFFER *nbuf;
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
s=AQH_ModService_GetBaseFolder(m);
GWEN_Buffer_AppendArgs(nbuf, "%s/devices", s?s:".");
AQH_ModAdmin_Extend(mSub, AQH_ModService_GetService(m), GWEN_Buffer_GetStart(nbuf));
AQH_Module_Tree2_AddChild(m, mSub);
GWEN_Buffer_free(nbuf);
return mSub;
}
}
return NULL;
}
int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem)
{
GWEN_BUFFER *dbuf;
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
AQH_ModService_AddHeader(m, "en", dbuf);
if (strcasecmp(sLastPathElem, "login")==0)
_handleRqLogin(m, rq, dbuf);
else if (strcasecmp(sLastPathElem, "signup")==0) {
AQCGI_Request_SetResponseCode(rq, 501);
AQCGI_Request_SetResponseText(rq, "Not Implemented");
}
else if (strcasecmp(sLastPathElem, "confirm")==0) {
AQCGI_Request_SetResponseCode(rq, 501);
AQCGI_Request_SetResponseText(rq, "Not Implemented");
}
else if (strcasecmp(sLastPathElem, "index.html")==0)
_handleRqIndex(m, rq, dbuf);
else {
AQCGI_Request_SetResponseCode(rq, 404);
AQCGI_Request_SetResponseText(rq, "Not Found");
}
AQH_ModService_AddFooter(m, "en", dbuf);
AQCGI_Request_SetBufferResponseBody(rq, dbuf);
AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html");
return AQCGI_SendResponse(rq);
}
int _handleRqIndex(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf)
{
if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_GET)
return AQH_ModService_RespondWithFile(m, rq, "en", "index.html", dbuf);
else {
DBG_ERROR(NULL, "Invalid request method %d", AQCGI_Request_GetRequestMethod(rq));
AQCGI_Request_SetResponseCode(rq, 405);
AQCGI_Request_SetResponseText(rq, "Method Not Allowed");
return GWEN_ERROR_GENERIC;
}
}
int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf)
{
if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_GET)
AQH_ModService_RespondWithFile(m, rq, "en", "login.html", dbuf);
else if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_POST)
_handleRqLoginPost(m, rq, dbuf);
else {
DBG_ERROR(NULL, "Invalid request method %d", AQCGI_Request_GetRequestMethod(rq));
AQCGI_Request_SetResponseCode(rq, 405);
AQCGI_Request_SetResponseText(rq, "Method Not Allowed");
return GWEN_ERROR_GENERIC;
}
return 0;
}
int _handleRqLoginPost(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf)
{
AQH_SERVICE *sv;
AQH_USER *user;
AQH_SESSION *session;
GWEN_BUFFER *tbuf;
GWEN_TIMESTAMP *ts;
int rv;
DBG_ERROR(NULL, "Handling request");
sv=AQH_ModService_GetService(m);
user=_getAndCheckUser(m, rq, dbuf);
if (user==NULL) {
DBG_INFO(NULL, "here");
AQCGI_Request_SetResponseCode(rq, 500);
AQCGI_Request_SetResponseText(rq, "Internal Error");
return GWEN_ERROR_GENERIC;
}
ts=GWEN_Timestamp_NowInLocalTime();
AQH_User_SetTimestampLastLogin(user, ts);
DBG_ERROR(NULL, "Saving user");
rv=AQH_Service_SaveUser(sv, user);
if (rv<0) {
DBG_ERROR(NULL, "Error saving user \"%s\"", AQH_User_GetAlias(user));
AQCGI_Request_SetResponseCode(rq, 500);
AQCGI_Request_SetResponseText(rq, "Internal Error");
AQH_User_free(user);
return rv;
}
/* generate session */
DBG_ERROR(NULL, "Generating session");
tbuf=GWEN_Buffer_new(0, 64, 0, 1);
AQCGI_GenerateSessionId(tbuf);
session=AQH_Session_new();
AQH_Session_SetTimestampCreation(session, ts);
AQH_Session_SetTimestampLastAccess(session, ts);
AQH_Session_SetUid(session, GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
AQH_Session_SetUserAlias(session, AQH_User_GetAlias(user));
rv=AQH_Service_AddSession(sv, session);
if (rv<0) {
DBG_ERROR(NULL, "Error adding session for user \"%s\" (%d)", AQH_User_GetAlias(user), rv);
AQCGI_Request_SetResponseCode(rq, 500);
AQCGI_Request_SetResponseText(rq, "Internal Error");
AQH_Session_free(session);
AQH_User_free(user);
return GWEN_ERROR_INTERNAL;
}
/* add Set-Cookie header */
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(tbuf, "Set-Cookie: session=%s; max-age=86400", AQH_Session_GetUid(session));
AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(tbuf));
GWEN_Buffer_free(tbuf);
/* finish */
AQCGI_Request_AddResponseHeaderData(rq, "Location: index.html");
AQCGI_Request_SetResponseCode(rq, 303);
AQCGI_Request_SetResponseText(rq, "See other");
AQH_Session_free(session);
AQH_User_free(user);
return 0;
}
AQH_USER *_getAndCheckUser(AQH_MODULE *m, AQCGI_REQUEST *rq, GWEN_BUFFER *dbuf)
{
GWEN_DB_NODE *dbPost;
dbPost=AQCGI_Request_GetDbPostBody(rq);
if (dbPost) {
AQH_SERVICE *sv;
const char *sUserName;
const char *sPasswd;
AQH_USER *user;
const char *hashedPaswd;
GWEN_BUFFER *buf;
sv=AQH_ModService_GetService(m);
sUserName=GWEN_DB_GetCharValue(dbPost, "userid", 0, NULL);
sPasswd=GWEN_DB_GetCharValue(dbPost, "password", 0, NULL);
if (!(sUserName && *sUserName && sPasswd && *sPasswd)) {
DBG_ERROR(NULL, "Either user name or password missing");
AQCGI_Request_SetResponseCode(rq, 400);
AQCGI_Request_SetResponseText(rq, "Bad Request");
return NULL;
}
DBG_ERROR(NULL, "Loading user \"%s\" (%p)", sUserName, sv);
user=AQH_Service_LoadUser(sv, sUserName);
if (user==NULL) {
DBG_ERROR(NULL, "User \"%s\" not found", sUserName);
AQCGI_Request_SetResponseCode(rq, 403);
AQCGI_Request_SetResponseText(rq, "Forbidden");
return NULL;
}
DBG_ERROR(NULL, "Loaded user \"%s\"", sUserName);
if (AQH_User_GetState(user)!=AQH_UserState_Active) {
DBG_ERROR(NULL, "User \"%s\" not active", sUserName);
AQCGI_Request_SetResponseCode(rq, 403);
AQCGI_Request_SetResponseText(rq, "Forbidden");
AQH_User_free(user);
return NULL;
}
hashedPaswd=AQH_User_GetHashedPassword(user);
if (!(hashedPaswd && *hashedPaswd)) {
DBG_ERROR(NULL, "User \"%s\" has no hashed password", sUserName);
AQCGI_Request_SetResponseCode(rq, 403);
AQCGI_Request_SetResponseText(rq, "Forbidden");
AQH_User_free(user);
return NULL;
}
buf=GWEN_Buffer_new(0, 256, 0, 1);
AQCGI_HashMd256ToBuffer(sPasswd, buf);
DBG_ERROR(NULL, "Password: [%s]", sPasswd); // TODO: Remove!!!
DBG_ERROR(NULL, "Hashed password: [%s]", GWEN_Buffer_GetStart(buf));
if (strcasecmp(GWEN_Buffer_GetStart(buf), hashedPaswd)!=0) {
DBG_ERROR(NULL, "Bad password for user \"%s\"", sUserName);
AQCGI_Request_SetResponseCode(rq, 403);
AQCGI_Request_SetResponseText(rq, "Forbidden");
GWEN_Buffer_free(buf);
AQH_User_free(user);
return NULL;
}
GWEN_Buffer_free(buf);
DBG_ERROR(NULL, "User \"%s\" accepted", sUserName);
return user;
}
else {
DBG_ERROR(NULL, "No POST data");
AQCGI_SendResponseWithStatus(rq, 400, "Bad Request");
AQCGI_Request_SetResponseCode(rq, 400);
AQCGI_Request_SetResponseText(rq, "Bad Request");
return NULL;
}
}

View File

@@ -1,27 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MROOT_H
#define AQHOME_CGI_MROOT_H
#include <aqhome-cgi/modules/common/mservice.h>
#include <aqcgi/request.h>
#include <gwenhywfar/buffer.h>
AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder);
AQH_MODULE *AQH_ModRoot_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
int AQH_ModRoot_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
#endif

View File

@@ -1,18 +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.
****************************************************************************/
#ifndef AQHOME_CGI_MROOT_P_H
#define AQHOME_CGI_MROOT_P_H
#include "aqhome-cgi/modules/mroot.h"
#endif

View File

@@ -1,14 +0,0 @@
<?xml?>
<gwbuild>
<data dist="true" install="$(httpdatadir)/aqhome-cgi/static/en">
header.html
footer.html
login.html
index.html
</data>
</gwbuild>

View File

@@ -1,4 +0,0 @@
</body>
</html>

View File

@@ -1,27 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<!-- copyright (c) 2025 by martin@libchipcard.de -->
<meta name="generator" content="FTE 1.1" />
<meta name="revised" content="martin,2025-06-12" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="author" content="martin" />
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<link rel="stylesheet" href="/style.css" >
<title>AqHome</title>
</head>
<ul class="mainmenu" >
<li><a href="/aqhome/devices/index.html">Devices</a></li>
<li><a href="/aqhome/devices/page.html">Pages</a></li>
<li><a href="/aqhome/admin/index.html">Admin</a></li>
<li><a href="#news">News</a></li>
<li><a href="#contact">Contact</a></li>
<li style="float:right"><a href="/aqhome/login">Login</a></li>
</ul>
<body>

View File

@@ -1,6 +0,0 @@
<h1> AqHome Main Page </h1>
<p>Nothing to see for now</p>

View File

@@ -1,25 +0,0 @@
<div class="main">
<h1>AqHome</h1>
<h3>Enter your login credentials</h3>
<form action="login" method="post">
<label for="userid">Username:</label>
<input type="text" id="userid" name="userid" placeholder="Enter your Username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" placeholder="Enter your Password" required>
<div class="wrap">
<button type="submit">Submit</button>
</div>
</form>
<p>Not registered?
<a href="signup" style="text-decoration: none;">
Create an account
</a>
</p>
</div>
</body>
</html>

View File

@@ -1,63 +0,0 @@
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;
}

View File

@@ -20,7 +20,7 @@
</includes>
<define name="not_BUILDING_AQHOME" />
<define name="BUILDING_AQHOME" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>

View File

@@ -46,7 +46,7 @@
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember sortbymember</flags>
<flags>with_getbymember</flags>
</member>
<member name="flags" type="uint32_t" maxlen="4">
@@ -60,7 +60,7 @@
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>own with_getbymember sortbymember</flags>
<flags>own with_getbymember</flags>
</member>
<member name="descr" type="char_ptr" maxlen="256">

View File

@@ -31,21 +31,21 @@
<members>
<member name="moduleId" type="char_ptr" maxlen="256">
<member name="moduleId" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember sortbymember</flags>
<flags>with_getbymember</flags>
</member>
<member name="explAddPerms" type="uint32_t" maxlen="4">
<member name="exclAddPerms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags></flags>
</member>
<member name="explDelPerms" type="uint32_t" maxlen="4">
<member name="exclDelPerms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
@@ -59,6 +59,14 @@
<flags></flags>
</member>
<member name="perms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>volatile</flags>
</member>
</members>
</type>

View File

@@ -43,13 +43,6 @@
<flags>own</flags>
</member>
<member name="descr" type="char_ptr" maxlen="256">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>own</flags>
</member>
<member name="perms" type="uint32_t" maxlen="4">
<default>0</default>
<preset>0</preset>

View File

@@ -27,7 +27,7 @@ GWEN_LIST_FUNCTIONS(AQH_SERVICE, AQH_Service);
AQH_SERVICE *AQH_Service_new(const char *baseFolder, const char *baseUrl)
AQH_SERVICE *AQH_Service_new(void)
{
AQH_SERVICE *sv;
@@ -35,32 +35,6 @@ AQH_SERVICE *AQH_Service_new(const char *baseFolder, const char *baseUrl)
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;
}
@@ -72,44 +46,11 @@ 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)
{

View File

@@ -52,13 +52,10 @@ typedef GWEN_STRINGLIST* (*AQH_SERVICE_LISTSESSIONS_FN)(AQH_SERVICE *sv);
AQH_SERVICE *AQH_Service_new(const char *baseFolder, const char *baseUrl);
AQH_SERVICE *AQH_Service_new(void);
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);

View File

@@ -17,11 +17,6 @@ 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;

View File

@@ -32,10 +32,6 @@
</lang>
<defines>
<define id="AQH_USER_FLAGS" prefix="AQH_USER_FLAGS_">
<item name="ADMIN" value="0x00000001" />
</define>
<define id="AQH_USER_RTFLAGS" prefix="AQH_USER_RTFLAGS_">
<item name="MODIFIED" value="0x00000001" />
<item name="PERMSCALC" value="0x00000002" />
@@ -58,10 +54,6 @@
<descr>Waiting for approval by admin</descr>
</item>
<item name="active">
<descr>User active</descr>
</item>
</enum>
</enums>
@@ -73,7 +65,7 @@
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getbymember sortbymember</flags>
<flags>with_getbymember</flags>
</member>
<member name="flags" type="uint32_t" maxlen="4">
@@ -87,21 +79,21 @@
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>sortbymember</flags>
<flags></flags>
</member>
<member name="name" type="char_ptr" maxlen="16">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>own sortbymember</flags>
<flags>own</flags>
</member>
<member name="alias" type="char_ptr" maxlen="16">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>own with_getbymember sortbymember</flags>
<flags>own with_getbymember</flags>
</member>
<member name="hashedPassword" type="char_ptr" maxlen="128">
@@ -115,7 +107,7 @@
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>own with_getbymember sortbymember</flags>
<flags>own</flags>
</member>
<member name="notes" type="char_ptr" maxlen="256">
@@ -129,14 +121,14 @@
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own sortbymember</flags>
<flags>own</flags>
</member>
<member name="timestampLastLogin" type="gwen_timestamp" maxlen="8">
<default>NULL</default>
<preset>NULL</preset>
<access>public</access>
<flags>own sortbymember</flags>
<flags>own</flags>
</member>
<member name="modulePermList" type="AQH_MODULE_PERMS_LIST">

View File

@@ -70,8 +70,6 @@ static int _addGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *s
static int _deleteGroup(AQH_SERVICE *sv, const char *groupName, const char *subGroupName);
static GWEN_STRINGLIST *_listGroup(AQH_SERVICE *sv, const char *groupName);
//static void _logGroup(const char *groupName, const char *subGroupName, GWEN_DB_NODE *db);
/* ------------------------------------------------------------------------------------------------
@@ -79,15 +77,16 @@ static GWEN_STRINGLIST *_listGroup(AQH_SERVICE *sv, const char *groupName);
* ------------------------------------------------------------------------------------------------
*/
AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder, const char *baseUrl)
AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder)
{
AQH_SERVICE *sv;
AQH_SERVICE_FILE *xs;
GWEN_BUFFER *dbuf;
sv=AQH_Service_new(baseFolder, baseUrl);
sv=AQH_Service_new();
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);
@@ -108,7 +107,7 @@ AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder, const char *baseUrl)
AQH_Service_SetListSessionsFn(sv, _listSessions);
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(dbuf, "dir://%s", AQH_Service_GetRuntimeFolder(sv));
GWEN_Buffer_AppendArgs(dbuf, "dir://%s", baseFolder);
DBG_ERROR(NULL, "Creating config mgr \"%s\"", GWEN_Buffer_GetStart(dbuf));
xs->configMgr=GWEN_ConfigMgr_Factory(GWEN_Buffer_GetStart(dbuf));
if (xs->configMgr==NULL) {
@@ -130,6 +129,7 @@ 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);
}
@@ -169,9 +169,6 @@ int _saveUser(AQH_SERVICE *sv, AQH_USER *user)
GWEN_DB_Group_free(db);
return rv;
}
//_logGroup(AQH_SERVICE_FILE_GROUP_USERS, s, db);
rv=_saveGroupLocked(sv, AQH_SERVICE_FILE_GROUP_USERS, s, db);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
@@ -211,9 +208,6 @@ int _addUser(AQH_SERVICE *sv, AQH_USER *user)
GWEN_DB_Group_free(db);
return 0;
}
else {
DBG_ERROR(NULL, "Missing alias");
}
return GWEN_ERROR_INVALID;
}
@@ -420,7 +414,6 @@ GWEN_STRINGLIST *_listSessions(AQH_SERVICE *sv)
GWEN_DB_NODE *_loadGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroupName)
{
DBG_ERROR(NULL, "Lock and load group %s/%s", groupName, subGroupName);
if (sv && groupName && subGroupName) {
AQH_SERVICE_FILE *xs;
@@ -429,20 +422,17 @@ GWEN_DB_NODE *_loadGroupLocked(AQH_SERVICE *sv, const char *groupName, const cha
GWEN_DB_NODE *db=NULL;
int rv;
DBG_ERROR(NULL, "Locking group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_LockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error locking group \"%s/%s\": %d", groupName, subGroupName, rv);
return NULL;
}
DBG_ERROR(NULL, "Loading group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_GetGroup(xs->configMgr, groupName, subGroupName, &db);
if (rv<0) {
DBG_ERROR(NULL, "Error reading group \"%s/%s\": %d", groupName, subGroupName, rv);
GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
return NULL;
}
DBG_ERROR(NULL, "Unlocking group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
@@ -452,9 +442,6 @@ GWEN_DB_NODE *_loadGroupLocked(AQH_SERVICE *sv, const char *groupName, const cha
return db;
}
}
else {
DBG_ERROR(NULL, "Missing argument");
}
return NULL;
}
@@ -467,26 +454,25 @@ int _saveGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGrou
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
if (xs) {
GWEN_DB_NODE *db=NULL;
int rv;
DBG_ERROR(NULL, "Locking group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_LockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error locking group \"%s/%s\": %d", groupName, subGroupName, rv);
return rv;
}
DBG_ERROR(NULL, "Writing group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_SetGroup(xs->configMgr, groupName, subGroupName, db);
if (rv<0) {
DBG_ERROR(NULL, "Error writing group \"%s/%s\": %d", groupName, subGroupName, rv);
return rv;
}
DBG_ERROR(NULL, "Unlocking group %s/%s", groupName, subGroupName);
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
GWEN_DB_Group_free(db);
return rv;
}
@@ -505,6 +491,7 @@ int _addGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroup
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
if (xs) {
GWEN_DB_NODE *db=NULL;
int rv;
rv=GWEN_ConfigMgr_HasGroup(xs->configMgr, groupName, subGroupName);
@@ -528,6 +515,7 @@ int _addGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroup
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
if (rv<0) {
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
GWEN_DB_Group_free(db);
return rv;
}
@@ -589,24 +577,3 @@ GWEN_STRINGLIST *_listGroup(AQH_SERVICE *sv, const char *groupName)
}
#if 0
void _logGroup(const char *groupName, const char *subGroupName, GWEN_DB_NODE *db)
{
if (db) {
GWEN_BUFFER *dbuf;
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_DB_WriteToBuffer(db, dbuf, GWEN_DB_FLAGS_DEFAULT);
DBG_ERROR(NULL, "Group %s/%s:\n%s", groupName?groupName:"<empty>", subGroupName?subGroupName:"<empty>",
GWEN_Buffer_GetStart(dbuf));
GWEN_Buffer_free(dbuf);
}
else {
DBG_ERROR(NULL, "Group %s/%s empty", groupName?groupName:"<empty>", subGroupName?subGroupName:"<empty>");
}
}
#endif

View File

@@ -13,7 +13,6 @@
#include "aqhome-cgi/service/service.h"
AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder, const char *baseUrl);

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
* 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.
@@ -18,6 +18,7 @@
typedef struct AQH_SERVICE_FILE AQH_SERVICE_FILE;
struct AQH_SERVICE_FILE {
char *baseFolder;
GWEN_CONFIGMGR *configMgr;
};

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
* 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.
@@ -33,8 +33,8 @@
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 1024
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 512
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 2048
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 1024
/* ------------------------------------------------------------------------------------------------
@@ -44,15 +44,13 @@
static int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value,
int mode,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId);
static int _getAndSendDataPointsPeriod(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
static int _getAndSendDataPointsNoNum(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
uint32_t refMsgId);
static int _getAndSendDataPointsFirst(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
static int _getAndSendDataPointsLast(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
static int _getAndSendDataPointsWithNum(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
static void _sendDataPointsResponse(AQH_OBJECT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
uint32_t refMsgId);
static void _getAndSendLastDatapoint(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint32_t refMsgId);
@@ -81,18 +79,16 @@ void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const A
uint64_t tsBegin;
uint64_t tsEnd;
uint64_t numRequested;
int mode;
tsBegin=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0);
tsEnd=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_END, 0);
numRequested=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_NUM, 0);
mode=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_MODE, AQH_MSGDATA_GETDATA_MODE_FIRST);
value=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName);
if (value) {
int resultCode;
resultCode=_getAndSendDataPoints(xo->storage, ep, value, mode, tsBegin, tsEnd, numRequested, refMsgId);
resultCode=_getAndSendDataPoints(xo->storage, ep, value, tsBegin, tsEnd, numRequested, refMsgId);
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, resultCode);
}
else {
@@ -118,73 +114,54 @@ void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const A
int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value,
int mode,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
uint32_t refMsgId)
{
switch(mode) {
case AQH_MSGDATA_GETDATA_MODE_FIRST: return _getAndSendDataPointsFirst(storage, ep, value, num, refMsgId);
case AQH_MSGDATA_GETDATA_MODE_PERIOD: return _getAndSendDataPointsPeriod(storage, ep, value, tsBegin, tsEnd, num, refMsgId);
default:
case AQH_MSGDATA_GETDATA_MODE_LAST: return _getAndSendDataPointsLast(storage, ep, value, num, refMsgId);
}
}
int _getAndSendDataPointsPeriod(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
uint32_t refMsgId)
{
uint64_t valueId;
uint64_t *tablePtr;
valueId=AQH_Value_GetId(value);
tablePtr=AQH_Storage_GetDataPoints(storage, valueId, tsBegin, tsEnd, num);
if (tablePtr) {
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
free(tablePtr);
if (num==0)
return _getAndSendDataPointsNoNum(storage, ep, value, tsBegin, tsEnd, refMsgId);
else if (num==1) {
_getAndSendLastDatapoint(storage, ep, value, refMsgId);
return AQH_MSGDATA_RESULT_SUCCESS;
}
else {
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
return AQH_MSGDATA_RESULT_ERROR_NODATA;
}
else
return _getAndSendDataPointsWithNum(storage, ep, value, num, refMsgId);
}
int _getAndSendDataPointsLast(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t num,
uint32_t refMsgId)
{
uint64_t valueId;
uint64_t *tablePtr;
valueId=AQH_Value_GetId(value);
tablePtr=AQH_Storage_GetLastNDataPoints(storage, valueId, num);
if (tablePtr) {
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
free(tablePtr);
return AQH_MSGDATA_RESULT_SUCCESS;
}
else {
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
return AQH_MSGDATA_RESULT_ERROR_NODATA;
}
}
int _getAndSendDataPointsFirst(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t num,
int _getAndSendDataPointsNoNum(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
uint32_t refMsgId)
{
uint64_t valueId;
uint64_t *tablePtr;
valueId=AQH_Value_GetId(value);
tablePtr=AQH_Storage_GetFirstNDataPoints(storage, valueId, num);
tablePtr=AQH_Storage_GetDataPoints(storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES);
if (tablePtr) {
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
free(tablePtr);
return AQH_MSGDATA_RESULT_SUCCESS;
}
else {
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
return AQH_MSGDATA_RESULT_ERROR_NODATA;
}
}
int _getAndSendDataPointsWithNum(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint64_t num,
uint32_t refMsgId)
{
uint64_t valueId;
uint64_t *tablePtr;
if (num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS)
num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS;
valueId=AQH_Value_GetId(value);
tablePtr=AQH_Storage_GetLastNDataPoints(storage, valueId, num);
if (tablePtr) {
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
free(tablePtr);
@@ -204,29 +181,48 @@ void _sendDataPointsResponse(AQH_OBJECT *ep,
{
int numTableEntries;
int numDataPoints;
AQH_MESSAGE *outMsg;
numTableEntries=(int)(tablePtr[0]);
numDataPoints=numTableEntries/2;
tablePtr++;
outMsg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
AQH_Endpoint_GetNextMessageId(ep), refMsgId,
value, &(tablePtr[1]), numDataPoints);
AQH_Endpoint_AddMsgOut(ep, outMsg);
}
while(numDataPoints) {
void _getAndSendLastDatapoint(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value, uint32_t refMsgId)
{
int rv;
uint64_t timestamp=0;
double data=0.0;
rv=AQH_Storage_GetLastDataPoint(storage, AQH_Value_GetId(value), &timestamp, &data);
if (rv<0) {
int resultCode;
switch(rv) {
case GWEN_ERROR_INVALID: resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID; break;
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSGDATA_RESULT_ERROR_NODATA; break;
default: resultCode=AQH_MSGDATA_RESULT_ERROR_GENERIC; break;
}
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, resultCode);
}
else {
AQH_MESSAGE *outMsg;
int toSend;
uint32_t flags=0;
toSend=numDataPoints;
if (toSend>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS)
toSend=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS;
numDataPoints-=toSend;
if (numDataPoints==0)
flags|=AQH_MSGDATA_MULTIDATA_FLAGS_LASTMSG;
outMsg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
AQH_Endpoint_GetNextMessageId(ep), refMsgId, flags,
value, tablePtr, toSend);
tablePtr+=(toSend*2);
outMsg=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
AQH_Endpoint_GetNextMessageId(ep), refMsgId,
value, timestamp, data);
AQH_Endpoint_AddMsgOut(ep, outMsg);
}
}

View File

@@ -16,13 +16,11 @@
#include "aqhome/ipc2/endpoint.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdevices.h"
#include "aqhome/msg/ipc/data/m_ipcd_devices.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
@@ -40,10 +38,7 @@
* ------------------------------------------------------------------------------------------------
*/
static AQH_DEVICE_LIST *_getMatchingDeviceList(AQHOME_SERVER *xo, const GWEN_TAG16_LIST *tagList);
static int _deviceMatches(const AQH_DEVICE *dev, const char *deviceName);
static void _sendDeviceList(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t refMsgId);
static void _sendDeviceListMsg(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId);
static void _sendDeviceList(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId);
@@ -52,114 +47,63 @@ static void _sendDeviceListMsg(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleGetDevices(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
void AqHomeDataServer_HandleGetDevices(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, GWEN_UNUSED const GWEN_TAG16_LIST *tagList)
{
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
AQH_DEVICE_LIST *deviceList;
const AQH_DEVICE_LIST *origDeviceList;
uint32_t refMsgId;
refMsgId=AQH_IpcMessage_GetMsgId(msg);
DBG_INFO(NULL, "HandleGetDevices");
deviceList=_getMatchingDeviceList(xo, tagList);
if (deviceList) {
_sendDeviceList(ep, deviceList, refMsgId);
AQH_Device_List_free(deviceList);
origDeviceList=AQH_Storage_GetDeviceList(xo->storage);
if (origDeviceList) {
DBG_INFO(NULL, "Have a list of %d devices", AQH_Device_List_GetCount(origDeviceList));
if (AQH_Device_List_GetCount(origDeviceList)<AQHOMEDATA_DEVICESPERMSG) {
DBG_INFO(NULL, "Sending all entries in one message");
_sendDeviceList(ep, origDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
}
else {
AQH_DEVICE_LIST *tmpDeviceList;
const AQH_DEVICE *v;
DBG_INFO(NULL, "Sending entries in multiple messages");
tmpDeviceList=AQH_Device_List_new();
v=AQH_Device_List_First(origDeviceList);
while(v) {
const AQH_DEVICE *next;
AQH_DEVICE *copyOfDevice;
next=AQH_Device_List_Next(v);
copyOfDevice=AQH_Device_dup(v);
AQH_Device_List_Add(copyOfDevice, tmpDeviceList);
if (AQH_Device_List_GetCount(tmpDeviceList)>=AQHOMEDATA_DEVICESPERMSG) {
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
_sendDeviceList(ep, tmpDeviceList, next?0:AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
AQH_Device_List_Clear(tmpDeviceList);
}
v=next;
}
if (AQH_Device_List_GetCount(tmpDeviceList)) {
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
_sendDeviceList(ep, tmpDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId); /* send remaining */
}
AQH_Device_List_free(tmpDeviceList);
}
}
else {
/* empty list */
_sendDeviceListMsg(ep, NULL, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
_sendDeviceList(ep, NULL, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
}
}
}
AQH_DEVICE_LIST *_getMatchingDeviceList(AQHOME_SERVER *xo, const GWEN_TAG16_LIST *tagList)
{
const AQH_DEVICE_LIST *origDeviceList;
AQH_DEVICE_LIST *tmpDeviceList=NULL;
char *deviceName;
deviceName=tagList?AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETDEVICES_TAGS_DEVICENAME, NULL):NULL;
origDeviceList=AQH_Storage_GetDeviceList(xo->storage);
if (origDeviceList) {
const AQH_DEVICE *dev;
tmpDeviceList=AQH_Device_List_new();
dev=AQH_Device_List_First(origDeviceList);
while(dev) {
if (_deviceMatches(dev, deviceName)) {
AQH_DEVICE *copyOfDevice;
copyOfDevice=AQH_Device_dup(dev);
AQH_Device_List_Add(copyOfDevice, tmpDeviceList);
}
dev=AQH_Device_List_Next(dev);
}
if (AQH_Device_List_GetCount(tmpDeviceList)<1) {
AQH_Device_List_free(tmpDeviceList);
tmpDeviceList=NULL;
}
}
free(deviceName);
return tmpDeviceList;
}
int _deviceMatches(const AQH_DEVICE *dev, const char *deviceName)
{
if (deviceName && *deviceName) {
const char *s;
s=AQH_Device_GetNameForSystem(dev);
if (s && *s && GWEN_Text_ComparePattern(s, deviceName, 0)==-1)
return 0;
}
return 1;
}
void _sendDeviceList(AQH_OBJECT *ep, const AQH_DEVICE_LIST *deviceList, uint32_t refMsgId)
{
AQH_DEVICE_LIST *tmpDeviceList;
const AQH_DEVICE *dev;
DBG_INFO(NULL, "Sending entries in multiple messages");
tmpDeviceList=AQH_Device_List_new();
dev=AQH_Device_List_First(deviceList);
while(dev) {
const AQH_DEVICE *next;
AQH_DEVICE *copyOfDevice;
next=AQH_Device_List_Next(dev);
copyOfDevice=AQH_Device_dup(dev);
AQH_Device_List_Add(copyOfDevice, tmpDeviceList);
if (AQH_Device_List_GetCount(tmpDeviceList)>=AQHOMEDATA_DEVICESPERMSG) {
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
_sendDeviceListMsg(ep, tmpDeviceList, next?0:AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
AQH_Device_List_Clear(tmpDeviceList);
}
dev=next;
}
if (AQH_Device_List_GetCount(tmpDeviceList)) {
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
_sendDeviceListMsg(ep, tmpDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId); /* send remaining */
}
AQH_Device_List_free(tmpDeviceList);
}
void _sendDeviceListMsg(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId)
void _sendDeviceList(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId)
{
AQH_MESSAGE *msg;

View File

@@ -13,16 +13,13 @@
#include "./s_getvalues.h"
#include "./server_p.h"
#include "aqhome/aqhome.h"
#include "aqhome/ipc2/endpoint.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getvalues.h"
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
@@ -41,10 +38,7 @@
* ------------------------------------------------------------------------------------------------
*/
static AQH_VALUE_LIST *_getMatchingValueList(AQHOME_SERVER *xo, const GWEN_TAG16_LIST *tagList);
static void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t refMsgId);
static void _sendValueListMsg(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
static int _valueMatches(const AQH_VALUE *v, const char *deviceName, int modality);
static void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
@@ -53,100 +47,64 @@ static int _valueMatches(const AQH_VALUE *v, const char *deviceName, int modalit
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleGetValues(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
void AqHomeDataServer_HandleGetValues(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, GWEN_UNUSED const GWEN_TAG16_LIST *tagList)
{
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
AQH_VALUE_LIST *valueList;
const AQH_VALUE_LIST *origValueList;
uint32_t refMsgId;
refMsgId=AQH_IpcMessage_GetMsgId(msg);
DBG_INFO(NULL, "HandleGetValues");
valueList=_getMatchingValueList(xo, tagList);
if (valueList) {
_sendValueList(ep, valueList, refMsgId);
AQH_Value_List_free(valueList);
origValueList=AQH_Storage_GetValueList(xo->storage);
if (origValueList) {
DBG_INFO(NULL, "Have a list of %d values", AQH_Value_List_GetCount(origValueList));
if (AQH_Value_List_GetCount(origValueList)<AQHOMEDATA_VALUESPERMSG) {
DBG_INFO(NULL, "Sending all entries in one message");
_sendValueList(ep, origValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
}
else {
AQH_VALUE_LIST *tmpValueList;
const AQH_VALUE *v;
DBG_INFO(NULL, "Sending entries in multiple messages");
tmpValueList=AQH_Value_List_new();
v=AQH_Value_List_First(origValueList);
while(v) {
const AQH_VALUE *next;
AQH_VALUE *copyOfValue;
next=AQH_Value_List_Next(v);
copyOfValue=AQH_Value_dup(v);
AQH_Value_List_Add(copyOfValue, tmpValueList);
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
_sendValueList(ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
AQH_Value_List_Clear(tmpValueList);
}
v=next;
}
if (AQH_Value_List_GetCount(tmpValueList)) {
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
_sendValueList(ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId); /* send remaining */
}
AQH_Value_List_free(tmpValueList);
}
}
else {
/* empty list */
_sendValueListMsg(ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
_sendValueList(ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
}
}
}
AQH_VALUE_LIST *_getMatchingValueList(AQHOME_SERVER *xo, const GWEN_TAG16_LIST *tagList)
{
const AQH_VALUE_LIST *origValueList;
AQH_VALUE_LIST *tmpValueList=NULL;
char *deviceName;
int modality;
deviceName=tagList?AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETVALUES_TAGS_DEVICENAME, NULL):NULL;
modality=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETVALUES_TAGS_MODALITY, 0):0;
origValueList=AQH_Storage_GetValueList(xo->storage);
if (origValueList) {
const AQH_VALUE *v;
tmpValueList=AQH_Value_List_new();
v=AQH_Value_List_First(origValueList);
while(v) {
if (_valueMatches(v, deviceName, modality)) {
AQH_VALUE *copyOfValue;
copyOfValue=AQH_Value_dup(v);
AQH_Value_List_Add(copyOfValue, tmpValueList);
}
v=AQH_Value_List_Next(v);
}
if (AQH_Value_List_GetCount(tmpValueList)<1) {
AQH_Value_List_free(tmpValueList);
tmpValueList=NULL;
}
}
free(deviceName);
return tmpValueList;
}
void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t refMsgId)
{
AQH_VALUE_LIST *tmpValueList;
const AQH_VALUE *v;
tmpValueList=AQH_Value_List_new();
v=AQH_Value_List_First(vl);
while(v) {
const AQH_VALUE *next;
AQH_VALUE *copyOfValue;
next=AQH_Value_List_Next(v);
copyOfValue=AQH_Value_dup(v);
AQH_Value_List_Add(copyOfValue, tmpValueList);
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
_sendValueListMsg(ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
AQH_Value_List_Clear(tmpValueList);
}
v=next;
}
if (AQH_Value_List_GetCount(tmpValueList)) {
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
_sendValueListMsg(ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId); /* send remaining */
}
AQH_Value_List_free(tmpValueList);
}
void _sendValueListMsg(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
{
AQH_MESSAGE *msg;
@@ -157,27 +115,3 @@ void _sendValueListMsg(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags,
int _valueMatches(const AQH_VALUE *v, const char *deviceName, int modality)
{
if (modality!=AQH_ValueModality_Unknown) {
int valModality;
valModality=AQH_Value_GetModality(v);
if (valModality!=modality)
return 0;
}
if (deviceName && *deviceName) {
const char *s;
s=AQH_Value_GetDeviceNameForSystem(v);
if (s && *s && GWEN_Text_ComparePattern(s, deviceName, 0)==-1)
return 0;
}
return 1;
}

View File

@@ -42,15 +42,14 @@
* ------------------------------------------------------------------------------------------------
*/
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, double data);
const AQH_VALUE *v, const char *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, double data);
static AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, const char *data);
static int _subRqHandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg);
static void _subRqAbort(AQH_MSG_REQUEST *rq, int reason);
@@ -77,11 +76,11 @@ void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_
recvdValue=AQH_IpcdMessageSetData_ReadValue(tagList);
if (recvdValue) {
const char *valueName;
double valueData;
char *valueDataFreeable;
AQH_VALUE *systemValue;
valueName=AQH_Value_GetNameForSystem(recvdValue);
valueData=AQH_IpcdMessageSetData_ReadData(tagList);
valueDataFreeable=AQH_IpcdMessageSetData_ReadData(tagList);
systemValue=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName);
if (systemValue) {
@@ -97,10 +96,8 @@ 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, valueData);
rq=_mkRequest_SetData(o, epSrc, msgId, epDriver, systemValue, valueDataFreeable);
AqHomeDataServer_AddRequestToTree(o, rq);
_storeDatapoint(xo, systemValue, valueData);
}
else {
DBG_ERROR(NULL, "Driver \"%s\" not available", driverName);
@@ -122,6 +119,7 @@ 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");
@@ -133,23 +131,6 @@ 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
*/
@@ -157,7 +138,7 @@ void _storeDatapoint(AQHOME_SERVER *xo, const AQH_VALUE *v, double valueData)
AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o,
AQH_OBJECT *epSrc, uint32_t requestMsgId,
AQH_OBJECT *epDriver,
const AQH_VALUE *v, double data)
const AQH_VALUE *v, const char *data)
{
AQH_MSG_REQUEST *rq;
AQH_MSG_REQUEST *subRq;
@@ -224,7 +205,7 @@ void _rqAbort(AQH_MSG_REQUEST *rq, int reason)
*/
AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, double data)
AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, const char *data)
{
AQH_MSG_REQUEST *rq;
uint16_t msgId;

View File

@@ -152,7 +152,7 @@ void _sendDataChangedMsgToAllClients(AQHOME_SERVER *xo, AQH_OBJECT *epSrc, const
DBG_DEBUG(AQH_LOGDOMAIN, "Sending update msg to endpoint");
msg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
AQH_Endpoint_GetNextMessageId(ep), 0, 0,
AQH_Endpoint_GetNextMessageId(ep), 0,
v, dataPoints, numValues);
AQH_Endpoint_AddMsgOut(ep, msg);
}

View File

@@ -79,9 +79,6 @@ static int _handleNewClient(AQH_OBJECT *o, AQH_OBJECT *clientEndpoint);
static int _handleClientDown(AQH_OBJECT *o, AQH_OBJECT *clientEndpoint);
static void _handleMsgsFromClient(AQH_OBJECT *o, AQHOME_SERVER *xo, AQH_OBJECT *ep);
static void _handleMsgFromClient(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg);
static void _createValue(AQHOME_SERVER *xo, AQH_OBJECT *epDriver,
const char *deviceName, const char *valueNameForSystem, const AQH_VALUE *valueTemplate);
static void _updateValue(AQHOME_SERVER *xo, AQH_VALUE *v, const char *deviceName, const AQH_VALUE *valueTemplate);
static AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_SERVER *xo, AQH_OBJECT *epDriver, const char *deviceName);
static int _createPidFile(const char *pidFilename);
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
@@ -655,16 +652,32 @@ AQH_VALUE *AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(AQH_OBJECT *o,
v=AQH_Storage_GetValueByNameForSystem(xo->storage, GWEN_Buffer_GetStart(buf));
if (v==NULL) {
if (AQH_Endpoint_GetPermissions(epDriver) & AQH_ENDPOINT_PERMS_ADDVALUE)
_createValue(xo, epDriver, deviceName, GWEN_Buffer_GetStart(buf), valueTemplate);
if (AQH_Endpoint_GetPermissions(epDriver) & AQH_ENDPOINT_PERMS_ADDVALUE) {
AQH_DEVICE *device;
DBG_INFO(AQH_LOGDOMAIN, "Creating value \"%s\"", GWEN_Buffer_GetStart(buf));
device=(deviceName && *deviceName)?_getOrCreateDeviceForDriver(xo, epDriver, deviceName):NULL;
v=AQH_Value_new();
AQH_Value_SetDriver(v, serviceName);
AQH_Value_SetName(v, AQH_Value_GetName(valueTemplate));
AQH_Value_SetNameForSystem(v, GWEN_Buffer_GetStart(buf));
AQH_Value_SetValueUnits(v, AQH_Value_GetValueUnits(valueTemplate));
AQH_Value_SetValueType(v, AQH_Value_GetValueType(valueTemplate));
AQH_Value_SetModality(v, AQH_Value_GetModality(valueTemplate));
AQH_Value_SetTimestampCreation(v, (uint64_t) time(NULL));
if (device) {
AQH_Value_SetDeviceNameForSystem(v, AQH_Device_GetNameForSystem(device));
AQH_Value_SetDeviceName(v, AQH_Device_GetName(device));
}
AQH_Storage_AddValue(xo->storage, v);
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create value \"%s\"", GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
return NULL;
}
}
else
_updateValue(xo, v, GWEN_Buffer_GetStart(buf), valueTemplate);
GWEN_Buffer_free(buf);
return v;
}
@@ -673,80 +686,6 @@ AQH_VALUE *AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(AQH_OBJECT *o,
void _createValue(AQHOME_SERVER *xo, AQH_OBJECT *epDriver,
const char *deviceName, const char *valueNameForSystem, const AQH_VALUE *valueTemplate)
{
AQH_DEVICE *device;
const char *serviceName;
const char *valueName;
AQH_VALUE *v;
serviceName=AQH_Endpoint_GetServiceName(epDriver);
valueName=AQH_Value_GetName(valueTemplate);
device=(deviceName && *deviceName)?_getOrCreateDeviceForDriver(xo, epDriver, deviceName):NULL;
DBG_ERROR(AQH_LOGDOMAIN,
"Creating value: service=\"%s\", device=\"%s\", value \"%s\"",
serviceName?serviceName:"<no service>", deviceName?deviceName:"<no device>", valueName?valueName:"<no value>");
v=AQH_Value_new();
AQH_Value_SetDriver(v, serviceName);
AQH_Value_SetName(v, AQH_Value_GetName(valueTemplate));
AQH_Value_SetNameForSystem(v, valueNameForSystem);
AQH_Value_SetValueUnits(v, AQH_Value_GetValueUnits(valueTemplate));
AQH_Value_SetValueType(v, AQH_Value_GetValueType(valueTemplate));
AQH_Value_SetModality(v, AQH_Value_GetModality(valueTemplate));
AQH_Value_SetTimestampCreation(v, (uint64_t) time(NULL));
if (device) {
AQH_Value_SetDeviceNameForSystem(v, AQH_Device_GetNameForSystem(device));
AQH_Value_SetDeviceName(v, AQH_Device_GetName(device));
}
AQH_Storage_AddValue(xo->storage, v);
}
void _updateValue(AQHOME_SERVER *xo, AQH_VALUE *value, const char *deviceName, const AQH_VALUE *valueTemplate)
{
int chg=0;
const char *s1;
const char *s2;
int i1;
int i2;
DBG_INFO(AQH_LOGDOMAIN, "Updating value \"%s\"", deviceName);
s1=AQH_Value_GetValueUnits(valueTemplate);
s2=AQH_Value_GetValueUnits(value);
if (s1 && *s1) {
if (!(s2 && *s2) || (strcasecmp(s1, s2)!=0)) {
AQH_Value_SetValueUnits(value, s1);
chg=1;
}
}
i1=AQH_Value_GetValueType(valueTemplate);
i2=AQH_Value_GetValueType(value);
if (i1!=AQH_ValueDataType_Unknown) {
if (i1!=i2) {
AQH_Value_SetValueType(value, i1);
chg=1;
}
}
i1=AQH_Value_GetModality(valueTemplate);
i2=AQH_Value_GetModality(value);
if (i1!=AQH_ValueModality_Unknown) {
if (i1!=i2) {
AQH_Value_SetModality(value, i1);
chg=1;
}
}
if (chg)
AQH_Storage_AddRuntimeFlags(xo->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
}
AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_SERVER *xo, AQH_OBJECT *epDriver, const char *deviceName)
{
const char *serviceName;
@@ -761,7 +700,7 @@ AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_SERVER *xo, AQH_OBJECT *epDriver,
device=AQH_Storage_GetDeviceByNameForSystem(xo->storage, GWEN_Buffer_GetStart(buf));
if (device==NULL) {
if (AQH_Endpoint_GetPermissions(epDriver) & AQH_ENDPOINT_PERMS_ADDDEVICE) {
DBG_ERROR(AQH_LOGDOMAIN, "Creating device \"%s\"", GWEN_Buffer_GetStart(buf));
DBG_INFO(AQH_LOGDOMAIN, "Creating device \"%s\"", GWEN_Buffer_GetStart(buf));
device=AQH_Device_new();
AQH_Device_SetDriver(device, serviceName);
AQH_Device_SetName(device, deviceName);

View File

@@ -218,7 +218,7 @@ void _sendMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQ
AQH_MESSAGE *pubMsg;
pubMsg=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0, 0,
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0,
msgValue, now, f);
DBG_INFO(AQH_LOGDOMAIN, "BROKER UPDATE_DATA %s/%s: %f",
deviceName?deviceName:"<no device name>",

View File

@@ -30,13 +30,8 @@
*/
static void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device,
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);
const char *valueName, const char *valueData);
static void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData);
static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic);
@@ -70,11 +65,12 @@ void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o,
device=AQH_MqttLogServer_FindRegisteredDevice(o, deviceName);
if (device) {
double valueData;
char *valueDataFreeable;
DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
valueData=AQH_IpcdMessageSetData_ReadData(tagList);
_sendDataForDevice(xo, device, valueName, valueData);
valueDataFreeable=AQH_IpcdMessageSetData_ReadData(tagList);
_sendDataForDevice(xo, device, valueName, valueDataFreeable);
free(valueDataFreeable);
}
else {
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
@@ -97,7 +93,7 @@ void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o,
void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo,
const AQHMQTT_DEVICE *device,
const char *valueName, double valueData)
const char *valueName, const char *valueData)
{
const char *deviceId;
@@ -120,7 +116,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, device, topic, value, valueData);
_sendValueToMqtt(xo, deviceId, topic, valueData);
}
} /* if out */
topic=AQHMQTT_Topic_List_Next(topic);
@@ -134,82 +130,32 @@ void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo,
void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo,
const AQHMQTT_DEVICE *device,
const AQHMQTT_TOPIC *topic,
const AQHMQTT_VALUE *value,
double valueData)
void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *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:"<empty>");
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:"<empty>");
#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) {
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;
}
GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic)
{
GWEN_BUFFER *buf;

View File

@@ -32,18 +32,18 @@
<members>
<member name="aqhValue" type="int" maxlen="8">
<member name="aqhValue" type="char_ptr" maxlen="128">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>with_getByMember</flags>
<flags>own</flags>
</member>
<member name="driverValue" type="char_ptr" maxlen="128">
<default>0</default>
<preset>0</preset>
<access>public</access>
<flags>own with_getByMember</flags>
<flags>own</flags>
</member>

View File

@@ -62,7 +62,6 @@ 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;
@@ -391,15 +390,13 @@ 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, sValueName);
AQHMQTT_Value_SetName(value, GWEN_XMLNode_GetProperty(valueNode, "name", NULL));
AQHMQTT_Value_SetValueUnits(value, GWEN_XMLNode_GetProperty(valueNode, "units", NULL));
AQHMQTT_Value_SetPath(value, GWEN_XMLNode_GetProperty(valueNode, "path", NULL));
@@ -418,12 +415,12 @@ AQHMQTT_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode)
translationList=_readXmlTranslationList(translationNode);
if (translationList) {
DBG_ERROR(NULL, "Translations read for value \"%s\"", sValueName);
DBG_INFO(NULL, "Translations read");
AQHMQTT_Value_SetTranslationList(value, translationList);
}
}
else {
DBG_ERROR(NULL, "No <translations> element in value %s", sValueName);
DBG_INFO(NULL, "No <translations> element");
}
return value;
@@ -443,7 +440,7 @@ AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(GWEN_XMLNODE *parentNode)
if (translation)
AQHMQTT_Translation_List_Add(translation, translationList);
else {
DBG_ERROR(NULL, "Error reading <translation> element");
DBG_INFO(NULL, "Error reading <translation> element");
AQHMQTT_Translation_List_free(translationList);
return NULL;
}
@@ -461,16 +458,16 @@ AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(GWEN_XMLNODE *parentNode)
AQHMQTT_TRANSLATION *_readXmlTranslation(GWEN_XMLNODE *translationNode)
{
int aqhValue;
const char *sAqhValue;
const char *sDriverValue;
aqhValue=GWEN_XMLNode_GetIntProperty(translationNode, "aqhValue", 0);
sAqhValue=GWEN_XMLNode_GetProperty(translationNode, "aqhValue", NULL);
sDriverValue=GWEN_XMLNode_GetProperty(translationNode, "driverValue", NULL);
if (sDriverValue && *sDriverValue) {
if (sAqhValue && *sAqhValue && sDriverValue && *sDriverValue) {
AQHMQTT_TRANSLATION *translation;
translation=AQHMQTT_Translation_new();
AQHMQTT_Translation_SetAqhValue(translation, aqhValue);
AQHMQTT_Translation_SetAqhValue(translation, sAqhValue);
AQHMQTT_Translation_SetDriverValue(translation, sDriverValue);
return translation;
}

View File

@@ -222,7 +222,7 @@ void _writeValueToXml(const AQHMQTT_VALUE *value, GWEN_XMLNODE *node)
void _writeTranslationToXml(const AQHMQTT_TRANSLATION *t, GWEN_XMLNODE *nTranslation)
{
GWEN_XMLNode_SetIntProperty(nTranslation, "aqhValue", AQHMQTT_Translation_GetAqhValue(t));
_setXmlPropertyIfNotNull(nTranslation, "aqhValue", AQHMQTT_Translation_GetAqhValue(t));
_setXmlPropertyIfNotNull(nTranslation, "driverValue", AQHMQTT_Translation_GetDriverValue(t));
}

View File

@@ -55,7 +55,6 @@ void AQH_NodeServer_HandleForward(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSA
AQH_Message_SetData(nodeMsg, ptr, len);
AQH_Message_SetUsedSize(nodeMsg, len);
AQH_Endpoint_AddMsgOut(xo->ttyEndpoint, nodeMsg);
AQH_NodeServer_WriteTtyMsgToLogFile(o, nodeMsg, "sending");
DBG_ERROR(NULL, "Forwarding node message %d to node", AQH_NodeMessage_GetMsgType(nodeMsg));
}
else {

View File

@@ -54,7 +54,7 @@ void AQH_NodeServer_HandleGetNodes(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESS
AQH_Endpoint_GetNextMessageId(ep), AQH_IpcMessage_GetMsgId(msg),
niNext?0:AQH_MSGNODE_GETDEVICES_RSP_FLAGS_LASTMSG, ni);
AQH_Endpoint_AddMsgOut(ep, outMsg);
DBG_DEBUG(NULL, "Messages in clients out queue: %d", AQH_Message_List_GetCount(AQH_Endpoint_GetMsgOutList(ep)));
DBG_ERROR(NULL, "Messages in clients out queue: %d", AQH_Message_List_GetCount(AQH_Endpoint_GetMsgOutList(ep)));
ni=niNext;
}
}

View File

@@ -92,61 +92,69 @@ 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;
char *data;
data=AQH_IpcdMessageSetData_ReadData(tagList);
nodeInfo=_getNodeInfoFromValue(xo, value);
if (nodeInfo) {
const char *devName;
if (data) {
AQH_NODE_INFO *nodeInfo;
devName=AQH_NodeInfo_GetDeviceId(nodeInfo);
if (devName) {
const AQHNODE_DEVICE *devInfo;
nodeInfo=_getNodeInfoFromValue(xo, value);
if (nodeInfo) {
const char *devName;
devInfo=AQH_NodeServer_GetDeviceDefByName(o, devName);
if (devInfo) {
const AQHNODE_VALUE *devValue;
devName=AQH_NodeInfo_GetDeviceId(nodeInfo);
if (devName) {
const AQHNODE_DEVICE *devInfo;
devValue=AQHNODE_Value_List_GetByName(AQHNODE_Device_GetValueList(devInfo), varName);
if (devValue) {
uint16_t dataVal=0;
uint16_t dataDenom=0;
devInfo=AQH_NodeServer_GetDeviceDefByName(o, devName);
if (devInfo) {
const AQHNODE_VALUE *devValue;
if (AQH_ReadDataFromDouble(AQHNODE_Value_GetDataType(devValue), data, &dataVal, &dataDenom)==0) {
AQH_MSG_REQUEST *rq;
int destAddr;
devValue=AQHNODE_Value_List_GetByName(AQHNODE_Device_GetValueList(devInfo), varName);
if (devValue) {
uint16_t dataVal=0;
uint16_t dataDenom=0;
destAddr=AQH_NodeInfo_GetBusAddress(nodeInfo);
DBG_DEBUG(NULL, "Creating SETDATA request");
if (AQH_ReadDataFromString(AQHNODE_Value_GetDataType(devValue), data, &dataVal, &dataDenom)==0) {
AQH_MSG_REQUEST *rq;
int destAddr;
rq=_mkRequest_SetData(o, xo, ep, msgId, destAddr, AQHNODE_Value_GetId(devValue), dataVal, dataDenom);
AQH_NodeServer_AddRequestToTree(o, rq);
/* done */
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);
}
}
else {
DBG_ERROR(NULL, "Bad data \"%.2f\"", data);
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_BADDATA);
DBG_ERROR(NULL, "Invalid value name \"%s\"", varName);
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
}
}
else {
DBG_ERROR(NULL, "Invalid value name \"%s\"", varName);
DBG_ERROR(NULL, "Unknown node \"%s\"", devName);
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
}
}
else {
DBG_ERROR(NULL, "Unknown node \"%s\"", devName);
_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, "Node not yet fully identified, come back later");
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_TRYAGAIN);
DBG_ERROR(NULL, "No matching nodeinfo");
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
}
free(data);
}
else {
DBG_ERROR(NULL, "No matching nodeinfo");
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
DBG_ERROR(NULL, "No data");
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_NODATA);
}
}
else {
@@ -266,7 +274,6 @@ AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_NODE_SERVER *xo,
AQH_MsgRequest_SetTimestamps(rq, R_SETDATA_SUBREQUEST_EXPIRE_SECS);
msgOut=AQH_ValueMessage_new(destAddr, xo->nodeAddress, AQH_MSG_TYPE_VALUE_SET, msgId, valueId, dataVal, dataDenom);
AQH_NodeServer_WriteTtyMsgToLogFile(o, msgOut, "sending");
AQH_Endpoint_AddMsgOut(xo->ttyEndpoint, msgOut);
return rq;

View File

@@ -41,7 +41,6 @@
#include <aqhome/msg/node/m_value.h>
#include <aqhome/msg/node/m_recvstats.h>
#include <aqhome/msg/node/m_sendstats.h>
#include <aqhome/msg/node/m_memstats.h>
#include <aqhome/data/value.h>
#include <gwenhywfar/args.h>
@@ -123,9 +122,7 @@ static void _forwardTtyMsgToBroker(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH
static void _forwardValueMessageToBroker(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _forwardDataFromSendStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _forwardDataFromRecvStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _forwardDataFromMemStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _forwardTtyMsgToClients(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _publishIntWithIdx(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int idx, int vModality, const char *vUnits, int v);
static void _publishInt(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int vModality, const char *vUnits, int v);
static void _publishDouble(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int vModality, const char *vUnits, double v);
static void _setDeviceName(AQH_VALUE *value, uint32_t uid);
@@ -830,11 +827,9 @@ void _forwardTtyMsgToBroker(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAG
code=AQH_NodeMessage_GetMsgType(msg);
switch(code) {
case AQH_MSG_TYPE_VALUE_REPORT: _forwardValueMessageToBroker(o, xo, msg); break;
case AQH_MSG_TYPE_COMSENDSTATS: _forwardDataFromSendStatsMsgToBroker(xo, msg); break;
case AQH_MSG_TYPE_COMRECVSTATS: _forwardDataFromRecvStatsMsgToBroker(xo, msg); break;
case AQH_MSG_TYPE_MEMSTATS: _forwardDataFromMemStatsMsgToBroker(xo, msg); break;
case AQH_MSG_TYPE_VALUE_REPORT: _forwardValueMessageToBroker(o, xo, msg); break;
case AQH_MSG_TYPE_COMSENDSTATS: _forwardDataFromSendStatsMsgToBroker(xo, msg); break;
case AQH_MSG_TYPE_COMRECVSTATS: _forwardDataFromRecvStatsMsgToBroker(xo, msg); break;
default: break;
}
}
@@ -903,21 +898,24 @@ void _forwardDataFromSendStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE
packetsOutInt=AQH_SendStatsMessage_GetPacketsOut(msg);
if (packetsOutInt) {
uint32_t uid;
int devNum;
double packetsOut;
double collisions;
double busy;
double collisionsPercentage=0.0;
double busyPercentage=0.0;
uid=AQH_SendStatsMessage_GetUid(msg);
devNum=AQH_SendStatsMessage_GetInterface(msg);
packetsOut=/*(double)*/ packetsOutInt;
collisions=/*(double)*/ AQH_SendStatsMessage_GetCollisions(msg);
busy=/*(double)*/ AQH_SendStatsMessage_GetBusyErrors(msg);
if (devNum==0) {
_publishInt(xo, uid, "net/packetsOut", AQH_ValueModality_Stats, NULL, packetsOutInt);
_publishInt(xo, uid, "net/collisions", AQH_ValueModality_Stats, NULL, (int) AQH_SendStatsMessage_GetCollisions(msg));
_publishInt(xo, uid, "net/busy", AQH_ValueModality_Stats, NULL, (int) AQH_SendStatsMessage_GetBusyErrors(msg));
}
else {
_publishIntWithIdx(xo, uid, "net/packetsOut", devNum, AQH_ValueModality_Stats, NULL, packetsOutInt);
_publishIntWithIdx(xo, uid, "net/collisions", devNum, AQH_ValueModality_Stats, NULL, (int) AQH_SendStatsMessage_GetCollisions(msg));
_publishIntWithIdx(xo, uid, "net/busy", devNum, AQH_ValueModality_Stats, NULL, (int) AQH_SendStatsMessage_GetBusyErrors(msg));
}
collisionsPercentage=collisions*100.0/packetsOut;
busyPercentage=busy*100.0/packetsOut;
_publishInt( xo, uid, "net/packetsOut", 0, NULL, packetsOutInt);
_publishInt( xo, uid, "net/collisions", 0, NULL, (int) AQH_SendStatsMessage_GetCollisions(msg));
_publishDouble(xo, uid, "net/collisionsPercent", 0, "%", collisionsPercentage);
_publishDouble(xo, uid, "net/busyPercent", 0, "%", busyPercentage);
}
}
@@ -930,57 +928,30 @@ void _forwardDataFromRecvStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE
packetsInInt=AQH_RecvStatsMessage_GetPacketsIn(msg);
if (packetsInInt) {
uint32_t uid;
int devNum;
int m=AQH_ValueModality_Stats;
double packetsIn;
double crcErrors;
double ioErrors;
double crcErrorsPercentage=0.0;
double ioErrorsPercentage=0.0;
uid=AQH_RecvStatsMessage_GetUid(msg);
devNum=AQH_RecvStatsMessage_GetInterface(msg);
uid=AQH_SendStatsMessage_GetUid(msg);
packetsIn=/*(double)*/ packetsInInt;
crcErrors=/*(double)*/AQH_RecvStatsMessage_GetCrcErrors(msg);
ioErrors=/*(double)*/AQH_RecvStatsMessage_GetIoErrors(msg);
if (devNum==0) {
_publishInt(xo, uid, "net/packetsIn", m, NULL, packetsInInt);
_publishInt(xo, uid, "net/crcErrors", m, NULL, (int) AQH_RecvStatsMessage_GetCrcErrors(msg));
_publishInt(xo, uid, "net/ioErrors", m, NULL, (int) AQH_RecvStatsMessage_GetIoErrors(msg));
_publishInt(xo, uid, "net/nobufferErrors", m, NULL, (int) AQH_RecvStatsMessage_GetNoBufferErrors(msg));
_publishInt(xo, uid, "net/msgSizeErrors", m, NULL, (int) AQH_RecvStatsMessage_GetMsgSizeErrors(msg));
_publishInt(xo, uid, "net/missed", m, NULL, (int) AQH_RecvStatsMessage_GetMissed(msg));
}
else {
_publishIntWithIdx(xo, uid, "net/packetsIn", devNum, m, NULL, packetsInInt);
_publishIntWithIdx(xo, uid, "net/crcErrors", devNum, m, NULL, (int) AQH_RecvStatsMessage_GetCrcErrors(msg));
_publishIntWithIdx(xo, uid, "net/ioErrors", devNum, m, NULL, (int) AQH_RecvStatsMessage_GetIoErrors(msg));
_publishIntWithIdx(xo, uid, "net/nobufferErrors", devNum, m, NULL, (int) AQH_RecvStatsMessage_GetNoBufferErrors(msg));
_publishIntWithIdx(xo, uid, "net/msgSizeErrors", devNum, m, NULL, (int) AQH_RecvStatsMessage_GetMsgSizeErrors(msg));
_publishIntWithIdx(xo, uid, "net/missed", devNum, m, NULL, (int) AQH_RecvStatsMessage_GetMissed(msg));
}
crcErrorsPercentage=crcErrors*100.0/packetsIn;
ioErrorsPercentage=ioErrors*100.0/packetsIn;
_publishInt( xo, uid, "net/packetsIn", 0, NULL, packetsInInt);
_publishInt( xo, uid, "net/crcerrors", 0, NULL, (int) AQH_RecvStatsMessage_GetCrcErrors(msg));
_publishInt( xo, uid, "net/ioerrors", 0, NULL, (int) AQH_RecvStatsMessage_GetIoErrors(msg));
_publishDouble(xo, uid, "net/crcerrorsPercent", 0, "%", crcErrorsPercentage);
_publishDouble(xo, uid, "net/ioerrorsPercent", 0, "%", ioErrorsPercentage);
}
}
void _forwardDataFromMemStatsMsgToBroker(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
{
uint32_t uid;
uid=AQH_MemStatsMessage_GetUid(msg);
_publishInt( xo, uid, "mem/buffersUsed", AQH_ValueModality_Stats, NULL, AQH_MemStatsMessage_GetBuffersUsed(msg));
_publishInt( xo, uid, "mem/maxBuffersUsed", AQH_ValueModality_Stats, NULL, AQH_MemStatsMessage_GetMaxBuffersUsed(msg));
}
void _publishIntWithIdx(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int idx, int vModality, const char *vUnits, int v)
{
GWEN_BUFFER *tbuf;
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(tbuf, "%s%d", vPath, idx);
_publishInt(xo, uid, GWEN_Buffer_GetStart(tbuf), vModality, vUnits, v);
GWEN_Buffer_free(tbuf);
}
void _publishInt(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int vModality, const char *vUnits, int v)
{
_publishDouble(xo, uid, vPath, vModality, vUnits, /*(double)*/ v);
@@ -1009,7 +980,7 @@ void _publishDouble(AQH_NODE_SERVER *xo, uint32_t uid, const char *vPath, int vM
AQH_MESSAGE *pubMsg;
pubMsg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0, 0,
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0,
value, arrayToSend, 1);
if (pubMsg) {
DBG_INFO(AQH_LOGDOMAIN,
@@ -1046,30 +1017,6 @@ void _setDeviceName(AQH_VALUE *value, uint32_t uid)
void AQH_NodeServer_WriteTtyMsgToLogFile(AQH_OBJECT *o, const AQH_MESSAGE *msg, const char *txt)
{
if (o && msg) {
AQH_NODE_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQH_NODE_SERVER, o);
if (xo && xo->logFile) {
GWEN_BUFFER *dbuf;
GWEN_TIME *ti;
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
ti=GWEN_CurrentTime();
GWEN_Time_toString(ti, "YYYY-MM-DD hh:mm:ss ", dbuf);
GWEN_Time_free(ti);
ti=NULL;
AQH_NodeMessage_DumpSpecificToBuffer(msg, dbuf, txt?txt:"");
_writeToLogFile(xo->logFile, GWEN_Buffer_GetStart(dbuf));
GWEN_Buffer_free(dbuf);
}
}
}
void _writeTtyMsgToLogFile(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
{
if (xo->logFile) {

View File

@@ -86,7 +86,6 @@ AQH_MSG_REQUEST *AQH_NodeServer_GetRequestTree(const AQH_OBJECT *o);
void AQH_NodeServer_AddRequestToTree(AQH_OBJECT *o, AQH_MSG_REQUEST *rq);
void AQH_NodeServer_CleanupRequests(AQH_OBJECT *o);
void AQH_NodeServer_WriteTtyMsgToLogFile(AQH_OBJECT *o, const AQH_MESSAGE *msg, const char *txt);

View File

@@ -26,6 +26,15 @@
<unit id="and1" type="and" />
<unit id="zeroPosNegString1" type="zeroPosNegString">
<params>
<param name="valueIfNegative">OFF</param>
<param name="valueIfZero">OFF</param>
<param name="valueIfPositive">ON</param>
</params>
</unit>
<unit id="valueSetOutPlug1" type="valueSet">
<params>
<param name="valueName">mqtt/109C2F/power</param>
@@ -40,6 +49,7 @@
<link sourceUnit=".timer" sourcePort="output" targetUnit="suntime1" targetPort="timer" />
<link sourceUnit="suntime1" sourcePort="output" targetUnit="and1" targetPort="input" />
<link sourceUnit="delayedOff1" sourcePort="output" targetUnit="and1" targetPort="input" />
<link sourceUnit="and1" sourcePort="output" targetUnit="valueSetOutPlug1" targetPort="input" />
<link sourceUnit="and1" sourcePort="output" targetUnit="zeroPosNegString1" targetPort="input" />
<link sourceUnit="zeroPosNegString1" sourcePort="output" targetUnit="valueSetOutPlug1" targetPort="input" />
</links>
</network>

View File

@@ -12,7 +12,7 @@
</inputPorts>
<outputPorts>
<outputPort name="output" dataType="double" />
<outputPort name="output" dataType="string" />
</outputPorts>

View File

@@ -349,35 +349,13 @@ const char *_readDouble(const char *s, double *ptrDouble)
while(*s && isspace(*s))
s++;
sStart=s;
if (*s=='#') {
uint32_t v=0;
while(*s && (isdigit(*s) || *s=='.' || *s=='+' || *s=='-'))
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;
}
rv=GWEN_Text_StringToDouble(sStart, ptrDouble);
if (rv<0) {
DBG_ERROR(NULL, "Error reading double: %d", rv);
return NULL;
}
return s;

View File

@@ -38,6 +38,7 @@
*/
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);
@@ -61,7 +62,7 @@ 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_DOUBLE);
AQHREACT_Port_SetDataType(port, AQHREACT_DATAOBJECTTYPE_STRING);
AQHREACT_Unit_AddInputPort(unit, port);
param=AQHREACT_Param_new();
@@ -91,6 +92,9 @@ 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;
@@ -126,20 +130,47 @@ 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, data);
v, GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
AQH_Value_free(v);
return msgOut;
}

View File

@@ -6,7 +6,6 @@
<includes type="c" >
$(gwenhywfar_cflags)
$(aqdiagram_cflags)
-I$(topsrcdir)
-I$(topbuilddir)
</includes>
@@ -51,18 +50,15 @@
aqhome
aqhtool_nodes
aqhtool_data
aqhtool_image
</useTargets>
<libraries>
$(gwenhywfar_libs)
$(aqdiagram_libs)
</libraries>
<subdirs>
nodes
data
image
</subdirs>

View File

@@ -37,14 +37,9 @@
getdevices.h
adddata.h
getdatapoints.h
getfirstdata.h
getlastdata.h
getperioddata.h
setdata.h
moddevice.h
watch.h
devicestate.h
imgperioddata.h
</headers>
<sources>
@@ -54,14 +49,9 @@
getdevices.c
adddata.c
getdatapoints.c
getfirstdata.c
getlastdata.c
getperioddata.c
setdata.c
moddevice.c
watch.c
devicestate.c
imgperioddata.c
</sources>
<useTargets>

View File

@@ -197,7 +197,7 @@ AQH_MESSAGE *_createRequestMessage(GWEN_UNUSED AQH_OBJECT *o, uint32_t msgId)
AQH_Value_SetValueUnits(v, valueUnits);
AQH_Value_SetDeviceName(v, deviceName);
msg=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_UPDATEDATA, msgId, 0, 0, v, timestampToSend, dataToSend);
msg=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_UPDATEDATA, msgId, 0, v, timestampToSend, dataToSend);
AQH_Value_free(v);
GWEN_JsonElement_free(jRoot);
return msg;

View File

@@ -1,264 +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 <config.h>
#endif
#include "./devicestate.h"
#include "../utils.h"
#include "aqhome/aqhome.h"
#include "aqhome/dataclient/client.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/timestamp.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* defs
* ------------------------------------------------------------------------------------------------
*/
#define I18S(msg) msg
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT
#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST)
#define A_CHAR GWEN_ArgsType_Char
#define A_INT GWEN_ArgsType_Int
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _runCommand(AQH_DATACLIENT *dc);
static void _handleDevice(AQH_DATACLIENT *dc, const AQH_DEVICE *device);
static void _handleValue(AQH_DATACLIENT *dc, const AQH_VALUE *value);
static void _printDataPoints(const uint64_t *dataPoints, uint32_t numValues);
static void _printSingleDataPoint(uint64_t timestamp, double data);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
int AQH_Tool_DeviceState(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
AQH_EVENT_LOOP *eventLoop;
AQH_DATACLIENT *dc;
int rv;
const GWEN_ARGS args[]= {
/* flags type name min max s long short_descr, long_descr */
{ A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL},
{ A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL},
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ A_ARG, A_CHAR, "device", 1, 1, "d", "device", I18S("device name"), NULL},
{ A_ARG, A_CHAR, "valueName", 0, 1, "N", "valuename", I18S("Value name for device(e.g. LIGHT)"), NULL},
{ A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
};
eventLoop=AQH_EventLoop_new();
dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION);
rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=AQH_DataClient_ConnectWithArgs(dc, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=_runCommand(dc);
if (rv<0) {
DBG_ERROR(NULL, "Error running (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 0;
}
int _runCommand(AQH_DATACLIENT *dc)
{
GWEN_DB_NODE *dbLocalArgs;
const char *deviceName;
AQH_DEVICE_LIST *deviceList;
AQH_DEVICE *device;
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
deviceName=GWEN_DB_GetCharValue(dbLocalArgs, "device", 0, "*");
deviceList=AQH_DataClient_GetDevices(dc, deviceName);
if (deviceList==NULL) {
DBG_ERROR(NULL, "Error getting devices");
return GWEN_ERROR_GENERIC;
}
device=AQH_Device_List_First(deviceList);
while(device) {
const char *s;
s=AQH_Device_GetNameForSystem(device);
if (s && *s && -1!=GWEN_Text_ComparePattern(s, deviceName, 0)) {
_handleDevice(dc, device);
}
device=AQH_Device_List_Next(device);
}
AQH_Device_List_free(deviceList);
return 0;
}
void _handleDevice(AQH_DATACLIENT *dc, const AQH_DEVICE *device)
{
AQH_VALUE_LIST *valueList;
const char *devName;
const char *roomName;
const char *location;
const char *descr;
devName=AQH_Device_GetNameForSystem(device);
roomName=AQH_Device_GetRoomName(device);
location=AQH_Device_GetLocation(device);
descr=AQH_Device_GetDescription(device);
fprintf(stdout, "%s (room: %s, loc: %s, descr: %s)\n",
devName,
roomName?roomName:"--",
location?location:"--",
descr?descr:"--");
valueList=AQH_DataClient_GetValues(dc, devName, 0);
if (valueList) {
const AQH_VALUE *value;
value=AQH_Value_List_First(valueList);
while(value) {
if (AQH_Value_GetValueType(value)==AQH_ValueType_Sensor)
_handleValue(dc, value);
value=AQH_Value_List_Next(value);
}
}
AQH_Value_List_free(valueList);
}
void _handleValue(AQH_DATACLIENT *dc, const AQH_VALUE *value)
{
GWEN_DB_NODE *dbLocalArgs;
const char *wantedValueName;
const char *valueName;
int numDataPoints;
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
numDataPoints=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 5);
wantedValueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, "*");
valueName=AQH_Value_GetName(value);
if (valueName &&
-1==GWEN_Text_ComparePattern(valueName, "stats_*", 0) &&
-1!=GWEN_Text_ComparePattern(valueName, wantedValueName, 0)) {
const char *valueNameForSystem;
uint64_t *dataPoints;
uint64_t recvdNum;
valueNameForSystem=AQH_Value_GetNameForSystem(value);
fprintf(stdout, " %s: ", valueName?valueName:"<empty>");
dataPoints=malloc(numDataPoints*sizeof(uint64_t)*2);
recvdNum=AQH_DataClient_GetLastData(dc, valueNameForSystem, dataPoints, numDataPoints);
if (recvdNum>0)
_printDataPoints(dataPoints, recvdNum);
free(dataPoints);
fprintf(stdout, "\n");
}
}
void _printDataPoints(const uint64_t *dataPoints, uint32_t numValues)
{
uint32_t i;
for(i=0; i<numValues; i++) {
uint64_t timestamp;
union {double f; uint64_t i;} u;
if (i)
fprintf(stdout, " | ");
timestamp=*(dataPoints++);
u.i=*(dataPoints++);
_printSingleDataPoint(timestamp, u.f);
}
}
void _printSingleDataPoint(uint64_t timestamp, double data)
{
GWEN_TIMESTAMP *ts;
ts=GWEN_Timestamp_fromLocalTime((time_t) timestamp);
if (ts)
fprintf(stdout, "%lf (%04d/%02d/%02d-%02d:%02d:%02d)",
data,
GWEN_Timestamp_GetYear(ts),
GWEN_Timestamp_GetMonth(ts),
GWEN_Timestamp_GetDay(ts),
GWEN_Timestamp_GetHour(ts),
GWEN_Timestamp_GetMinute(ts),
GWEN_Timestamp_GetSecond(ts));
else
fprintf(stdout, "%lf", data);
}

View File

@@ -1,21 +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.
****************************************************************************/
#ifndef AQHOME_TOOL_DEVICESTATE_H
#define AQHOME_TOOL_DEVICESTATE_H
#include <gwenhywfar/db.h>
int AQH_Tool_DeviceState(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
#endif

View File

@@ -10,7 +10,7 @@
# include <config.h>
#endif
#include "./getdatapoints.h"
#include "./getvalues.h"
#include "../client.h"
#include "../utils.h"
@@ -52,6 +52,7 @@
static AQH_MESSAGE *_createRequestMessage(AQH_OBJECT *o, uint32_t msgId);
static int _handleResponseMessage(AQH_OBJECT *o, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList, int first);
static void _handleDataResponse(const GWEN_TAG16_LIST *tagList, int printMean, int printDiff);
static uint64_t _getTimeStampFromString(const char *s);
@@ -109,23 +110,18 @@ AQH_MESSAGE *_createRequestMessage(GWEN_UNUSED AQH_OBJECT *o, uint32_t msgId)
dbArgs=AQH_ToolClient_GetDbLocalArgs(o);
valueName=GWEN_DB_GetCharValue(dbArgs, "valueName", 0, NULL);
num=GWEN_DB_GetIntValue(dbArgs, "numOfLastDatapoints", 0, 0);
tsBegin=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsBegin", 0, NULL));
tsBegin=_getTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsBegin", 0, NULL));
if (tsBegin==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad begin timestamp");
return NULL;
}
tsEnd=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsEnd", 0, NULL));
tsEnd=_getTimeStampFromString(GWEN_DB_GetCharValue(dbArgs, "tsEnd", 0, NULL));
if (tsEnd==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad end timestamp");
return NULL;
}
// TODO: use "mode" correctly
return AQH_IpcdMessageGetData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_REQ,
msgId, 0,
AQH_MSGDATA_GETDATA_MODE_LAST,
valueName,
tsBegin, tsEnd, num);
return AQH_IpcdMessageGetData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_REQ, msgId, 0, valueName, tsBegin, tsEnd, num);
}
@@ -182,3 +178,45 @@ void _handleDataResponse(const GWEN_TAG16_LIST *tagList, int printMean, int prin
uint64_t _getTimeStampFromString(const char *s)
{
if (s && *s) {
if (*s=='-') {
uint64_t x=0;
uint64_t now=time(NULL);
s++;
while(*s && isdigit(*s)) {
unsigned int i;
i=*(s++)-'0';
x*=10;
x+=i;
}
if (*s) {
switch(*s) {
case 0:
case 'm': x*=60; break;
case 'h': x*=(60*60); break;
case 'd': x*=(60*60*24); break;
default: break;
}
}
return (now-x);
}
else {
unsigned long int x;
if (1!=sscanf(s, "%lu", &x)) {
DBG_ERROR(NULL, "ERROR: Invalid timestamp");
return (uint64_t) (-1);
}
return (uint64_t) x;
}
}
return 0;
}

View File

@@ -1,153 +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 <config.h>
#endif
#include "./getfirstdata.h"
#include "../utils.h"
#include "aqhome/dataclient/client.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
#include "aqhome/dataclient/client.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* defs
* ------------------------------------------------------------------------------------------------
*/
#define I18S(msg) msg
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT
#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST)
#define A_CHAR GWEN_ArgsType_Char
#define A_INT GWEN_ArgsType_Int
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _runCommand(AQH_DATACLIENT *dc);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
int AQH_Tool_GetFirstData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
AQH_EVENT_LOOP *eventLoop;
AQH_DATACLIENT *dc;
int rv;
const GWEN_ARGS args[]= {
/* flags type name min max s long short_descr, long_descr */
{ A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL},
{ A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL},
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL},
{ A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL},
{ 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL},
{ 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
};
eventLoop=AQH_EventLoop_new();
dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION);
rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=AQH_DataClient_ConnectWithArgs(dc, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=_runCommand(dc);
if (rv<0) {
DBG_ERROR(NULL, "Error running (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 0;
}
int _runCommand(AQH_DATACLIENT *dc)
{
GWEN_DB_NODE *dbLocalArgs;
const char *valueName;
uint64_t num;
int printMean;
int printDiff;
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL);
num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1);
printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0);
printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0);
if (num>0) {
uint64_t *dataPoints;
uint64_t recvdNum;
dataPoints=malloc(num*sizeof(uint64_t)*2);
recvdNum=AQH_DataClient_GetFirstData(dc, valueName, dataPoints, num);
if (recvdNum>0) {
if (printMean)
Utils_PrintMeanData(dataPoints, recvdNum, NULL);
else if (printDiff)
Utils_PrintDiffData(dataPoints, recvdNum, NULL);
else
Utils_PrintDataPoints(dataPoints, recvdNum, NULL);
}
free(dataPoints);
}
return 0;
}

View File

@@ -1,21 +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.
****************************************************************************/
#ifndef AQHOME_TOOL_GETFIRSTDATA_H
#define AQHOME_TOOL_GETFIRSTDATA_H
#include <gwenhywfar/db.h>
int AQH_Tool_GetFirstData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
#endif

View File

@@ -1,153 +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 <config.h>
#endif
#include "./getlastdata.h"
#include "../utils.h"
#include "aqhome/dataclient/client.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
#include "aqhome/dataclient/client.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* defs
* ------------------------------------------------------------------------------------------------
*/
#define I18S(msg) msg
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT
#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST)
#define A_CHAR GWEN_ArgsType_Char
#define A_INT GWEN_ArgsType_Int
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _runCommand(AQH_DATACLIENT *dc);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
int AQH_Tool_GetLastData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
AQH_EVENT_LOOP *eventLoop;
AQH_DATACLIENT *dc;
int rv;
const GWEN_ARGS args[]= {
/* flags type name min max s long short_descr, long_descr */
{ A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL},
{ A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL},
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL},
{ A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL},
{ 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL},
{ 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
};
eventLoop=AQH_EventLoop_new();
dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION);
rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=AQH_DataClient_ConnectWithArgs(dc, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=_runCommand(dc);
if (rv<0) {
DBG_ERROR(NULL, "Error running (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 0;
}
int _runCommand(AQH_DATACLIENT *dc)
{
GWEN_DB_NODE *dbLocalArgs;
const char *valueName;
uint64_t num;
int printMean;
int printDiff;
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL);
num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1);
printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0);
printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0);
if (num>0) {
uint64_t *dataPoints;
uint64_t recvdNum;
dataPoints=malloc(num*sizeof(uint64_t)*2);
recvdNum=AQH_DataClient_GetLastData(dc, valueName, dataPoints, num);
if (recvdNum>0) {
if (printMean)
Utils_PrintMeanData(dataPoints, recvdNum, NULL);
else if (printDiff)
Utils_PrintDiffData(dataPoints, recvdNum, NULL);
else
Utils_PrintDataPoints(dataPoints, recvdNum, NULL);
}
free(dataPoints);
}
return 0;
}

View File

@@ -1,21 +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.
****************************************************************************/
#ifndef AQHOME_TOOL_GETLASTDATA_H
#define AQHOME_TOOL_GETLASTDATA_H
#include <gwenhywfar/db.h>
int AQH_Tool_GetLastData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
#endif

View File

@@ -1,167 +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 <config.h>
#endif
#include "./getperioddata.h"
#include "../utils.h"
#include "aqhome/dataclient/client.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
#include "aqhome/dataclient/client.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
#include <ctype.h>
/* ------------------------------------------------------------------------------------------------
* defs
* ------------------------------------------------------------------------------------------------
*/
#define I18S(msg) msg
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
#define A_ARG GWEN_ARGS_FLAGS_HAS_ARGUMENT
#define A_END (GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST)
#define A_CHAR GWEN_ArgsType_Char
#define A_INT GWEN_ArgsType_Int
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _runCommand(AQH_DATACLIENT *dc);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
int AQH_Tool_GetPeriodData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{
AQH_EVENT_LOOP *eventLoop;
AQH_DATACLIENT *dc;
int rv;
const GWEN_ARGS args[]= {
/* flags type name min max s long short_descr, long_descr */
{ A_ARG, A_CHAR, "brokerAddress", 0, 1, "t", "tcpaddress", I18S("TCP address to connect to [127.0.0.1]"), NULL},
{ A_ARG, A_INT, "brokerPort", 0, 1, "P", "tcpport", I18S("Specify the TCP port to listen on"), NULL},
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ A_ARG, A_CHAR, "valueName", 1, 1, "N", "valuename", I18S("Value name (e.g. server/temp/system)"), NULL},
{ A_ARG, A_INT, "numOfDatapoints", 0, 1, "n", NULL, I18S("Get up to n datapoints"), NULL},
{ A_ARG, A_CHAR, "tsBegin", 0, 1, "tb", "tsbegin", I18S("Timestamp range begin"), NULL},
{ A_ARG, A_CHAR, "tsEnd", 0, 1, "te", "tsend", I18S("Timestamp range end"), NULL},
{ 0, A_INT, "printMean", 0, 1, "M", "mean", I18S("Print mean value of data received"), NULL},
{ 0, A_INT, "printDiff", 0, 1, "D", "diff", I18S("Print diff last-first value"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
};
eventLoop=AQH_EventLoop_new();
dc=AQH_DataClient_new(eventLoop, AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION);
rv=AQH_DataClient_ReadLocalArgs(dc, dbGlobalArgs, args, argc, argv);
if (rv<0) {
DBG_ERROR(NULL, "here (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=AQH_DataClient_ConnectWithArgs(dc, 0);
if (rv<0) {
DBG_ERROR(NULL, "Error connecting (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
rv=_runCommand(dc);
if (rv<0) {
DBG_ERROR(NULL, "Error running (%d)", rv);
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 2;
}
AQH_DataClient_free(dc);
AQH_EventLoop_free(eventLoop);
return 0;
}
int _runCommand(AQH_DATACLIENT *dc)
{
GWEN_DB_NODE *dbLocalArgs;
const char *valueName;
uint64_t num;
uint64_t tsBegin;
uint64_t tsEnd;
int printMean;
int printDiff;
dbLocalArgs=AQH_DataClient_GetDbLocalArgs(dc);
valueName=GWEN_DB_GetCharValue(dbLocalArgs, "valueName", 0, NULL);
num=GWEN_DB_GetIntValue(dbLocalArgs, "numOfDatapoints", 0, 1);
tsBegin=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbLocalArgs, "tsBegin", 0, NULL));
if (tsBegin==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad begin timestamp");
return 1;
}
tsEnd=Utils_GetTimeStampFromString(GWEN_DB_GetCharValue(dbLocalArgs, "tsEnd", 0, NULL));
if (tsEnd==(uint64_t) (-1)) {
DBG_ERROR(NULL, "Bad end timestamp");
return 1;
}
printMean=GWEN_DB_GetIntValue(dbLocalArgs, "printMean", 0, 0);
printDiff=GWEN_DB_GetIntValue(dbLocalArgs, "printDiff", 0, 0);
if (num>0) {
uint64_t *dataPoints;
uint64_t recvdNum;
dataPoints=malloc(num*sizeof(uint64_t)*2);
recvdNum=AQH_DataClient_GetPeriodData(dc, valueName, dataPoints, num, tsBegin, tsEnd);
if (recvdNum>0) {
if (printMean)
Utils_PrintMeanData(dataPoints, recvdNum, NULL);
else if (printDiff)
Utils_PrintDiffData(dataPoints, recvdNum, NULL);
else
Utils_PrintDataPoints(dataPoints, recvdNum, NULL);
}
free(dataPoints);
}
return 0;
}

View File

@@ -1,21 +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.
****************************************************************************/
#ifndef AQHOME_TOOL_GETPERIODDATA_H
#define AQHOME_TOOL_GETPERIODDATA_H
#include <gwenhywfar/db.h>
int AQH_Tool_GetPeriodData(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv);
#endif

View File

@@ -14,12 +14,10 @@
#include "../client.h"
#include "../utils.h"
#include "aqhome/aqhome.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
#include "aqhome/msg/ipc/data/m_ipcd_getvalues.h"
#include <gwenhywfar/args.h>
#include <gwenhywfar/i18n.h>
@@ -69,8 +67,6 @@ int AQH_Tool_GetValues(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
{ A_ARG, A_INT, "timeout", 0, 1, "T", NULL, I18S("Specify timeout in seconds for response"), NULL},
{ A_ARG, A_CHAR, "brokerClientId", 0, 1, "c", "clientid", I18S("Specify CLIENTID"), NULL},
{ A_ARG, A_CHAR, "userId", 0, 1, "u", "userid", I18S("Specify user id"), NULL},
{ A_ARG, A_CHAR, "device", 0, 1, "d", "device", I18S("device name to match"), NULL},
{ A_ARG, A_CHAR, "modality", 0, 1, "m", NULL, I18S("Modality to match"), NULL},
{ A_ARG, A_CHAR, "password", 0, 1, "p", "password", I18S("Specify service password"), NULL},
{ 0, A_INT, "printHeader", 0, 1, "H", "printheader", I18S("Print header if given"), NULL},
{ A_END, A_INT, "help", 0, 0, "h", "help", I18S("Show this help screen"), NULL}
@@ -94,23 +90,11 @@ int AQH_Tool_GetValues(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv)
AQH_MESSAGE *_createRequestMessage(GWEN_UNUSED AQH_OBJECT *o, uint32_t msgId)
{
GWEN_DB_NODE *dbArgs;
const char *deviceName;
const char *s;
int modality;
dbArgs=AQH_ToolClient_GetDbLocalArgs(o);
deviceName=GWEN_DB_GetCharValue(dbArgs, "device", 0, NULL);
s=GWEN_DB_GetCharValue(dbArgs, "modality", 0, NULL);
if (s && *s) {
modality=AQH_ValueModality_fromString(s);
if (modality==AQH_ValueModality_Unknown) {
}
}
else
modality=AQH_ValueModality_Unknown;
return AQH_IpcdMessageGetValues_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ, msgId, 0, deviceName, modality);
return AQH_IpcMessage_new(AQH_IPC_PROTOCOL_DATA_ID,
AQH_IPC_PROTOCOL_DATA_VERSION,
AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ,
msgId, 0,
0, NULL);
}

Some files were not shown because too many files have changed in this diff Show More