34 Commits

Author SHA1 Message Date
Martin Preuss
6174233731 avr: re-added firmware for older devices. 2025-03-11 23:51:14 +01:00
Martin Preuss
216a13e90d aqhome: decreased verbosity. 2025-03-11 23:00:53 +01:00
Martin Preuss
44c5eb65bd aqhome: added AQH_Message_dup() 2025-03-11 23:00:41 +01:00
Martin Preuss
edb6c90f46 decreased verbosity. 2025-03-11 23:00:14 +01:00
Martin Preuss
58bc39c2fb aqhome-tool: Decreased verbosity, fixed flash handling. 2025-03-11 23:00:02 +01:00
Martin Preuss
fecaaaf341 aqhome apps: fixed taglist handling. 2025-03-11 22:59:18 +01:00
Martin Preuss
263ce00a14 more work on new events2-based apps. 2025-03-11 00:56:18 +01:00
Martin Preuss
9cca3af402 aqhome apps: sending a message via aqhome-nodes to nodes now works. 2025-03-10 23:22:30 +01:00
Martin Preuss
541b5ee2ca added file to .gitignore 2025-03-10 00:15:52 +01:00
Martin Preuss
dc4a02a8ff aqhome-apps: removed unneeded files. 2025-03-10 00:15:36 +01:00
Martin Preuss
5011e7e123 aqhome-apps: decreased verbosity. 2025-03-10 00:02:26 +01:00
Martin Preuss
cf9408b594 avr: no longer build firmware for outdated nodes. 2025-03-09 23:25:27 +01:00
Martin Preuss
3e4e3ffe2d aqhome-apps: all apps now work again. 2025-03-09 23:25:02 +01:00
Martin Preuss
9c1188b4d1 aqhome: decreased verbosity. 2025-03-09 15:04:03 +01:00
Martin Preuss
ea564ba101 aqhome apps: more work on transition to events2. 2025-03-09 00:06:12 +01:00
Martin Preuss
ca2103f7b3 aqhome: adapted server aqhome-mqttlog to events2 api. 2025-03-08 01:03:22 +01:00
Martin Preuss
58c6d12e36 aqhome: finished transformation of aqhome-data and aqhome-tool. 2025-03-02 21:48:22 +01:00
Martin Preuss
2f468e4f78 added device descriptor for t03. 2025-03-01 16:58:18 +01:00
Martin Preuss
daba490c09 events2: make sure object is disconnected from event loop! 2025-03-01 16:58:04 +01:00
Martin Preuss
3638378344 ipc2: added missing include. 2025-03-01 16:57:36 +01:00
Martin Preuss
f26effc8b3 aqhome-data: increased verbosity. 2025-03-01 16:57:20 +01:00
Martin Preuss
8b22e7d22a aqhome-nodes: don't directly delete endpoint when connection goes down.
object should only be deleted outside the loop!
2025-03-01 16:57:00 +01:00
Martin Preuss
b413b172e5 ipc2: minor beautification. 2025-03-01 15:23:56 +01:00
Martin Preuss
4e85b59ec9 aqhome: added missing defs. 2025-03-01 15:23:26 +01:00
Martin Preuss
c7551512bc aqhome: added AQH_IpcdMessageValues_newForOne() 2025-03-01 15:23:07 +01:00
Martin Preuss
6b61763d6f ipc2: added ipc_endpoint 2025-03-01 15:22:34 +01:00
Martin Preuss
106f47d465 aqhome-tool: more work on transformation to events2. 2025-03-01 15:22:00 +01:00
Martin Preuss
0cfec70025 aqhome-nodes: transformed app to use new event2 interface. 2025-03-01 15:21:02 +01:00
Martin Preuss
72e32847c7 aqhome-mqttlog: fixed compiler warning. 2025-03-01 15:20:29 +01:00
Martin Preuss
c6f4759530 aqhome-data: removed unneeded files. 2025-03-01 15:19:58 +01:00
Martin Preuss
3e9aa7969b aqhome: add apiCode to endpoint. 2025-02-28 00:22:26 +01:00
Martin Preuss
e308e07b87 aqhome-tool: move basic client code on folder up. 2025-02-27 23:55:29 +01:00
Martin Preuss
f2d527cd2f aqhome-data, aqhome-tool: more work on new protocol. 2025-02-27 23:50:18 +01:00
Martin Preuss
d887747b3c aqhome: more work on transformation to event2/ipc2. 2025-02-27 14:08:44 +01:00
294 changed files with 12953 additions and 14880 deletions

1
.gitignore vendored
View File

@@ -16,6 +16,7 @@ aqhome-nodes.vg
aqhome-tool.vg
aqhome-mqtt.pid
aqhome-mqtt.devices
aqhome-react.pid
core.*
core

View File

@@ -35,40 +35,32 @@
</setVar>
<headers dist="true" >
aqhome_data.h
aqhome_data_p.h
fini.h
init.h
loop.h
c_connect.h
c_updatedata.h
c_getvalues.h
c_getdevices.h
c_getdatapoints.h
c_getlastdatapoint.h
c_setdata.h
c_addvalue.h
c_annvalue.h
c_moddevice.h
server.h
server_p.h
s_connect.h
s_getdevices.h
s_getvalues.h
s_addvalue.h
s_annvalue.h
s_updatedata.h
s_setdata.h
s_getdatapoints.h
s_moddevice.h
</headers>
<sources>
$(local/typefiles)
aqhome_data.c
fini.c
init.c
loop.c
c_connect.c
c_updatedata.c
c_getvalues.c
c_getdevices.c
c_getdatapoints.c
c_getlastdatapoint.c
c_setdata.c
c_addvalue.c
c_annvalue.c
c_moddevice.c
server.c
s_connect.c
s_getdevices.c
s_getvalues.c
s_addvalue.c
s_annvalue.c
s_updatedata.c
s_setdata.c
s_getdatapoints.c
s_moddevice.c
main.c
</sources>

View File

@@ -1,152 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./aqhome_data_p.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
AQHOME_DATA *AqHomeData_new()
{
AQHOME_DATA *aqh;
GWEN_NEW_OBJECT(AQHOME_DATA, aqh);
aqh->storageMutex=GWEN_Mutex_new();
aqh->requestTree=GWEN_MsgRequest_new();
return aqh;
}
void AqHomeData_free(AQHOME_DATA *aqh)
{
if (aqh) {
GWEN_Mutex_free(aqh->storageMutex);
GWEN_MsgRequest_free(aqh->requestTree);
GWEN_MsgEndpoint_free(aqh->ipcdEndpoint);
GWEN_DB_Group_free(aqh->dbArgs);
AQH_Storage_free(aqh->storage);
free(aqh->pidFile);
GWEN_FREE_OBJECT(aqh);
}
}
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcdEndpoint(const AQHOME_DATA *aqh)
{
return aqh?(aqh->ipcdEndpoint):NULL;
}
GWEN_DB_NODE *AqHomeData_GetDbArgs(const AQHOME_DATA *aqh)
{
return aqh?(aqh->dbArgs):NULL;
}
AQH_STORAGE *AqHomeData_GetStorage(const AQHOME_DATA *aqh)
{
return aqh?(aqh->storage):NULL;
}
GWEN_MSG_REQUEST *AqHomeData_GetRequestTree(const AQHOME_DATA *aqh)
{
return aqh?aqh->requestTree:NULL;
}
void AqHomeData_AddRequestToTree(AQHOME_DATA *aqh, GWEN_MSG_REQUEST *rq)
{
if (aqh && rq)
GWEN_MsgRequest_Tree2_AddChild(aqh->requestTree, rq);
}
const char *AqHomeData_GetPidFile(const AQHOME_DATA *aqh)
{
return aqh?aqh->pidFile:NULL;
}
int AqHomeData_GetTimeout(const AQHOME_DATA *aqh)
{
return aqh?aqh->timeout:0;
}
int AqHomeData_LockStorage(AQHOME_DATA *aqh)
{
int rv;
rv=GWEN_Mutex_Lock(aqh->storageMutex);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on storage mutex");
return rv;
}
return rv;
}
int AqHomeData_UnlockStorage(AQHOME_DATA *aqh)
{
int rv;
rv=GWEN_Mutex_Unlock(aqh->storageMutex);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on storage mutex");
return rv;
}
return rv;
}
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcEndpointByServiceName(const AQHOME_DATA *aqh, const char *serviceName)
{
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
while(ep) {
const char *s;
s=AQH_IpcEndpoint_GetServiceName(ep);
if (s && *s && strcasecmp(s, serviceName)==0)
return ep;
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
}
return NULL;
}

View File

@@ -1,47 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_H
#define AQHOME_DATA_H
#include "aqhome/data/storage.h"
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/request.h>
typedef struct AQHOME_DATA AQHOME_DATA;
AQHOME_DATA *AqHomeData_new();
void AqHomeData_free(AQHOME_DATA *aqh);
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcdEndpoint(const AQHOME_DATA *aqh);
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcEndpointByServiceName(const AQHOME_DATA *aqh, const char *serviceName);
GWEN_DB_NODE *AqHomeData_GetDbArgs(const AQHOME_DATA *aqh);
AQH_STORAGE *AqHomeData_GetStorage(const AQHOME_DATA *aqh);
const char *AqHomeData_GetPidFile(const AQHOME_DATA *aqh);
int AqHomeData_GetTimeout(const AQHOME_DATA *aqh);
int AqHomeData_LockStorage(AQHOME_DATA *aqh);
int AqHomeData_UnlockStorage(AQHOME_DATA *aqh);
GWEN_MSG_REQUEST *AqHomeData_GetRequestTree(const AQHOME_DATA *aqh);
void AqHomeData_AddRequestToTree(AQHOME_DATA *aqh, GWEN_MSG_REQUEST *rq);
#endif

View File

@@ -1,72 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_addvalue.h"
#include "./aqhome_data_p.h"
#include "./loop.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
AQH_VALUE *recvdValue;
AQH_ValuesDataIpcMsg_Parse(msg, 0);
recvdValue=AQH_ValuesDataIpcMsg_ReadFirstValue(msg);
if (recvdValue) {
AQH_VALUE *value;
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
if (value==NULL)
resultCode=AQH_MSG_IPC_ERROR_PERMS;
AQH_Value_free(recvdValue);
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}

View File

@@ -1,65 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "./c_annvalue.h"
#include "./aqhome_data_p.h"
#include "./loop.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleAnnounceValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
{
AQH_VALUE *recvdValue;
AQH_ValuesDataIpcMsg_Parse(msg, 0);
recvdValue=AQH_ValuesDataIpcMsg_ReadFirstValue(msg);
if (recvdValue) {
AQH_VALUE *value;
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
if (value==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "Could not create announced value");
}
AQH_Value_free(recvdValue);
}
}

View File

@@ -1,93 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_connect.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/data/msg_data_connect.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleConnect(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
char *clientId=NULL;
char *userId=NULL;
char *passw=NULL;
uint32_t flags;
AQH_ConnectDataIpcMsg_Parse(msg, 0);
clientId=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_CLIENTID, NULL);
userId=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_USERID, NULL);
flags=AQH_Tag16IpcMsg_GetTagDataAsUint32(msg, AQH_MSGDATA_CONNECT_TAGS_FLAGS, 0);
passw=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_PASSWORD, NULL);
if (clientId)
AQH_IpcEndpoint_SetServiceName(ep, clientId);
if (userId)
AQH_IpcEndpoint_SetUserName(ep, userId);
if (flags & AQH_MSGDATA_CONNECT_FLAGS_WANTUPDATES)
GWEN_MsgEndpoint_AddFlags(ep, AQH_IPCENDPOINT_FLAGS_WANTUPDATES);
/* TODO: add user management, for now we allow all */
AQH_IpcEndpoint_SetPermissions(ep,
AQH_IPCENDPOINT_PERMS_LISTVALUES |
AQH_IPCENDPOINT_PERMS_READVALUE |
AQH_IPCENDPOINT_PERMS_ADDVALUE |
AQH_IPCENDPOINT_PERMS_LISTDATA |
AQH_IPCENDPOINT_PERMS_READDATA |
AQH_IPCENDPOINT_PERMS_ADDDATA |
AQH_IPCENDPOINT_PERMS_LISTDEVICES |
AQH_IPCENDPOINT_PERMS_READDEVICE |
AQH_IPCENDPOINT_PERMS_ADDDEVICE |
AQH_IPCENDPOINT_PERMS_MODDEVICE);
free(passw);
free(userId);
free(clientId);
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}

View File

@@ -1,211 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_getdatapoints.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_multidata.h"
#include "aqhome/ipc/data/msg_data_getdata.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 2048
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 1024
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _getAndSendDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep,
const AQH_VALUE *value,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId);
static int _getAndSendDataPointsNoNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
uint32_t refMsgId);
static int _getAndSendDataPointsWithNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
static void _sendDataPointsResponse(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
uint32_t refMsgId);
static void _getAndSendLastDatapoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint32_t refMsgId);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) {
AQH_VALUE *value;
char *valueName;
uint64_t tsBegin;
uint64_t tsEnd;
uint64_t numRequested;
AQH_GetDataDataIpcMsg_Parse(recvdMsg, 0);
valueName=AQH_Tag16IpcMsg_GetTagDataAsNewString(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL);
tsBegin=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0);
tsEnd=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_END, 0);
numRequested=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NUM, 0);
value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
if (value) {
resultCode=_getAndSendDataPoints(aqh, ep, value, tsBegin, tsEnd, numRequested, GWEN_IpcMsg_GetMsgId(recvdMsg));
if (resultCode==AQH_MSG_IPC_SUCCESS)
return;
}
else {
DBG_INFO(NULL, "Value \"%s\" does not exist", valueName);
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
}
free(valueName);
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
resultCode=AQH_MSG_IPC_ERROR_PERMS;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}
int _getAndSendDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
uint32_t refMsgId)
{
if (num==0)
return _getAndSendDataPointsNoNum(aqh, ep, value, tsBegin, tsEnd, refMsgId);
else if (num==1) {
_getAndSendLastDatapoint(aqh, ep, value, refMsgId);
return AQH_MSG_IPC_SUCCESS;
}
else
return _getAndSendDataPointsWithNum(aqh, ep, value, num, refMsgId);
}
int _getAndSendDataPointsNoNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *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_GetDataPoints(aqh->storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES);
if (tablePtr) {
_sendDataPointsResponse(aqh, ep, value, tablePtr, refMsgId);
free(tablePtr);
return AQH_MSG_IPC_SUCCESS;
}
else {
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
return AQH_MSG_IPC_ERROR_NODATA;
}
}
int _getAndSendDataPointsWithNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *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(aqh->storage, valueId, num);
if (tablePtr) {
_sendDataPointsResponse(aqh, ep, value, tablePtr, refMsgId);
free(tablePtr);
return AQH_MSG_IPC_SUCCESS;
}
else {
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
return AQH_MSG_IPC_ERROR_NODATA;
}
}
void _sendDataPointsResponse(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
uint32_t refMsgId)
{
int numTableEntries;
int numDataPoints;
GWEN_MSG *outMsg;
numTableEntries=(int)(tablePtr[0]);
numDataPoints=numTableEntries/2;
outMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
value, &(tablePtr[1]), numDataPoints);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}
void _getAndSendLastDatapoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint32_t refMsgId)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
int rv;
uint64_t timestamp=0;
double data=0.0;
rv=AQH_Storage_GetLastDataPoint(aqh->storage, AQH_Value_GetId(value), &timestamp, &data);
if (rv<0) {
switch(rv) {
case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break;
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break;
default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break;
}
}
else {
outMsg=AQH_MultiDataDataIpcMsg_newForOne(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
value, timestamp, data);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
return;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}

View File

@@ -1,106 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_getdevices.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_devices.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_DEVICESPERMSG 10
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _sendDeviceList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleGetDevices(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
const AQH_DEVICE_LIST *origDeviceList;
DBG_INFO(NULL, "HandleGetDevices");
origDeviceList=AQH_Storage_GetDeviceList(aqh->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(aqh, ep, origDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
}
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(aqh, ep, tmpDeviceList, next?0:AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
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(aqh, ep, tmpDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg)); /* send remaining */
}
AQH_Device_List_free(tmpDeviceList);
}
}
else {
/* empty list */
_sendDeviceList(aqh, ep, NULL, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
}
}
void _sendDeviceList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId)
{
GWEN_MSG *msg;
msg=AQH_DevicesDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP,
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
flags, vl);
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
}

View File

@@ -1,25 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_C_GETDEVICES_H
#define AQHOME_DATA_C_GETDEVICES_H
#include "./aqhome_data.h"
void AqHomeData_HandleGetDevices(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
#endif

View File

@@ -1,107 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_getlastdatapoint.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_getdata.h"
#include "aqhome/ipc/data/msg_data_multidata.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) {
char *valueName;
AQH_GetDataDataIpcMsg_Parse(recvdMsg, 0);
valueName=AQH_Tag16IpcMsg_GetTagDataAsNewString(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL);
if (valueName && *valueName) {
const AQH_VALUE *storedValue;
storedValue=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
if (storedValue) {
uint64_t timestamp=0;
double data=0.0;
int rv;
rv=AQH_Storage_GetLastDataPoint(aqh->storage, AQH_Value_GetId(storedValue), &timestamp, &data);
if (rv<0) {
switch(rv) {
case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break;
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break;
default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break;
}
}
else {
outMsg=AQH_MultiDataDataIpcMsg_newForOne(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
storedValue, timestamp, data);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
free(valueName);
return;
}
}
else {
DBG_INFO(NULL, "Value \"%s\" not found", valueName);
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
}
free(valueName);
}
else {
DBG_INFO(NULL, "No name for value");
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
}
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
resultCode=AQH_MSG_IPC_ERROR_PERMS;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}

View File

@@ -1,25 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_C_GETLASTDATAPOINT_H
#define AQHOME_DATA_C_GETLASTDATAPOINT_H
#include "./aqhome_data.h"
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
#endif

View File

@@ -1,106 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_getvalues.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_VALUESPERMSG 10
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
const AQH_VALUE_LIST *origValueList;
DBG_INFO(NULL, "HandleGetValues");
origValueList=AQH_Storage_GetValueList(aqh->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(aqh, ep, origValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
}
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(aqh, ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
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(aqh, ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg)); /* send remaining */
}
AQH_Value_List_free(tmpValueList);
}
}
else {
/* empty list */
_sendValueList(aqh, ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
}
}
void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
{
GWEN_MSG *msg;
msg=AQH_ValuesDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP,
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
flags, vl);
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
}

View File

@@ -1,25 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_C_GETVALUES_H
#define AQHOME_DATA_C_GETVALUES_H
#include "./aqhome_data.h"
void AqHomeData_HandleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
#endif

View File

@@ -1,114 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_getlastdatapoint.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_devices.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/text.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleModDevice(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_MODDEVICE) {
AQH_DEVICE *device;
AQH_DevicesDataIpcMsg_Parse(recvdMsg, 0);
device=AQH_DevicesDataIpcMsg_ReadFirstDevice(recvdMsg);
if (device) {
const char *deviceNameForSystem;
deviceNameForSystem=AQH_Device_GetNameForSystem(device);
if (deviceNameForSystem && *deviceNameForSystem) {
AQH_DEVICE *storedDevice;
storedDevice=AQH_Storage_GetDeviceByNameForSystem(aqh->storage, deviceNameForSystem);
if (storedDevice) {
const char *s;
s=AQH_Device_GetNameForGui(device);
if (s && *s)
AQH_Device_SetNameForGui(storedDevice, s);
s=AQH_Device_GetRoomName(device);
if (s && *s)
AQH_Device_SetRoomName(storedDevice, s);
s=AQH_Device_GetLocation(device);
if (s && *s)
AQH_Device_SetLocation(storedDevice, s);
s=AQH_Device_GetDescription(device);
if (s && *s)
AQH_Device_SetDescription(storedDevice, s);
AQH_Storage_AddRuntimeFlags(aqh->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
resultCode=AQH_MSG_IPC_SUCCESS;
}
else {
DBG_INFO(NULL, "Device \"%s\" not found", deviceNameForSystem);
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
}
}
else {
DBG_INFO(NULL, "No name for value");
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
}
}
else {
DBG_INFO(NULL, "No device info in message");
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
resultCode=AQH_MSG_IPC_ERROR_PERMS;
}
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}

View File

@@ -1,25 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_C_MODDEVICE_H
#define AQHOME_DATA_C_MODDEVICE_H
#include "./aqhome_data.h"
void AqHomeData_HandleModDevice(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
#endif

View File

@@ -1,258 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_setdata.h"
#include "./aqhome_data_p.h"
#include "./loop.h"
#include "aqhome/aqhome.h"
#include "aqhome/ipc/requests.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_set.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define R_SETDATA_REQUEST_EXPIRE_SECS 20
#define R_SETDATA_SUBREQUEST_EXPIRE_SECS 10
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static GWEN_MSG_REQUEST *_mkRequest_SetData(AQHOME_DATA *aqh,
GWEN_MSG_ENDPOINT *epSrc, uint32_t requestMsgId,
GWEN_MSG_ENDPOINT *epDriver,
const AQH_VALUE *v, const char *data);
static void _rqSubRequestFinished(GWEN_MSG_REQUEST *rq, GWEN_MSG_REQUEST *subRq, int reason);
static void _rqAbort(GWEN_MSG_REQUEST *rq, int reason);
static GWEN_MSG_REQUEST *_mkSubRequest_SetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const AQH_VALUE *v, const char *data);
static int _subRqHandleResponse(GWEN_MSG_REQUEST *rq, GWEN_MSG *msg);
static void _subRqAbort(GWEN_MSG_REQUEST *rq, int reason);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleSetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, GWEN_MSG *recvdMsg)
{
uint32_t msgId;
AQH_VALUE *recvdValue;
const char *valueName;
char *valueDataFreeable;
AQH_VALUE *systemValue;
msgId=GWEN_IpcMsg_GetMsgId(recvdMsg);
DBG_INFO(NULL, "Received IPC SetDataRequest message (msgId=%d)", msgId);
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
valueName=recvdValue?AQH_Value_GetNameForSystem(recvdValue):NULL;
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
systemValue=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
if (systemValue) {
if (AQH_Value_GetValueType(systemValue)==AQH_ValueType_Actor) {
const char *driverName;
driverName=AQH_Value_GetDriver(systemValue);
if (driverName && *driverName) {
GWEN_MSG_ENDPOINT *epDriver;
epDriver=AqHomeData_GetIpcEndpointByServiceName(aqh, driverName);
if (epDriver) {
GWEN_MSG_REQUEST *rq;
DBG_DEBUG(NULL, "Creating SETDATA request for driver endpoint (%s)", GWEN_MsgEndpoint_GetName(epDriver));
rq=_mkRequest_SetData(aqh, epSrc, msgId, epDriver, systemValue, valueDataFreeable);
AqHomeData_AddRequestToTree(aqh, rq);
}
else {
DBG_ERROR(NULL, "Driver \"%s\" not available", driverName);
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
}
}
else {
DBG_ERROR(NULL, "No driver name");
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
}
}
else {
DBG_ERROR(NULL, "Value \"%s\" is not an actor", valueName);
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_INVALID);
}
}
else {
DBG_ERROR(NULL, "Unknown value \"%s\"", valueName);
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_NOTFOUND);
}
AQH_Value_free(recvdValue);
free(valueDataFreeable);
}
/* ------------------------------------------------------------------------------------------------
* IPC Request SETDATA
*/
GWEN_MSG_REQUEST *_mkRequest_SetData(AQHOME_DATA *aqh,
GWEN_MSG_ENDPOINT *epSrc, uint32_t requestMsgId,
GWEN_MSG_ENDPOINT *epDriver,
const AQH_VALUE *v, const char *data)
{
GWEN_MSG_REQUEST *rq;
GWEN_MSG_REQUEST *subRq;
rq=GWEN_MsgRequest_new();
GWEN_MsgRequest_SetPrivateData(rq, aqh);
GWEN_MsgRequest_SetEndpoint(rq, epSrc);
GWEN_MsgRequest_SetRequestMsgId(rq, requestMsgId);
GWEN_MsgRequest_SetSubRequestFinishedFn(rq, _rqSubRequestFinished);
GWEN_MsgRequest_SetAbortFn(rq, _rqAbort);
GWEN_MsgRequest_SetTimestamps(rq, R_SETDATA_REQUEST_EXPIRE_SECS);
subRq=_mkSubRequest_SetData(aqh, epDriver, v, data);
GWEN_MsgRequest_Tree2_AddChild(rq, subRq);
return rq;
}
void _rqSubRequestFinished(GWEN_MSG_REQUEST *rq, GWEN_MSG_REQUEST *subRq, int reason)
{
GWEN_MSG_ENDPOINT *ep;
uint32_t refMsgId;
int result;
DBG_DEBUG(NULL, "SubRequest finished (reason: %d)", reason);
refMsgId=GWEN_MsgRequest_GetRequestMsgId(rq);
ep=GWEN_MsgRequest_GetEndpoint(rq);
result=GWEN_MsgRequest_GetResult(subRq);
if (reason==GWEN_MSG_REQUEST_REASON_ABORTED)
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
else
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, result);
GWEN_MsgRequest_SetResult(rq, result);
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
}
void _rqAbort(GWEN_MSG_REQUEST *rq, int reason)
{
GWEN_MSG_ENDPOINT *ep;
uint32_t refMsgId;
GWEN_MSG_REQUEST *rqParent;
DBG_INFO(NULL, "Aborting request");
refMsgId=GWEN_MsgRequest_GetRequestMsgId(rq);
ep=GWEN_MsgRequest_GetEndpoint(rq);
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
if (rqParent)
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, reason);
}
/* ------------------------------------------------------------------------------------------------
* Driver Request SETDATA
*/
GWEN_MSG_REQUEST *_mkSubRequest_SetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const AQH_VALUE *v, const char *data)
{
GWEN_MSG_REQUEST *rq;
uint16_t msgId;
GWEN_MSG *driverMsg;
rq=GWEN_MsgRequest_new();
GWEN_MsgRequest_SetPrivateData(rq, aqh);
GWEN_MsgRequest_SetEndpoint(rq, epDriver);
GWEN_MsgRequest_SetHandleResponseFn(rq, _subRqHandleResponse);
GWEN_MsgRequest_SetAbortFn(rq, _subRqAbort);
msgId=GWEN_MsgEndpoint_GetNextMessageId(epDriver);
GWEN_MsgRequest_SetRequestMsgId(rq, msgId);
GWEN_MsgRequest_SetTimestamps(rq, R_SETDATA_SUBREQUEST_EXPIRE_SECS);
driverMsg=AQH_SetDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_SETDATA, msgId, 0, v, data);
GWEN_MsgEndpoint_AddSendMessage(epDriver, driverMsg);
return rq;
}
int _subRqHandleResponse(GWEN_MSG_REQUEST *rq, GWEN_MSG *msg)
{
DBG_DEBUG(NULL, "Checking message from driver");
if (GWEN_IpcMsg_GetCode(msg)==AQH_MSGTYPE_IPC_DATA_RESULT) {
uint32_t result;
GWEN_MSG_REQUEST *rqParent;
result=AQH_ResultIpcMsg_GetResultCode(msg);
DBG_INFO(NULL, "Received result for request: %d", result);
GWEN_MsgRequest_SetResult(rq, result);
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
if (rqParent)
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, GWEN_MSG_REQUEST_REASON_DONE);
return GWEN_MSG_REQUEST_RESULT_HANDLED;
}
else {
DBG_ERROR(NULL, "Unexpected response message %d", GWEN_IpcMsg_GetCode(msg));
}
return GWEN_MSG_REQUEST_RESULT_NOT_HANDLED;
}
void _subRqAbort(GWEN_MSG_REQUEST *rq, int reason)
{
GWEN_MSG_REQUEST *rqParent;
DBG_INFO(NULL, "Aborting request");
GWEN_MsgRequest_SetResult(rq, AQH_MSG_IPC_ERROR_GENERIC);
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
if (rqParent)
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, reason);
}

View File

@@ -1,25 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_C_SETDATA_H
#define AQHOME_DATA_C_SETDATA_H
#include "./aqhome_data.h"
void AqHomeData_HandleSetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
#endif

View File

@@ -1,153 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./c_updatedata.h"
#include "./aqhome_data_p.h"
#include "./loop.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_multidata.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/msg_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define DISABLE_DEBUGLOG
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues);
static void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
const uint64_t *dataPoints, uint32_t numValues);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
{
GWEN_MSG *outMsg;
int resultCode=AQH_MSG_IPC_SUCCESS;
const GWEN_TAG16 *tag;
AQH_VALUE *recvdValue;
const char *valueName;
const uint64_t *dataPoints=NULL;
unsigned int numberOfPoints=0;
AQH_MultiDataDataIpcMsg_Parse(recvdMsg, 0);
recvdValue=AQH_MultiDataDataIpcMsg_ReadValue(recvdMsg);
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
tag=AQH_Tag16IpcMsg_FindFirstTagByType(recvdMsg, AQH_MSGDATA_MULTIDATA_TAGS_DATA);
dataPoints=tag?((const uint64_t*)GWEN_Tag16_GetTagData(tag)):NULL;
numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t));
if (numberOfPoints>0) {
AQH_VALUE *value;
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
if (value) {
resultCode=_storeDataPoints(aqh, value, dataPoints, numberOfPoints);
if (resultCode==AQH_MSG_IPC_SUCCESS)
_sendDataChangedMsgToAllClients(aqh, ep, value, dataPoints, numberOfPoints);
}
else {
DBG_INFO(NULL, "No permissions to add datapoint for value \"%s\"", valueName);
resultCode=AQH_MSG_IPC_ERROR_PERMS;
}
}
else {
DBG_INFO(NULL, "No datapoints");
resultCode=AQH_MSG_IPC_ERROR_INVALID;
}
AQH_Value_free(recvdValue);
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
resultCode);
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
}
int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues)
{
uint32_t i;
for(i=0; i<numValues; i++) {
uint64_t timestamp;
union {double f; uint64_t i;} u;
int rv;
timestamp=*(dataPoints++);
u.i=*(dataPoints++);
rv=AQH_Storage_AddDatapoint(aqh->storage, AQH_Value_GetId(v), timestamp, u.f);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return AQH_MSG_IPC_ERROR_GENERIC;
}
else {
DBG_DEBUG(NULL, "Datapoint added for value \"%s\"", AQH_Value_GetNameForSystem(v));
}
} /* for */
return AQH_MSG_IPC_SUCCESS;
}
void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
const uint64_t *dataPoints, uint32_t numValues)
{
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
while(ep) {
if (ep!=epSrc) {
if (GWEN_MsgEndpoint_GetFlags(ep) & AQH_IPCENDPOINT_FLAGS_WANTUPDATES) {
GWEN_MSG *msg;
DBG_DEBUG(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep));
msg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
GWEN_MsgEndpoint_GetNextMessageId(ep), 0,
v, dataPoints, numValues);
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
}
else {
DBG_DEBUG(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep));
}
}
else {
DBG_DEBUG(AQH_LOGDOMAIN, "Not sending update msg to source of updates");
}
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
}
}

View File

@@ -1,25 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_C_UPDATEDATA_H
#define AQHOME_DATA_C_UPDATEDATA_H
#include "./aqhome_data.h"
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
#endif

View File

@@ -1,80 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./fini.h"
#include "./aqhome_data_p.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <unistd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_Fini(AQHOME_DATA *aqh)
{
if (aqh) {
if (aqh->ipcdEndpoint) {
_disconnectTree(aqh->ipcdEndpoint);
GWEN_MsgEndpoint_Disconnect(aqh->ipcdEndpoint);
}
GWEN_MsgEndpoint_free(aqh->ipcdEndpoint);
aqh->ipcdEndpoint=NULL;
if (aqh->pidFile)
remove(aqh->pidFile);
}
}
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
{
GWEN_MSG_ENDPOINT *epChild;
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
while(epChild) {
_disconnectTree(epChild);
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
} /* while */
GWEN_MsgEndpoint_Disconnect(ep);
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_FINI_H
#define AQHOME_DATA_FINI_H
#include "./aqhome_data.h"
void AqHomeData_Fini(AQHOME_DATA *aqh);
#endif

View File

@@ -1,341 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./init.h"
#include "./aqhome_data_p.h"
#include "aqhome/aqhome.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/endpoint_msgio.h>
#include <gwenhywfar/directory.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _setupStorage(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs);
static void _setupIpc(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs);
static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
static int _createPidFile(const char *pidFilename);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AqHomeData_Init(AQHOME_DATA *aqh, int argc, char **argv)
{
GWEN_DB_NODE *dbArgs;
int rv;
const char *s;
dbArgs=GWEN_DB_Group_new("args");
rv=_readArgs(argc, argv, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error reading args (%d)", rv);
return rv;
}
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
aqh->dbArgs=dbArgs;
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
if (s && *s) {
GWEN_LOGGER_LEVEL ll;
ll=GWEN_Logger_Name2Level(s);
GWEN_Logger_SetLevel(NULL, ll);
}
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_DATA_DEFAULT_PIDFILE);
if (s && *s) {
free(aqh->pidFile);
aqh->pidFile=strdup(s);
rv=_createPidFile(s);
if (rv<0) {
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
return rv;
}
}
rv=_setupStorage(aqh, dbArgs);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
_setupIpc(aqh, dbArgs);
return 0;
}
int _setupStorage(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs)
{
const char *dataFolder;
GWEN_BUFFER *nameBuf;
AQH_STORAGE *sto;
int rv;
dataFolder=GWEN_DB_GetCharValue(dbArgs, "dataFolder", 0, AQHOME_DATA_DEFAULT_DATADIR);
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(nameBuf, "%s%s%s", dataFolder, GWEN_DIR_SEPARATOR_S, AQHOME_DATA_STATEFILENAME);
sto=AQH_Storage_new();
AQH_Storage_SetStateFile(sto, GWEN_Buffer_GetStart(nameBuf));
AQH_Storage_SetDataFileFolder(sto, dataFolder);
GWEN_Buffer_free(nameBuf);
rv=AQH_Storage_Init(sto);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
AQH_Storage_free(sto);
return rv;
}
aqh->storage=sto;
return 0;
}
void _setupIpc(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs)
{
const char *tcpAddress;
int tcpPort;
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
if (!(tcpAddress && *tcpAddress))
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, NULL);
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, -1);
if (tcpPort<0)
tcpPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_DATA_DEFAULT_IPC_PORT);
if (tcpAddress && *tcpAddress && tcpPort>0) {
GWEN_MSG_ENDPOINT *ep;
DBG_INFO(NULL, "Starting TCP service on \"%s\":%d", tcpAddress, tcpPort);
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptIpcFn, aqh);
aqh->ipcdEndpoint=ep;
}
}
GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep,
GWEN_SOCKET *sk,
const GWEN_INETADDRESS *addr,
GWEN_UNUSED void *data)
{
/* AQHOME_DATA *aqh;
*
* aqh=(AQHOME_DATA*) data;
*/
DBG_INFO(NULL, "Incoming IPC connection");
return AQH_IpcEndpoint_CreateIpcTcpServiceForSocket(sk, NULL, 0);
}
int _createPidFile(const char *pidFilename)
{
FILE *f;
int pidfd;
if (remove(pidFilename)==0) {
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
}
#ifdef HAVE_SYS_STAT_H
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (pidfd < 0) {
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
f = fdopen(pidfd, "w");
#else /* HAVE_STAT_H */
f=fopen(pidFilename,"w+");
#endif /* HAVE_STAT_H */
/* write pid */
#ifdef HAVE_GETPID
fprintf(f,"%d\n",getpid());
#else
fprintf(f,"-1\n");
#endif
if (fclose(f)) {
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
return 0;
}
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
{
int rv;
const GWEN_ARGS args[]= {
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"loglevel", /* name */
0, /* minnum */
1, /* maxnum */
"L", /* short option */
"loglevel", /* long option */
I18S("Specify loglevel"), /* short description */
I18S("Specify loglevel") /* long description */
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"tcpAddress", /* name */
0, /* minnum */
1, /* maxnum */
"t", /* short option */
"tcpaddress", /* long option */
I18S("Specify the TCP address to listen on (disabled if missing)"),
I18S("Specify the TCP address to listen on (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"tcpPort", /* name */
0, /* minnum */
1, /* maxnum */
"P", /* short option */
"tcpport", /* long option */
I18S("Specify the TCP port to listen on"),
I18S("Specify the TCP port to listen on")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"datafolder", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"datafolder", /* long option */
I18S("Folder where data files are stored"),
I18S("Folder where data files are stored")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"pidfile", /* name */
0, /* minnum */
1, /* maxnum */
"p", /* short option */
"pidfile", /* long option */
I18S("Specify the PID file"),
I18S("Specify the PID file")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"timeout", /* name */
0, /* minnum */
1, /* maxnum */
"T", /* short option */
"timeout", /* long option */
I18S("Specify timeout in second (default: no timeout)"),
I18S("Specify timeout in second (default: no timeout)")
},
{
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
GWEN_ArgsType_Int, /* type */
"help", /* name */
0, /* minnum */
0, /* maxnum */
"h", /* short option */
"help",
I18S("Show this help screen."),
I18S("Show this help screen.")
}
};
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
if (rv==GWEN_ARGS_RESULT_ERROR) {
fprintf(stderr, "ERROR: Could not parse arguments main\n");
return GWEN_ERROR_INVALID;
}
else if (rv==GWEN_ARGS_RESULT_HELP) {
GWEN_BUFFER *ubuf;
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
GWEN_Buffer_AppendArgs(ubuf,
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
AQHOME_VERSION_STRING,
argv[0]);
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
fprintf(stderr, "ERROR: Could not create help string\n");
return 1;
}
GWEN_Buffer_AppendString(ubuf, "\n");
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
GWEN_Buffer_free(ubuf);
return GWEN_ERROR_CLOSE;
}
return 0;
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_INIT_H
#define AQHOME_DATA_INIT_H
#include "./aqhome_data.h"
int AqHomeData_Init(AQHOME_DATA *aqh, int argc, char **argv);
#endif

View File

@@ -1,260 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop.h"
#include "./c_connect.h"
#include "./c_updatedata.h"
#include "./c_getdatapoints.h"
#include "./c_getlastdatapoint.h"
#include "./c_getvalues.h"
#include "./c_getdevices.h"
#include "./c_setdata.h"
#include "./c_addvalue.h"
#include "./c_annvalue.h"
#include "./c_moddevice.h"
#include "./aqhome_data_p.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/ipc/data/msg_data_datapoints.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/requests.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/msg_ipc.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define DISABLE_DEBUGLOG
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _readAndHandleIpcMessages(AQHOME_DATA *aqh);
static void _handleIpcEndpoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep);
static void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
static AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const char *nameForDriver);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeData_Loop(AQHOME_DATA *aqh, int timeoutInMsecs)
{
if (aqh) {
GWEN_MsgEndpoint_IoLoop(aqh->ipcdEndpoint, timeoutInMsecs);
_readAndHandleIpcMessages(aqh);
AQH_Requests_CheckTimeouts(aqh->requestTree);
AQH_Requests_Cleanup(aqh->requestTree);
}
}
int AqHomeData_WriteStorageIfChanged(AQHOME_DATA *aqh)
{
if (AQH_Storage_GetRuntimeFlags(aqh->storage) & AQH_STORAGE_RTFLAGS_MODIFIED) {
int rv;
DBG_INFO(NULL, "Storage modified, writing statefile");
rv=AqHomeData_LockStorage(aqh);
if (rv<0) {
DBG_INFO(NULL, "Error locking storage (%d)", rv);
return rv;
}
rv=AQH_Storage_WriteState(aqh->storage);
if (rv<0) {
DBG_INFO(NULL, "Error writing state file (%d)", rv);
AqHomeData_UnlockStorage(aqh);
return rv;
}
rv=AqHomeData_UnlockStorage(aqh);
if (rv<0) {
DBG_INFO(NULL, "Error unlocking storage (%d)", rv);
return rv;
}
}
return 0;
}
AQH_VALUE *AqHomeData_GetOrCreateValueForDriverWithTemplate(AQHOME_DATA *aqh,
GWEN_MSG_ENDPOINT *epDriver,
const AQH_VALUE *valueTemplate)
{
const char *serviceName;
AQH_VALUE *v;
GWEN_BUFFER *buf;
const char *valueName;
const char *deviceName;
serviceName=AQH_IpcEndpoint_GetServiceName(epDriver);
valueName=AQH_Value_GetName(valueTemplate);
deviceName=AQH_Value_GetDeviceName(valueTemplate);
buf=GWEN_Buffer_new(0, 256, 0, 1);
if (deviceName && *deviceName)
GWEN_Buffer_AppendArgs(buf, "%s/%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName, valueName);
else
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", valueName);
v=AQH_Storage_GetValueByNameForSystem(aqh->storage, GWEN_Buffer_GetStart(buf));
if (v==NULL) {
if (AQH_IpcEndpoint_GetPermissions(epDriver) & AQH_IPCENDPOINT_PERMS_ADDVALUE) {
AQH_DEVICE *device;
DBG_INFO(AQH_LOGDOMAIN, "Creating value \"%s\"", GWEN_Buffer_GetStart(buf));
device=(deviceName && *deviceName)?_getOrCreateDeviceForDriver(aqh, 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(aqh->storage, v);
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create value \"%s\"", GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
return NULL;
}
}
GWEN_Buffer_free(buf);
return v;
}
AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const char *deviceName)
{
const char *serviceName;
AQH_DEVICE *device;
GWEN_BUFFER *buf;
serviceName=AQH_IpcEndpoint_GetServiceName(epDriver);
buf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName);
device=AQH_Storage_GetDeviceByNameForSystem(aqh->storage, GWEN_Buffer_GetStart(buf));
if (device==NULL) {
if (AQH_IpcEndpoint_GetPermissions(epDriver) & AQH_IPCENDPOINT_PERMS_ADDDEVICE) {
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);
AQH_Device_SetNameForSystem(device, GWEN_Buffer_GetStart(buf));
AQH_Device_SetTimestampCreation(device, (uint64_t) time(NULL));
AQH_Storage_AddDevice(aqh->storage, device);
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create device \"%s\"", GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
return NULL;
}
}
GWEN_Buffer_free(buf);
return device;
}
void _readAndHandleIpcMessages(AQHOME_DATA *aqh)
{
if (aqh->ipcdEndpoint) {
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
while(ep) {
_handleIpcEndpoint(aqh, ep);
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
}
}
}
void _handleIpcEndpoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep)
{
GWEN_MSG *msg;
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) {
DBG_INFO(NULL, "Got IPS message %d (msgId=%d, refMsgId=%d) [%s]",
GWEN_IpcMsg_GetCode(msg),
GWEN_IpcMsg_GetMsgId(msg),
GWEN_IpcMsg_GetRefMsgId(msg),
GWEN_MsgEndpoint_GetName(ep));
if (AQH_Requests_HandleIpcMsg(aqh->requestTree, ep, msg)!=GWEN_MSG_REQUEST_RESULT_HANDLED)
_handleIpcMsg(aqh, ep, msg);
GWEN_Msg_free(msg);
}
}
void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
{
uint16_t code;
uint8_t protoId;
/* exec IPC message */
code=GWEN_IpcMsg_GetCode(msg);
protoId=GWEN_IpcMsg_GetProtoId(msg);
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet %d (%x)", (int) code, code);
switch(code) {
case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: AqHomeData_HandleConnect(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: AqHomeData_HandleUpdateData(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeData_HandleGetValues(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: AqHomeData_HandleGetDataPoints(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ: AqHomeData_HandleGetLastDataPoint(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeData_HandleSetData(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_ADDVALUE: AqHomeData_HandleAddValue(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: AqHomeData_HandleAnnounceValue(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: AqHomeData_HandleGetDevices(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: AqHomeData_HandleModDevice(aqh, ep, msg); break;
default: break;
}
}
else {
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
}
}

View File

@@ -1,30 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_LOOP_H
#define AQHOME_DATA_LOOP_H
#include "./aqhome_data.h"
void AqHomeData_Loop(AQHOME_DATA *aqh, int timeoutInMsecs);
int AqHomeData_WriteStorageIfChanged(AQHOME_DATA *aqh);
AQH_VALUE *AqHomeData_GetOrCreateValueForDriverWithTemplate(AQHOME_DATA *aqh,
GWEN_MSG_ENDPOINT *epDriver,
const AQH_VALUE *valueTemplate);
#endif

View File

@@ -13,10 +13,7 @@
#include <aqhome/api.h>
#include <aqhome/aqhome.h>
#include "./aqhome_data.h"
#include "./init.h"
#include "./fini.h"
#include "./loop.h"
#include "./server.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/logger.h>
@@ -58,8 +55,9 @@ static int _setupSigAction(struct sigaction *sa, int sig);
static void _signalHandler(int s);
#endif
static void _runService(AQHOME_DATA *aqh);
static void _writeCurrentState(AQHOME_DATA *aqh);
static void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop);
static void _writeCurrentState(AQH_OBJECT *aqh);
static int _diffInSeconds(time_t t1, time_t t0);
@@ -69,7 +67,7 @@ static void _writeCurrentState(AQHOME_DATA *aqh);
*/
#ifdef HAVE_SIGNAL_H
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT, saPIPE;
#endif
static int stopService=0;
@@ -84,7 +82,8 @@ static int stopService=0;
int main(int argc, char **argv)
{
int rv;
AQHOME_DATA *aqh;
AQH_EVENT_LOOP *eventLoop;
AQH_OBJECT *aqh;
GWEN_GUI *gui;
rv=GWEN_Init();
@@ -111,17 +110,18 @@ int main(int argc, char **argv)
gui=GWEN_Gui_CGui_new();
GWEN_Gui_SetGui(gui);
aqh=AqHomeData_new();
rv=AqHomeData_Init(aqh, argc, argv);
eventLoop=AQH_EventLoop_new();
aqh=AqHomeDataServer_new(eventLoop);
rv=AqHomeDataServer_Init(aqh, argc, argv);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return 2;
}
_runService(aqh);
_runService(aqh, eventLoop);
AqHomeData_Fini(aqh);
AqHomeData_free(aqh);
//AqHomeData_Fini(aqh);
AQH_Object_free(aqh);
GWEN_Gui_SetGui(NULL);
GWEN_Gui_free(gui);
@@ -131,14 +131,14 @@ int main(int argc, char **argv)
void _runService(AQHOME_DATA *aqh)
void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
{
time_t timeStart;
time_t timeLastWrite;
time_t timeLastConnectionCleanup;
int timeout;
timeout=AqHomeData_GetTimeout(aqh);
timeout=AqHomeDataServer_GetTimeout(aqh);
timeStart=time(NULL);
timeLastWrite=time(NULL);
timeLastConnectionCleanup=time(NULL);
@@ -146,25 +146,26 @@ void _runService(AQHOME_DATA *aqh)
while(!stopService) {
time_t now;
DBG_DEBUG(NULL, "Next loop");
AqHomeData_Loop(aqh, 2000);
DBG_INFO(NULL, "Next loop (%d clients)", AqHomeDataServer_GetClientNum(aqh));
AQH_EventLoop_Run(eventLoop, 2000);
AqHomeDataServer_HandleClientMsgs(aqh);
now=time(NULL);
if (((int)difftime(now, timeLastConnectionCleanup))>CONNCLEAN_INTERVAL_IN_SECS) {
DBG_DEBUG(NULL, "Cleanup connections");
GWEN_MsgEndpoint_RemoveUnconnectedAndEmptyChildren(AqHomeData_GetIpcdEndpoint(aqh));
if (_diffInSeconds(now, timeLastConnectionCleanup)>CONNCLEAN_INTERVAL_IN_SECS) {
DBG_INFO(NULL, "Cleanup connections");
AqHomeDataServer_CleanupClients(aqh);
timeLastConnectionCleanup=now;
}
if (((int)difftime(now, timeLastWrite))>WRITE_INTERVAL_IN_SECS) {
DBG_DEBUG(NULL, "Write time");
if (_diffInSeconds(now, timeLastWrite)>WRITE_INTERVAL_IN_SECS) {
DBG_INFO(NULL, "Write time");
_writeCurrentState(aqh);
timeLastWrite=now;
}
if (timeout && ((int)difftime(now, timeStart))>timeout) {
DBG_INFO(NULL, "Timeout");
if (timeout && (_diffInSeconds(now, timeStart)>timeout)) {
DBG_ERROR(NULL, "Timeout");
_writeCurrentState(aqh);
break;
}
@@ -173,11 +174,17 @@ void _runService(AQHOME_DATA *aqh)
void _writeCurrentState(AQHOME_DATA *aqh)
int _diffInSeconds(time_t t1, time_t t0)
{
return t1-t0;
}
void _writeCurrentState(AQH_OBJECT *aqh)
{
int rv;
rv=AqHomeData_WriteStorageIfChanged(aqh);
rv=AqHomeDataServer_WriteStorageIfChanged(aqh);
if (rv<0) {
DBG_ERROR(NULL, "ATTENTION: Could not write storage statefile (%d)", rv);
}
@@ -203,6 +210,10 @@ int _setSignalHandlers(void)
if (rv)
return rv;
rv=_setupSigAction(&saPIPE, SIGPIPE);
if (rv)
return rv;
# ifdef SIGTSTP
rv=_setupSigAction(&saTSTP, SIGTSTP);
if (rv)
@@ -244,6 +255,9 @@ void _signalHandler(int s)
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
stopService=1;
break;
case SIGPIPE:
DBG_WARN(0, "Received PIPE signal");
break;
default:
DBG_WARN(0, "Unknown signal %d",s);
break;

View File

@@ -0,0 +1,67 @@
/****************************************************************************
* 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 "./s_addvalue.h"
#include "./server_p.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_values.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleAddValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
AQH_MESSAGE *outMsg;
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
AQH_VALUE *recvdValue;
recvdValue=AQH_IpcdMessageValues_ReadFirstValue(tagList);
if (recvdValue) {
AQH_VALUE *value;
value=AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(o, ep, recvdValue);
if (value==NULL)
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
AQH_Value_free(recvdValue);
}
else
resultCode=AQH_MSGDATA_RESULT_ERROR_BADDATA;
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_DATA_ID,
AQH_IPC_PROTOCOL_DATA_VERSION,
AQH_MSGTYPE_IPC_DATA_RESULT,
AQH_Endpoint_GetNextMessageId(ep),
AQH_IpcMessage_GetMsgId(msg),
resultCode, NULL);
AQH_Endpoint_AddMsgOut(ep, outMsg);
}
}
}

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_S_ADDVALUE_H
#define AQHOME_DATA_S_ADDVALUE_H
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeDataServer_HandleAddValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
#endif

View File

@@ -0,0 +1,50 @@
/****************************************************************************
* 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 "./s_annvalue.h"
#include "./server_p.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_values.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleAnnounceValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
AQH_VALUE *recvdValue;
recvdValue=AQH_IpcdMessageValues_ReadFirstValue(tagList);
if (recvdValue) {
AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(o, ep, recvdValue);
AQH_Value_free(recvdValue);
}
}
}
}

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_S_ANNVALUE_H
#define AQHOME_DATA_S_ANNVALUE_H
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeDataServer_HandleAnnounceValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
#endif

View File

@@ -0,0 +1,82 @@
/****************************************************************************
* 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 "./s_connect.h"
#include "./server_p.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/m_ipc_connect.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleConnect(GWEN_UNUSED AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQH_MESSAGE *outMsg;
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
char *clientId=NULL;
char *userId=NULL;
char *passw=NULL;
uint32_t flags;
clientId=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_CLIENTID, NULL);
userId=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_USERID, NULL);
flags=AQH_Tag16_GetTagDataAsUint32(tagList, AQH_MSG_CONNECT_TAGS_FLAGS, 0);
passw=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_PASSWORD, NULL);
if (clientId)
AQH_Endpoint_SetServiceName(ep, clientId);
if (userId)
AQH_Endpoint_SetUserName(ep, userId);
if (flags & AQH_MSG_CONNECT_FLAGS_WANTUPDATES)
AQH_Endpoint_AddFlags(ep, AQH_ENDPOINT_FLAGS_WANTUPDATES);
/* TODO: add user management, for now we allow all */
AQH_Endpoint_SetPermissions(ep,
AQH_ENDPOINT_PERMS_LISTVALUES |
AQH_ENDPOINT_PERMS_READVALUE |
AQH_ENDPOINT_PERMS_ADDVALUE |
AQH_ENDPOINT_PERMS_LISTDATA |
AQH_ENDPOINT_PERMS_READDATA |
AQH_ENDPOINT_PERMS_ADDDATA |
AQH_ENDPOINT_PERMS_LISTDEVICES |
AQH_ENDPOINT_PERMS_READDEVICE |
AQH_ENDPOINT_PERMS_ADDDEVICE |
AQH_ENDPOINT_PERMS_MODDEVICE);
free(passw);
free(userId);
free(clientId);
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_DATA_ID,
AQH_IPC_PROTOCOL_DATA_VERSION,
AQH_MSGTYPE_IPC_DATA_RESULT,
AQH_Endpoint_GetNextMessageId(ep),
AQH_IpcMessage_GetMsgId(msg),
resultCode, NULL);
AQH_Endpoint_AddMsgOut(ep, outMsg);
}
}

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_S_CONNECT_H
#define AQHOME_DATA_S_CONNECT_H
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeDataServer_HandleConnect(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
#endif

View File

@@ -0,0 +1,228 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./s_getdatapoints.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/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/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 2048
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 1024
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId);
static int _getAndSendDataPointsNoNum(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
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);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
uint32_t refMsgId;
refMsgId=AQH_IpcMessage_GetMsgId(recvdMsg);
if (AQH_Endpoint_GetPermissions(ep) & AQH_ENDPOINT_PERMS_READDATA) {
char *valueName;
valueName=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL);
if (valueName && *valueName) {
AQH_VALUE *value;
uint64_t tsBegin;
uint64_t tsEnd;
uint64_t numRequested;
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);
value=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName);
if (value) {
int resultCode;
resultCode=_getAndSendDataPoints(xo->storage, ep, value, tsBegin, tsEnd, numRequested, refMsgId);
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, resultCode);
}
else {
DBG_INFO(NULL, "Value \"%s\" does not exist", valueName);
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_NOTFOUND);
}
free(valueName);
}
else {
DBG_INFO(NULL, "Missing value name");
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_BADDATA);
}
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_PERMS);
}
}
}
}
int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
const AQH_VALUE *value,
uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
uint32_t refMsgId)
{
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
return _getAndSendDataPointsWithNum(storage, ep, value, num, refMsgId);
}
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_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);
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;
}
}
void _sendDataPointsResponse(AQH_OBJECT *ep,
const AQH_VALUE *value, const uint64_t *tablePtr,
uint32_t refMsgId)
{
int numTableEntries;
int numDataPoints;
AQH_MESSAGE *outMsg;
numTableEntries=(int)(tablePtr[0]);
numDataPoints=numTableEntries/2;
outMsg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
AQH_Endpoint_GetNextMessageId(ep), refMsgId,
value, &(tablePtr[1]), numDataPoints);
AQH_Endpoint_AddMsgOut(ep, outMsg);
}
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;
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

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_S_GETDATAPOINTS_H
#define AQHOME_DATA_S_GETDATAPOINTS_H
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);
#endif

View File

@@ -0,0 +1,118 @@
/****************************************************************************
* 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 "./s_getdevices.h"
#include "./server_p.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_devices.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_DEVICESPERMSG 10
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _sendDeviceList(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleGetDevices(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
const AQH_DEVICE_LIST *origDeviceList;
uint32_t refMsgId;
refMsgId=AQH_IpcMessage_GetMsgId(msg);
DBG_ERROR(NULL, "HandleGetDevices");
origDeviceList=AQH_Storage_GetDeviceList(xo->storage);
if (origDeviceList) {
DBG_ERROR(NULL, "Have a list of %d devices", AQH_Device_List_GetCount(origDeviceList));
if (AQH_Device_List_GetCount(origDeviceList)<AQHOMEDATA_DEVICESPERMSG) {
DBG_ERROR(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_ERROR(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_ERROR(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 */
_sendDeviceList(ep, NULL, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
}
}
}
}
void _sendDeviceList(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId)
{
AQH_MESSAGE *msg;
DBG_ERROR(NULL, "Sending msg (refMsgId=%d)", refMsgId);
msg=AQH_IpcdMessageDevices_new(AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP, AQH_Endpoint_GetNextMessageId(ep), refMsgId, flags, vl);
AQH_Endpoint_AddMsgOut(ep, msg);
}

View File

@@ -6,14 +6,16 @@
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_C_ADDVALUE_H
#define AQHOME_DATA_C_ADDVALUE_H
#ifndef AQHOME_DATA_S_GETDEVICES_H
#define AQHOME_DATA_S_GETDEVICES_H
#include "./aqhome_data.h"
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeData_HandleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
void AqHomeDataServer_HandleGetDevices(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);

View File

@@ -0,0 +1,119 @@
/****************************************************************************
* 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 "./s_getvalues.h"
#include "./server_p.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_values.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define AQHOMEDATA_VALUESPERMSG 10
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleGetValues(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
const AQH_VALUE_LIST *origValueList;
uint32_t refMsgId;
refMsgId=AQH_IpcMessage_GetMsgId(msg);
DBG_INFO(NULL, "HandleGetValues");
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 */
_sendValueList(ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
}
}
}
}
void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
{
AQH_MESSAGE *msg;
DBG_ERROR(NULL, "Sending msg (refMsgId=%d)", refMsgId);
msg=AQH_IpcdMessageValues_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP, AQH_Endpoint_GetNextMessageId(ep), refMsgId, flags, vl);
AQH_Endpoint_AddMsgOut(ep, msg);
}

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_S_GETVALUES_H
#define AQHOME_DATA_S_GETVALUES_H
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeDataServer_HandleGetValues(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
#endif

View File

@@ -0,0 +1,105 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./s_moddevice.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/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.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>
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleModDevice(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
if (AQH_Endpoint_GetPermissions(ep) & AQH_ENDPOINT_PERMS_MODDEVICE) {
AQH_DEVICE *device;
device=AQH_IpcdMessageDevices_ReadFirstDevice(tagList);
if (device) {
const char *deviceNameForSystem;
deviceNameForSystem=AQH_Device_GetNameForSystem(device);
if (deviceNameForSystem && *deviceNameForSystem) {
AQH_DEVICE *storedDevice;
storedDevice=AQH_Storage_GetDeviceByNameForSystem(xo->storage, deviceNameForSystem);
if (storedDevice) {
const char *s;
s=AQH_Device_GetNameForGui(device);
if (s && *s)
AQH_Device_SetNameForGui(storedDevice, s);
s=AQH_Device_GetRoomName(device);
if (s && *s)
AQH_Device_SetRoomName(storedDevice, s);
s=AQH_Device_GetLocation(device);
if (s && *s)
AQH_Device_SetLocation(storedDevice, s);
s=AQH_Device_GetDescription(device);
if (s && *s)
AQH_Device_SetDescription(storedDevice, s);
AQH_Storage_AddRuntimeFlags(xo->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
resultCode=AQH_MSGDATA_RESULT_SUCCESS;
}
else {
DBG_INFO(NULL, "Device \"%s\" not found", deviceNameForSystem);
resultCode=AQH_MSGDATA_RESULT_ERROR_NOTFOUND;
}
}
else {
DBG_INFO(NULL, "No name for value");
resultCode=AQH_MSGDATA_RESULT_ERROR_NOTFOUND;
}
}
else {
DBG_INFO(NULL, "No device info in message");
resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID;
}
}
else {
DBG_ERROR(NULL, "No permissions to read data");
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
}
AqHomeDataServer_SendResponseResultToEndpoint(ep, AQH_IpcMessage_GetMsgId(recvdMsg), resultCode);
}
}
}

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_S_MODDEVICE_H
#define AQHOME_DATA_S_MODDEVICE_H
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeDataServer_HandleModDevice(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);
#endif

View File

@@ -0,0 +1,282 @@
/****************************************************************************
* 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 "./s_setdata.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/m_ipc_result.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_setdata.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define R_SETDATA_REQUEST_EXPIRE_SECS 20
#define R_SETDATA_SUBREQUEST_EXPIRE_SECS 10
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o,
AQH_OBJECT *epSrc, uint32_t requestMsgId,
AQH_OBJECT *epDriver,
const AQH_VALUE *v, const char *data);
static void _rqSubRequestFinished(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST *subRq, int reason);
static void _rqAbort(AQH_MSG_REQUEST *rq, int reason);
static AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, const char *data);
static int _subRqHandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg);
static void _subRqAbort(AQH_MSG_REQUEST *rq, int reason);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
uint32_t msgId;
AQH_VALUE *recvdValue;
msgId=AQH_IpcMessage_GetMsgId(recvdMsg);
DBG_INFO(NULL, "Received IPC SetDataRequest message (msgId=%d)", msgId);
recvdValue=AQH_IpcdMessageSetData_ReadValue(tagList);
if (recvdValue) {
const char *valueName;
char *valueDataFreeable;
AQH_VALUE *systemValue;
valueName=AQH_Value_GetNameForSystem(recvdValue);
valueDataFreeable=AQH_IpcdMessageSetData_ReadData(tagList);
systemValue=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName);
if (systemValue) {
if (AQH_Value_GetValueType(systemValue)==AQH_ValueType_Actor) {
const char *driverName;
driverName=AQH_Value_GetDriver(systemValue);
if (driverName && *driverName) {
AQH_OBJECT *epDriver;
epDriver=AqHomeDataServer_GetIpcEndpointByServiceName(o, driverName);
if (epDriver) {
AQH_MSG_REQUEST *rq;
DBG_ERROR(NULL, "Creating SETDATA request for driver endpoint (%s)", AQH_Endpoint_GetServiceName(epDriver));
rq=_mkRequest_SetData(o, epSrc, msgId, epDriver, systemValue, valueDataFreeable);
AqHomeDataServer_AddRequestToTree(o, rq);
}
else {
DBG_ERROR(NULL, "Driver \"%s\" not available", driverName);
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
}
}
else {
DBG_ERROR(NULL, "No driver name");
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
}
} /* if actor */
else {
DBG_ERROR(NULL, "Value \"%s\" is not an actor", valueName);
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
}
}
else {
DBG_ERROR(NULL, "Unknown value \"%s\"", valueName);
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");
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_BADDATA);
}
}
}
}
/* ------------------------------------------------------------------------------------------------
* IPC Request SETDATA
*/
AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o,
AQH_OBJECT *epSrc, uint32_t requestMsgId,
AQH_OBJECT *epDriver,
const AQH_VALUE *v, const char *data)
{
AQH_MSG_REQUEST *rq;
AQH_MSG_REQUEST *subRq;
rq=AQH_MsgRequest_new();
AQH_MsgRequest_SetPrivateData(rq, o);
AQH_MsgRequest_SetEndpoint(rq, epSrc);
AQH_MsgRequest_SetRequestMsgId(rq, requestMsgId);
AQH_MsgRequest_SetSubRequestFinishedFn(rq, _rqSubRequestFinished);
AQH_MsgRequest_SetAbortFn(rq, _rqAbort);
AQH_MsgRequest_SetTimestamps(rq, R_SETDATA_REQUEST_EXPIRE_SECS);
subRq=_mkSubRequest_SetData(o, epDriver, v, data);
AQH_MsgRequest_Tree2_AddChild(rq, subRq);
return rq;
}
void _rqSubRequestFinished(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST *subRq, int reason)
{
AQH_OBJECT *ep;
uint32_t refMsgId;
int result;
DBG_DEBUG(NULL, "SubRequest finished (reason: %d)", reason);
refMsgId=AQH_MsgRequest_GetRequestMsgId(rq);
ep=AQH_MsgRequest_GetEndpoint(rq);
result=AQH_MsgRequest_GetResult(subRq);
if (reason==AQH_MSG_REQUEST_REASON_ABORTED)
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
else
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, result);
AQH_MsgRequest_SetResult(rq, result);
AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE);
}
void _rqAbort(AQH_MSG_REQUEST *rq, int reason)
{
AQH_OBJECT *ep;
uint32_t refMsgId;
AQH_MSG_REQUEST *rqParent;
DBG_INFO(NULL, "Aborting request");
refMsgId=AQH_MsgRequest_GetRequestMsgId(rq);
ep=AQH_MsgRequest_GetEndpoint(rq);
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE);
rqParent=AQH_MsgRequest_Tree2_GetParent(rq);
if (rqParent)
AQH_MsgRequest_SubRequestFinished(rqParent, rq, reason);
}
/* ------------------------------------------------------------------------------------------------
* Driver Request SETDATA
*/
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;
AQH_MESSAGE *driverMsg;
rq=AQH_MsgRequest_new();
AQH_MsgRequest_SetPrivateData(rq, o);
AQH_MsgRequest_SetEndpoint(rq, epDriver);
AQH_MsgRequest_SetHandleResponseFn(rq, _subRqHandleResponse);
AQH_MsgRequest_SetAbortFn(rq, _subRqAbort);
msgId=AQH_Endpoint_GetNextMessageId(epDriver);
AQH_MsgRequest_SetRequestMsgId(rq, msgId);
AQH_MsgRequest_SetTimestamps(rq, R_SETDATA_SUBREQUEST_EXPIRE_SECS);
driverMsg=AQH_IpcdMessageSetData_new(AQH_MSGTYPE_IPC_DATA_SETDATA, msgId, 0, v, data);
AQH_Endpoint_AddMsgOut(epDriver, driverMsg);
return rq;
}
int _subRqHandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg)
{
DBG_DEBUG(NULL, "Checking message from driver");
if (AQH_IpcMessage_GetCode(msg)==AQH_MSGTYPE_IPC_DATA_RESULT) {
GWEN_TAG16_LIST *tagList;
tagList=AQH_IpcMessageTag16_ParsePayload(msg, 0);
if (tagList) {
uint32_t result;
AQH_MSG_REQUEST *rqParent;
result=AQH_IpcMessageResult_GetResult(tagList);
DBG_INFO(NULL, "Received result for request: %d", result);
AQH_MsgRequest_SetResult(rq, result);
AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE);
rqParent=AQH_MsgRequest_Tree2_GetParent(rq);
if (rqParent)
AQH_MsgRequest_SubRequestFinished(rqParent, rq, AQH_MSG_REQUEST_REASON_DONE);
GWEN_Tag16_List_free(tagList);
return AQH_MSG_REQUEST_RESULT_HANDLED;
}
else {
DBG_ERROR(NULL, "Bad message %d (no TAG16 data)", AQH_IpcMessage_GetCode(msg));
}
}
else {
DBG_ERROR(NULL, "Unexpected response message %d", AQH_IpcMessage_GetCode(msg));
}
return AQH_MSG_REQUEST_RESULT_NOT_HANDLED;
}
void _subRqAbort(AQH_MSG_REQUEST *rq, int reason)
{
AQH_MSG_REQUEST *rqParent;
DBG_INFO(NULL, "Aborting request");
AQH_MsgRequest_SetResult(rq, AQH_MSGDATA_RESULT_ERROR_GENERIC);
AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE);
rqParent=AQH_MsgRequest_Tree2_GetParent(rq);
if (rqParent)
AQH_MsgRequest_SubRequestFinished(rqParent, rq, reason);
}

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_S_SETDATA_H
#define AQHOME_DATA_S_SETDATA_H
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);
#endif

View File

@@ -0,0 +1,171 @@
/****************************************************************************
* 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 "./s_updatedata.h"
#include "./server_p.h"
#include <aqhome/data/value.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_multidata.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define DISABLE_DEBUGLOG
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _storeDataPoints(AQHOME_SERVER *xo, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues);
static void _sendDataChangedMsgToAllClients(AQHOME_SERVER *xo, AQH_OBJECT *epSrc,
const AQH_VALUE *v, const uint64_t *dataPoints, int numValues);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeDataServer_HandleUpdateData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQHOME_SERVER *xo;
xo=AqHomeDataServer_GetServerData(o);
if (xo) {
AQH_MESSAGE *outMsg;
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
AQH_VALUE *recvdValue;
recvdValue=AQH_IpcdMessageMultiData_ReadValue(tagList);
if (recvdValue) {
const char *valueName;
const uint64_t *dataPoints=NULL;
uint64_t numberOfPoints=0;
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
AQH_IpcdMessageMultiData_ReadDatapoints(tagList, &dataPoints, &numberOfPoints);
if (numberOfPoints>0) {
AQH_VALUE *value;
value=AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(o, ep, recvdValue);
if (value) {
if (AQH_Endpoint_GetPermissions(ep) & AQH_ENDPOINT_PERMS_ADDDATA) {
resultCode=_storeDataPoints(xo, value, dataPoints, numberOfPoints);
if (resultCode==AQH_MSGDATA_RESULT_SUCCESS)
_sendDataChangedMsgToAllClients(xo, ep, value, dataPoints, numberOfPoints);
}
else {
DBG_INFO(NULL, "No permissions to add data to value \"%s\"", valueName);
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
}
}
else {
DBG_INFO(NULL, "No permissions to add/create value \"%s\"", valueName);
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
}
}
else {
DBG_INFO(NULL, "No datapoints");
resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID;
}
AQH_Value_free(recvdValue);
}
else {
DBG_INFO(NULL, "No value");
resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID;
}
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_DATA_ID,
AQH_IPC_PROTOCOL_DATA_VERSION,
AQH_MSGTYPE_IPC_DATA_RESULT,
AQH_Endpoint_GetNextMessageId(ep),
AQH_IpcMessage_GetMsgId(msg),
resultCode, NULL);
AQH_Endpoint_AddMsgOut(ep, outMsg);
}
}
}
int _storeDataPoints(AQHOME_SERVER *xo, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues)
{
uint32_t i;
for(i=0; i<numValues; i++) {
uint64_t timestamp;
union {double f; uint64_t i;} u;
int rv;
timestamp=*(dataPoints++);
u.i=*(dataPoints++);
rv=AQH_Storage_AddDatapoint(xo->storage, AQH_Value_GetId(v), timestamp, u.f);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return AQH_MSGDATA_RESULT_ERROR_GENERIC;
}
else {
DBG_INFO(NULL, "Datapoint added for value \"%s\"", AQH_Value_GetNameForSystem(v));
}
} /* for */
return AQH_MSGDATA_RESULT_SUCCESS;
}
void _sendDataChangedMsgToAllClients(AQHOME_SERVER *xo, AQH_OBJECT *epSrc, const AQH_VALUE *v, const uint64_t *dataPoints, int numValues)
{
AQH_OBJECT *ep;
ep=AQH_Object_List_First(xo->tcpClientList);
while(ep) {
if (ep!=epSrc) {
if (AQH_Endpoint_GetFlags(ep) & AQH_ENDPOINT_FLAGS_WANTUPDATES) {
AQH_MESSAGE *msg;
DBG_DEBUG(AQH_LOGDOMAIN, "Sending update msg to endpoint");
msg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
AQH_Endpoint_GetNextMessageId(ep), 0,
v, dataPoints, numValues);
AQH_Endpoint_AddMsgOut(ep, msg);
}
else {
DBG_DEBUG(AQH_LOGDOMAIN, "Endpoint doesn't want updates");
}
}
else {
DBG_DEBUG(AQH_LOGDOMAIN, "Not sending update msg to source of updates");
}
ep=AQH_Object_List_Next(ep);
}
}

View File

@@ -0,0 +1,27 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_S_UPDATEDATA_H
#define AQHOME_DATA_S_UPDATEDATA_H
#include "./server.h"
#include <gwenhywfar/tag16.h>
void AqHomeDataServer_HandleUpdateData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
#endif

857
apps/aqhome-data/server.c Normal file
View File

@@ -0,0 +1,857 @@
/****************************************************************************
* 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 "./server_p.h"
#include "./s_connect.h"
#include "./s_getdevices.h"
#include "./s_getvalues.h"
#include "./s_addvalue.h"
#include "./s_annvalue.h"
#include "./s_updatedata.h"
#include "./s_setdata.h"
#include "./s_getdatapoints.h"
#include "./s_moddevice.h"
#include <aqhome/aqhome.h>
#include <aqhome/ipc2/ipc_server.h>
#include <aqhome/ipc2/tcpd_object.h>
#include <aqhome/msg/ipc/m_ipc.h>
#include <aqhome/msg/ipc/m_ipc_result.h>
#include <aqhome/msg/ipc/m_ipc_tag16.h>
#include <aqhome/msg/ipc/data/m_ipcd.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
enum {
AQH_AQHOME_SERVER_SLOT_NEWCLIENT=1,
AQH_AQHOME_SERVER_SLOT_CLOSED
};
/* ------------------------------------------------------------------------------------------------
* global vars
* ------------------------------------------------------------------------------------------------
*/
GWEN_INHERIT(AQH_OBJECT, AQHOME_SERVER)
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
static int _setupStorage(AQHOME_SERVER *xo, GWEN_DB_NODE *dbArgs);
static int _setupIpc(AQH_OBJECT *o, AQHOME_SERVER *xo, GWEN_DB_NODE *dbArgs);
static int _handleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, int param1, void *param2);
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 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);
/* ------------------------------------------------------------------------------------------------
* implementation
* ------------------------------------------------------------------------------------------------
*/
AQH_OBJECT *AqHomeDataServer_new(AQH_EVENT_LOOP *eventLoop)
{
AQH_OBJECT *o;
AQHOME_SERVER *xo;
o=AQH_Object_new(eventLoop);
GWEN_NEW_OBJECT(AQHOME_SERVER, xo);
GWEN_INHERIT_SETDATA(AQH_OBJECT, AQHOME_SERVER, o, xo, _freeData);
xo->storageMutex=GWEN_Mutex_new();
xo->tcpClientList=AQH_Object_List_new();
xo->requestTree=AQH_MsgRequest_new();
AQH_Object_SetSignalHandlerFn(o, _handleSignal);
return o;
}
void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p)
{
AQHOME_SERVER *xo;
xo=(AQHOME_SERVER*) p;
GWEN_Mutex_free(xo->storageMutex);
if (xo->ipcServer) {
AQH_Object_Disable(xo->ipcServer);
AQH_Object_free(xo->ipcServer);
xo->ipcServer=NULL;
}
if (xo->tcpClientList) {
AQH_Object_List_free(xo->tcpClientList);
xo->tcpClientList=NULL;
}
GWEN_DB_Group_free(xo->dbArgs);
AQH_Storage_free(xo->storage);
free(xo->pidFile);
GWEN_FREE_OBJECT(xo);
}
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* getters, setters
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
*/
AQHOME_SERVER *AqHomeDataServer_GetServerData(const AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
return xo;
}
int AqHomeDataServer_GetTimeout(const AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo)
return xo->timeout;
return 0;
}
int AqHomeDataServer_GetClientNum(const AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo)
return AQH_Object_List_GetCount(xo->tcpClientList);
return 0;
}
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* init
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
*/
int AqHomeDataServer_Init(AQH_OBJECT *o, int argc, char **argv)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
GWEN_DB_NODE *dbArgs;
int rv;
const char *s;
dbArgs=GWEN_DB_Group_new("args");
rv=_readArgs(argc, argv, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error reading args (%d)", rv);
return rv;
}
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
xo->dbArgs=dbArgs;
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
if (s && *s) {
GWEN_LOGGER_LEVEL ll;
ll=GWEN_Logger_Name2Level(s);
GWEN_Logger_SetLevel(NULL, ll);
}
xo->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_DATA_DEFAULT_PIDFILE);
if (s && *s) {
free(xo->pidFile);
xo->pidFile=strdup(s);
rv=_createPidFile(s);
if (rv<0) {
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
return rv;
}
}
rv=_setupStorage(xo, dbArgs);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=_setupIpc(o, xo, dbArgs);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
return 0;
}
else {
DBG_ERROR(NULL, "Not of type AQHOME_SERVER object");
return GWEN_ERROR_INVALID;
}
}
int _setupStorage(AQHOME_SERVER *xo, GWEN_DB_NODE *dbArgs)
{
const char *dataFolder;
GWEN_BUFFER *nameBuf;
AQH_STORAGE *sto;
int rv;
dataFolder=GWEN_DB_GetCharValue(dbArgs, "dataFolder", 0, AQHOME_DATA_DEFAULT_DATADIR);
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(nameBuf, "%s%s%s", dataFolder, GWEN_DIR_SEPARATOR_S, AQHOME_DATA_STATEFILENAME);
sto=AQH_Storage_new();
AQH_Storage_SetStateFile(sto, GWEN_Buffer_GetStart(nameBuf));
AQH_Storage_SetDataFileFolder(sto, dataFolder);
GWEN_Buffer_free(nameBuf);
rv=AQH_Storage_Init(sto);
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
AQH_Storage_free(sto);
return rv;
}
xo->storage=sto;
return 0;
}
int _setupIpc(AQH_OBJECT *o, AQHOME_SERVER *xo, GWEN_DB_NODE *dbArgs)
{
const char *tcpAddress;
int tcpPort;
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
if (!(tcpAddress && *tcpAddress))
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, NULL);
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, -1);
if (tcpPort<0)
tcpPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_DATA_DEFAULT_IPC_PORT);
if (tcpAddress && *tcpAddress && tcpPort>0) {
int fd;
DBG_ERROR(NULL, "Starting TCP service on \"%s\":%d", tcpAddress, tcpPort);
fd=AQH_TcpdObject_CreateListeningSocket(tcpAddress, tcpPort);
if (fd<0) {
DBG_INFO(NULL, "here");
return GWEN_ERROR_IO;
}
xo->ipcServer=AQH_IpcServerObject_new(AQH_Object_GetEventLoop(o), fd);
AQH_Object_AddLink(xo->ipcServer, AQH_IPC_SERVER_SIGNAL_NEWCLIENT, AQH_AQHOME_SERVER_SLOT_NEWCLIENT, o);
AQH_Object_Enable(xo->ipcServer);
return 0;
}
else {
DBG_ERROR(NULL, "Missing server address");
return GWEN_ERROR_GENERIC;
}
}
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* signal handler
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
*/
int _handleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, GWEN_UNUSED int param1, void *param2)
{
switch(slotId) {
case AQH_AQHOME_SERVER_SLOT_NEWCLIENT: return _handleNewClient(o, (AQH_OBJECT*) param2);
case AQH_AQHOME_SERVER_SLOT_CLOSED: return _handleClientDown(o, senderObject);
default:
break;
}
return 0; /* not handled */
}
int _handleNewClient(AQH_OBJECT *o, AQH_OBJECT *clientEndpoint)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
DBG_ERROR(NULL, "New IPC client");
AQH_Object_AddLink(clientEndpoint, AQH_ENDPOINT_SIGNAL_CLOSED, AQH_AQHOME_SERVER_SLOT_CLOSED, o);
AQH_Object_List_Add(clientEndpoint, xo->tcpClientList);
return 1; /* handled */
}
return 0; /* not handled */
}
int _handleClientDown(AQH_OBJECT *o, AQH_OBJECT *clientEndpoint)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
DBG_ERROR(NULL, "IPC client down");
AQH_Object_AddFlags(clientEndpoint, AQH_OBJECT_FLAGS_DELETE);
return 1; /* handled */
}
return 0; /* not handled */
}
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* client management functions
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
*/
void AqHomeDataServer_CleanupClients(AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
AQH_OBJECT *ep;
ep=AQH_Object_List_First(xo->tcpClientList);
while(ep) {
AQH_OBJECT *epNext;
epNext=AQH_Object_List_Next(ep);
if (AQH_Object_GetFlags(ep) & AQH_OBJECT_FLAGS_DELETE) {
AQH_Object_List_Del(ep);
AQH_Object_free(ep);
}
ep=epNext;
} /* while */
}
}
void AqHomeDataServer_HandleClientMsgs(AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
AQH_OBJECT *ep;
ep=AQH_Object_List_First(xo->tcpClientList);
while(ep) {
AQH_OBJECT *epNext;
epNext=AQH_Object_List_Next(ep);
_handleMsgsFromClient(o, xo, ep);
ep=epNext;
} /* while */
}
}
void _handleMsgsFromClient(AQH_OBJECT *o, AQHOME_SERVER *xo, AQH_OBJECT *ep)
{
AQH_MESSAGE *msg;
while( (msg=AQH_Endpoint_GetNextMsgIn(ep)) ) {
AQH_Message_SetObject(msg, ep);
if (AQH_Request_Tree2_HandleIpcMsg(xo->requestTree, ep, msg)!=AQH_MSG_REQUEST_RESULT_HANDLED)
_handleMsgFromClient(o, ep, msg);
AQH_Message_free(msg);
}
}
void _handleMsgFromClient(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg)
{
GWEN_TAG16_LIST *tagList;
uint16_t code;
uint8_t protoId;
tagList=AQH_IpcMessageTag16_ParsePayload(msg, 0);
code=AQH_IpcMessage_GetCode(msg);
protoId=AQH_IpcMessage_GetProtoId(msg);
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
DBG_INFO(NULL, "Received IPC packet %d (%x)", (int) code, code);
switch(code) {
case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: AqHomeDataServer_HandleConnect(o, ep, msg, tagList); break;
case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: AqHomeDataServer_HandleUpdateData(o, ep, msg, tagList); break;
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeDataServer_HandleGetValues(o, ep, msg, tagList); break;
case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: AqHomeDataServer_HandleGetDataPoints(o, ep, msg, tagList); break;
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeDataServer_HandleSetData(o, ep, msg, tagList); break;
case AQH_MSGTYPE_IPC_DATA_ADDVALUE: AqHomeDataServer_HandleAddValue(o, ep, msg, tagList); break;
case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: AqHomeDataServer_HandleAnnounceValue(o, ep, msg, tagList); break;
case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: AqHomeDataServer_HandleGetDevices(o, ep, msg, tagList); break;
case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: AqHomeDataServer_HandleModDevice(o, ep, msg, tagList); break;
default: break;
}
}
else {
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
}
GWEN_Tag16_List_free(tagList);
}
AQH_OBJECT *AqHomeDataServer_GetIpcEndpointByServiceName(const AQH_OBJECT *o, const char *serviceName)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
AQH_OBJECT *ep;
ep=AQH_Object_List_First(xo->tcpClientList);
while(ep) {
const char *s;
s=AQH_Endpoint_GetServiceName(ep);
if (s && *s && strcasecmp(s, serviceName)==0)
return ep;
ep=AQH_Object_List_Next(ep);
}
}
return NULL;
}
void AqHomeDataServer_SendResponseResultToEndpoint(AQH_OBJECT *ep, uint32_t refMsgId, int result)
{
AQH_MESSAGE *msg;
msg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, AQH_MSGTYPE_IPC_DATA_RESULT,
AQH_Endpoint_GetNextMessageId(ep), refMsgId, result, NULL);
AQH_Endpoint_AddMsgOut(ep, msg);
}
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* request management functions
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
*/
AQH_MSG_REQUEST *AqHomeDataServer_GetRequestTree(const AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo)
return xo->requestTree;
return NULL;
}
void AqHomeDataServer_AddRequestToTree(AQH_OBJECT *o, AQH_MSG_REQUEST *rq)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo && rq)
AQH_MsgRequest_Tree2_AddChild(xo->requestTree, rq);
}
void AqHomeDataServer_CleanupRequests(AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
AQH_Request_Tree2_CheckTimeouts(xo->requestTree);
AQH_Request_Tree2_Cleanup(xo->requestTree);
}
}
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* storage management functions
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
*/
int AqHomeDataServer_LockStorage(AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
int rv;
rv=GWEN_Mutex_Lock(xo->storageMutex);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on storage mutex");
return rv;
}
return rv;
}
return GWEN_ERROR_INVALID;
}
int AqHomeDataServer_UnlockStorage(AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
int rv;
rv=GWEN_Mutex_Unlock(xo->storageMutex);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on storage mutex");
return rv;
}
return rv;
}
return GWEN_ERROR_INVALID;
}
int AqHomeDataServer_WriteStorageIfChanged(AQH_OBJECT *o)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
if (AQH_Storage_GetRuntimeFlags(xo->storage) & AQH_STORAGE_RTFLAGS_MODIFIED) {
int rv;
DBG_INFO(NULL, "Storage modified, writing statefile");
rv=AqHomeDataServer_LockStorage(o);
if (rv<0) {
DBG_INFO(NULL, "Error locking storage (%d)", rv);
return rv;
}
rv=AQH_Storage_WriteState(xo->storage);
if (rv<0) {
DBG_INFO(NULL, "Error writing state file (%d)", rv);
AqHomeDataServer_UnlockStorage(o);
return rv;
}
rv=AqHomeDataServer_UnlockStorage(o);
if (rv<0) {
DBG_INFO(NULL, "Error unlocking storage (%d)", rv);
return rv;
}
}
return 0;
}
return GWEN_ERROR_INVALID;
}
AQH_VALUE *AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *valueTemplate)
{
AQHOME_SERVER *xo;
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
if (xo) {
const char *serviceName;
AQH_VALUE *v;
GWEN_BUFFER *buf;
const char *valueName;
const char *deviceName;
serviceName=AQH_Endpoint_GetServiceName(epDriver);
valueName=AQH_Value_GetName(valueTemplate);
deviceName=AQH_Value_GetDeviceName(valueTemplate);
buf=GWEN_Buffer_new(0, 256, 0, 1);
if (deviceName && *deviceName)
GWEN_Buffer_AppendArgs(buf, "%s/%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName, valueName);
else
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", valueName);
v=AQH_Storage_GetValueByNameForSystem(xo->storage, GWEN_Buffer_GetStart(buf));
if (v==NULL) {
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;
}
}
GWEN_Buffer_free(buf);
return v;
}
return NULL;
}
AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_SERVER *xo, AQH_OBJECT *epDriver, const char *deviceName)
{
const char *serviceName;
AQH_DEVICE *device;
GWEN_BUFFER *buf;
serviceName=AQH_Endpoint_GetServiceName(epDriver);
buf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName);
device=AQH_Storage_GetDeviceByNameForSystem(xo->storage, GWEN_Buffer_GetStart(buf));
if (device==NULL) {
if (AQH_Endpoint_GetPermissions(epDriver) & AQH_ENDPOINT_PERMS_ADDDEVICE) {
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);
AQH_Device_SetNameForSystem(device, GWEN_Buffer_GetStart(buf));
AQH_Device_SetTimestampCreation(device, (uint64_t) time(NULL));
AQH_Storage_AddDevice(xo->storage, device);
}
else {
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create device \"%s\"", GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
return NULL;
}
}
GWEN_Buffer_free(buf);
return device;
}
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
* helper functions
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
*/
int _createPidFile(const char *pidFilename)
{
FILE *f;
int pidfd;
if (remove(pidFilename)==0) {
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
}
#ifdef HAVE_SYS_STAT_H
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (pidfd < 0) {
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
f = fdopen(pidfd, "w");
#else /* HAVE_STAT_H */
f=fopen(pidFilename,"w+");
#endif /* HAVE_STAT_H */
/* write pid */
#ifdef HAVE_GETPID
fprintf(f,"%d\n",getpid());
#else
fprintf(f,"-1\n");
#endif
if (fclose(f)) {
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
return 0;
}
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
{
int rv;
const GWEN_ARGS args[]= {
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"loglevel", /* name */
0, /* minnum */
1, /* maxnum */
"L", /* short option */
"loglevel", /* long option */
I18S("Specify loglevel"), /* short description */
I18S("Specify loglevel") /* long description */
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"tcpAddress", /* name */
0, /* minnum */
1, /* maxnum */
"t", /* short option */
"tcpaddress", /* long option */
I18S("Specify the TCP address to listen on (disabled if missing)"),
I18S("Specify the TCP address to listen on (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"tcpPort", /* name */
0, /* minnum */
1, /* maxnum */
"P", /* short option */
"tcpport", /* long option */
I18S("Specify the TCP port to listen on"),
I18S("Specify the TCP port to listen on")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"datafolder", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"datafolder", /* long option */
I18S("Folder where data files are stored"),
I18S("Folder where data files are stored")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"pidfile", /* name */
0, /* minnum */
1, /* maxnum */
"p", /* short option */
"pidfile", /* long option */
I18S("Specify the PID file"),
I18S("Specify the PID file")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"timeout", /* name */
0, /* minnum */
1, /* maxnum */
"T", /* short option */
"timeout", /* long option */
I18S("Specify timeout in second (default: no timeout)"),
I18S("Specify timeout in second (default: no timeout)")
},
{
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
GWEN_ArgsType_Int, /* type */
"help", /* name */
0, /* minnum */
0, /* maxnum */
"h", /* short option */
"help",
I18S("Show this help screen."),
I18S("Show this help screen.")
}
};
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
if (rv==GWEN_ARGS_RESULT_ERROR) {
fprintf(stderr, "ERROR: Could not parse arguments main\n");
return GWEN_ERROR_INVALID;
}
else if (rv==GWEN_ARGS_RESULT_HELP) {
GWEN_BUFFER *ubuf;
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
GWEN_Buffer_AppendArgs(ubuf,
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
AQHOME_VERSION_STRING,
argv[0]);
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
fprintf(stderr, "ERROR: Could not create help string\n");
return 1;
}
GWEN_Buffer_AppendString(ubuf, "\n");
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
GWEN_Buffer_free(ubuf);
return GWEN_ERROR_CLOSE;
}
return 0;
}

59
apps/aqhome-data/server.h Normal file
View File

@@ -0,0 +1,59 @@
/****************************************************************************
* 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_DATA_SERVER_H
#define AQHOME_DATA_SERVER_H
#include <aqhome/data/storage.h>
#include <aqhome/events2/object.h>
#include <aqhome/ipc2/msgrequest.h>
#define AQH_ENDPOINT_PERMS_LISTVALUES 0x0001
#define AQH_ENDPOINT_PERMS_READVALUE 0x0002
#define AQH_ENDPOINT_PERMS_ADDVALUE 0x0004
#define AQH_ENDPOINT_PERMS_LISTDATA 0x0010
#define AQH_ENDPOINT_PERMS_READDATA 0x0020
#define AQH_ENDPOINT_PERMS_ADDDATA 0x0040
#define AQH_ENDPOINT_PERMS_SETDATA 0x0080
#define AQH_ENDPOINT_PERMS_LISTDEVICES 0x0100
#define AQH_ENDPOINT_PERMS_READDEVICE 0x0200
#define AQH_ENDPOINT_PERMS_ADDDEVICE 0x0400
#define AQH_ENDPOINT_PERMS_MODDEVICE 0x0800
AQH_OBJECT *AqHomeDataServer_new(AQH_EVENT_LOOP *eventLoop);
int AqHomeDataServer_Init(AQH_OBJECT *o, int argc, char **argv);
int AqHomeDataServer_GetTimeout(const AQH_OBJECT *o);
int AqHomeDataServer_GetClientNum(const AQH_OBJECT *o);
void AqHomeDataServer_CleanupClients(AQH_OBJECT *o);
void AqHomeDataServer_HandleClientMsgs(AQH_OBJECT *o);
AQH_OBJECT *AqHomeDataServer_GetIpcEndpointByServiceName(const AQH_OBJECT *o, const char *serviceName);
void AqHomeDataServer_SendResponseResultToEndpoint(AQH_OBJECT *ep, uint32_t refMsgId, int result);
AQH_MSG_REQUEST *AqHomeDataServer_GetRequestTree(const AQH_OBJECT *o);
void AqHomeDataServer_AddRequestToTree(AQH_OBJECT *o, AQH_MSG_REQUEST *rq);
void AqHomeDataServer_CleanupRequests(AQH_OBJECT *o);
int AqHomeDataServer_LockStorage(AQH_OBJECT *o);
int AqHomeDataServer_UnlockStorage(AQH_OBJECT *o);
int AqHomeDataServer_WriteStorageIfChanged(AQH_OBJECT *o);
AQH_VALUE *AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *valueTemplate);
#endif

View File

@@ -1,16 +1,18 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_DATA_P_H
#define AQHOME_DATA_P_H
#ifndef AQHOME_DATA_SERVER_P_H
#define AQHOME_DATA_SERVER_P_H
#include "./aqhome_data.h"
#include "./server.h"
#include <aqhome/events2/object.h>
#include <gwenhywfar/mutex.h>
@@ -23,22 +25,25 @@
struct AQHOME_DATA {
GWEN_MSG_ENDPOINT *ipcdEndpoint;
typedef struct AQHOME_SERVER AQHOME_SERVER;
struct AQHOME_SERVER {
AQH_OBJECT *ipcServer;
AQH_OBJECT_LIST *tcpClientList;
AQH_MSG_REQUEST *requestTree;
GWEN_DB_NODE *dbArgs;
AQH_STORAGE *storage;
char *pidFile;
int timeout; /* timeout for run e.g. inside valgrind */
GWEN_MUTEX *storageMutex;
GWEN_MSG_REQUEST *requestTree;
};
AQHOME_SERVER *AqHomeDataServer_GetServerData(const AQH_OBJECT *o);
#endif

View File

@@ -37,30 +37,22 @@
</setVar>
<headers dist="true" >
init.h
fini.h
loop.h
loop_ipc.h
loop_mqtt.h
aqhome_mqtt.h
aqhome_mqtt_p.h
xmlread.h
xmlwrite.h
c_setdata.h
server.h
server_p.h
s_publish.h
s_setdata.h
</headers>
<sources>
$(local/typefiles)
aqhome_mqtt.c
init.c
fini.c
loop.c
loop_ipc.c
loop_mqtt.c
main.c
xmlread.c
xmlwrite.c
c_setdata.c
server.c
s_publish.c
s_setdata.c
</sources>
<useTargets>

View File

@@ -1,189 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./aqhome_mqtt_p.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/endpoint_ipcclient.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include "aqhome/mqtt/msg_mqtt_publish.h"
#include <gwenhywfar/misc.h>
#include <gwenhywfar/debug.h>
AQHOME_MQTT *AqHomeMqtt_new(void)
{
AQHOME_MQTT *aqh;
GWEN_NEW_OBJECT(AQHOME_MQTT, aqh);
return aqh;
}
void AqHomeMqtt_free(AQHOME_MQTT *aqh)
{
if (aqh) {
AQHMQTT_Device_List_free(aqh->availableDeviceList);
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
GWEN_DB_Group_free(aqh->dbArgs);
free(aqh->pidFile);
GWEN_FREE_OBJECT(aqh);
}
}
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetBrokerEndpoint(const AQHOME_MQTT *aqh)
{
return aqh?(aqh->brokerEndpoint):NULL;
}
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetMqttEndpoint(const AQHOME_MQTT *aqh)
{
return aqh?(aqh->mqttEndpoint):NULL;
}
GWEN_DB_NODE *AqHomeMqtt_GetDbArgs(const AQHOME_MQTT *aqh)
{
return aqh?(aqh->dbArgs):NULL;
}
const char *AqHomeMqtt_GetPidFile(const AQHOME_MQTT *aqh)
{
return aqh?aqh->pidFile:NULL;
}
void AqHomeMqtt_SetPidFile(AQHOME_MQTT *aqh, const char *s)
{
if (aqh) {
free(aqh->pidFile);
aqh->pidFile=s?strdup(s):NULL;
}
}
int AqHomeMqtt_GetTimeout(const AQHOME_MQTT *aqh)
{
return aqh?aqh->timeout:0;
}
const char *AqHomeMqtt_GetDeviceFile(const AQHOME_MQTT *aqh)
{
return aqh?aqh->deviceFile:NULL;
}
void AqHomeMqtt_SetDeviceFile(AQHOME_MQTT *aqh, const char *s)
{
if (aqh) {
free(aqh->deviceFile);
aqh->deviceFile=s?strdup(s):NULL;
}
}
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh)
{
return aqh?aqh->availableDeviceList:NULL;
}
void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl)
{
if (aqh) {
AQHMQTT_Device_List_free(aqh->availableDeviceList);
aqh->availableDeviceList=dl;
}
}
void AqHomeMqtt_SetRegisteredDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl)
{
if (aqh) {
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
aqh->registeredDeviceList=dl;
}
}
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId)
{
if (aqh && aqh->registeredDeviceList) {
return AQHMQTT_Device_List_GetById(aqh->registeredDeviceList, wantedDeviceId);
}
else {
DBG_ERROR(NULL, "No registered devices");
}
return NULL;
}
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh)
{
if (aqh && aqh->registeredDeviceList) {
AQHMQTT_DEVICE *device;
device=AQHMQTT_Device_List_First(aqh->registeredDeviceList);
if (device) {
fprintf(stderr, "Registered Devices:\n");
while(device) {
const char *sDeviceName;
const char *sDeviceId;
sDeviceName=AQHMQTT_Device_GetName(device);
sDeviceId=AQHMQTT_Device_GetId(device);
fprintf(stderr, " %s (%s)\n", sDeviceId?sDeviceId:"<no id>", sDeviceName?sDeviceName:"<no name>");
device=AQHMQTT_Device_List_Next(device);
}
}
else {
fprintf(stderr, "No registered devices\n");
}
}
else {
fprintf(stderr, "No registered devices\n");
}
}

View File

@@ -1,51 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_MQTT_H
#define AQHOME_MQTT_H
//#include "./mqttvalue.h"
//#include "./mqtttopic.h"
#include "aqhome-mqttlog/types/device.h"
#include <gwenhywfar/endpoint.h>
typedef struct AQHOME_MQTT AQHOME_MQTT;
AQHOME_MQTT *AqHomeMqtt_new(void);
void AqHomeMqtt_free(AQHOME_MQTT *aqh);
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetBrokerEndpoint(const AQHOME_MQTT *aqh);
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetMqttEndpoint(const AQHOME_MQTT *aqh);
GWEN_DB_NODE *AqHomeMqtt_GetDbArgs(const AQHOME_MQTT *aqh);
const char *AqHomeMqtt_GetPidFile(const AQHOME_MQTT *aqh);
void AqHomeMqtt_SetPidFile(AQHOME_MQTT *aqh, const char *s);
int AqHomeMqtt_GetTimeout(const AQHOME_MQTT *aqh);
const char *AqHomeMqtt_GetDeviceFile(const AQHOME_MQTT *aqh);
void AqHomeMqtt_SetDeviceFile(AQHOME_MQTT *aqh, const char *s);
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh);
void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
void AqHomeMqtt_SetRegisteredDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId);
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh);
#endif

View File

@@ -1,160 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 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 "./c_setdata.h"
#include "aqhome/data/value.h"
#include "aqhome/ipc/data/msg_data_set.h"
#include "aqhome/mqtt/msg_mqtt_publish.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _sendDataForDevice(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const char *valueName, const char *valueData);
static void _sendValueToMqtt(AQHOME_MQTT *aqh, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData);
static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeMqttLog_HandleSetData(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
{
AQH_VALUE *recvdValue;
DBG_ERROR(NULL, "Received SETDATA request");
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
if (recvdValue) {
const char *valueName;
const char *deviceName;
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
if (valueName && deviceName) {
AQHMQTT_DEVICE *device;
device=AqHomeMqtt_FindRegisteredDevice(aqh, deviceName);
if (device) {
char *valueDataFreeable;
DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
_sendDataForDevice(aqh, device, valueName, valueDataFreeable);
free(valueDataFreeable);
}
else {
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
AqHomeMqtt_DumpRegisteredDevices(aqh);
}
}
else {
DBG_ERROR(NULL, "Either value name or device name missing in request");
}
AQH_Value_free(recvdValue);
}
else {
DBG_ERROR(NULL, "Request does not contain a value object");
}
}
void _sendDataForDevice(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const char *valueName, const char *valueData)
{
const char *deviceId;
deviceId=AQHMQTT_Device_GetId(device);
if (deviceId && *deviceId) {
AQHMQTT_TOPIC_LIST *topicList;
topicList=AQHMQTT_Device_GetTopicList(device);
if (topicList) {
AQHMQTT_TOPIC *topic;
topic=AQHMQTT_Topic_List_First(topicList);
while(topic) {
if (AQHMQTT_Topic_GetDirection(topic)==AQHMQTT_TopicDir_Out) {
AQHMQTT_VALUE_LIST *valueList;
AQHMQTT_VALUE *value;
valueList=AQHMQTT_Topic_GetValueList(topic);
value=valueList?AQHMQTT_Value_List_GetByName(valueList, valueName):NULL;
if (value) {
/* found value, create publish msg, send */
DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName);
_sendValueToMqtt(aqh, deviceId, topic, valueData);
}
} /* if out */
topic=AQHMQTT_Topic_List_Next(topic);
} /* while topic */
}
}
else {
DBG_ERROR(NULL, "Device has no id");
}
}
void _sendValueToMqtt(AQHOME_MQTT *aqh, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData)
{
GWEN_MSG_ENDPOINT *ep;
GWEN_BUFFER *buf;
GWEN_MSG *msgOut;
ep=AqHomeMqtt_GetMqttEndpoint(aqh);
buf=_createBufferForTopic(deviceId, topic);
DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:"<empty>");
msgOut=AQH_PublishMqttMsg_new(0, 0, GWEN_Buffer_GetStart(buf),
(const uint8_t*) (valueData?valueData:NULL),
valueData?strlen(valueData):0);
if (msgOut) {
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
}
else {
DBG_ERROR(NULL, "Error creating message");
}
GWEN_Buffer_free(buf);
}
GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic)
{
GWEN_BUFFER *buf;
const char *s;
buf=GWEN_Buffer_new(0, 256, 0, 1);
s=AQHMQTT_Topic_GetBeforeId(topic);
if (s && *s)
GWEN_Buffer_AppendString(buf, s);
GWEN_Buffer_AppendString(buf, deviceId);
s=AQHMQTT_Topic_GetAfterId(topic);
if (s && *s)
GWEN_Buffer_AppendString(buf, s);
return buf;
}

View File

@@ -1,85 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./fini.h"
#include "./aqhome_mqtt_p.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint.h>
#include <unistd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeMqtt_Fini(AQHOME_MQTT *aqh)
{
if (aqh) {
if (aqh->rootEndpoint)
_disconnectTree(aqh->rootEndpoint);
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
aqh->rootEndpoint=NULL;
aqh->brokerEndpoint=NULL;
aqh->mqttEndpoint=NULL;
AQHMQTT_Device_List_free(aqh->availableDeviceList);
aqh->availableDeviceList=NULL;
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
aqh->registeredDeviceList=NULL;
if (aqh->pidFile)
remove(aqh->pidFile);
}
}
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
{
GWEN_MSG_ENDPOINT *epChild;
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
while(epChild) {
_disconnectTree(epChild);
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
} /* while */
GWEN_MsgEndpoint_Disconnect(ep);
}

View File

@@ -1,489 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./init.h"
#include "./aqhome_mqtt_p.h"
#include "./xmlread.h"
#include "./xmlwrite.h"
#include "aqhome/aqhome.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/endpoint_ipcclient.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include <gwenhywfar/endpoint_multilayer.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _createPidFile(const char *pidFilename);
static int _setupBroker(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs);
static int _setupMqtt(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs);
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv)
{
int rv;
GWEN_DB_NODE *dbArgs;
const char *s;
dbArgs=GWEN_DB_Group_new("args");
rv=_readArgs(argc, argv, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error reading args (%d)", rv);
return rv;
}
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
aqh->dbArgs=dbArgs;
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
if (s && *s) {
GWEN_LOGGER_LEVEL ll;
ll=GWEN_Logger_Name2Level(s);
GWEN_Logger_SetLevel(NULL, ll);
}
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_MQTT_DEFAULT_PIDFILE);
if (s && *s) {
AqHomeMqtt_SetPidFile(aqh, s);
rv=_createPidFile(s);
if (rv<0) {
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
return rv;
}
}
s=GWEN_DB_GetCharValue(dbArgs, "devicefile", 0, NULL);
if (s && *s) {
AqHomeMqtt_SetDeviceFile(aqh, s);
}
else {
GWEN_BUFFER *bufFilename;
bufFilename=AQH_GetRuntimeFilePath(AQHOME_MQTT_DEFAULT_DEVICEFILE);
if (bufFilename) {
AqHomeMqtt_SetDeviceFile(aqh, GWEN_Buffer_GetStart(bufFilename));
GWEN_Buffer_free(bufFilename);
}
else {
DBG_ERROR(NULL, "Could not setup filename for devices, please specify via command line argument");
return GWEN_ERROR_GENERIC;
}
}
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
rv=_setupMqtt(aqh, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error setting up connection to broker (%d)", rv);
return rv;
}
rv=_setupBroker(aqh, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error setting up connection to broker (%d)", rv);
return rv;
}
AqHomeMqtt_LoadRuntimeDeviceFiles(aqh);
AqHomeMqtt_ReloadDeviceFiles(aqh);
return 0;
}
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh)
{
AQHMQTT_DEVICE_LIST *deviceList;
DBG_ERROR(NULL, "Loading devices description files");
deviceList=AqHomeMqttLog_ReadDataDeviceFiles(aqh);
if (deviceList)
AqHomeMqtt_SetAvailableDeviceList(aqh, deviceList);
}
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh)
{
AQHMQTT_DEVICE_LIST *deviceList;
DBG_ERROR(NULL, "Loading registered devices from file \"%s\"", aqh->deviceFile);
deviceList=AqHomeMqttLog_ReadDeviceFile(aqh, aqh->deviceFile);
if (deviceList)
AqHomeMqtt_SetRegisteredDeviceList(aqh, deviceList);
}
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh)
{
int rv;
rv=AqHomeMqttLog_WriteDevicesFile(aqh, aqh->registeredDeviceList, aqh->deviceFile);
if (rv<0) {
DBG_INFO(NULL, "Error writing devices to \"%s\" (%d)", aqh->deviceFile, rv);
return rv;
}
return 0;
}
int _createPidFile(const char *pidFilename)
{
FILE *f;
int pidfd;
if (remove(pidFilename)==0) {
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
}
#ifdef HAVE_SYS_STAT_H
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (pidfd < 0) {
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
f = fdopen(pidfd, "w");
#else /* HAVE_STAT_H */
f=fopen(pidFilename,"w+");
#endif /* HAVE_STAT_H */
/* write pid */
#ifdef HAVE_GETPID
fprintf(f,"%d\n",getpid());
#else
fprintf(f,"-1\n");
#endif
if (fclose(f)) {
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
return 0;
}
int _setupBroker(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs)
{
const char *brokerAddress;
int brokerPort;
const char *brokerClientId;
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "brokerAddress", 0, NULL);
if (!(brokerAddress && *brokerAddress))
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, "127.0.0.1");
brokerPort=GWEN_DB_GetIntValue(dbArgs, "brokerPort", 0, -1);
if (brokerPort<0)
brokerPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_MQTT_DEFAULT_BROKER_PORT);
brokerClientId=GWEN_DB_GetCharValue(dbArgs, "brokerClientId", 0, AQHOME_MQTT_DEFAULT_BROKER_CLIENTID);
if (brokerAddress && *brokerAddress && brokerPort) {
GWEN_MSG_ENDPOINT *ep;
GWEN_MSG_ENDPOINT *ipcBaseEndpoint;
int rv;
ep=AQH_ClientIpcEndpoint_new("brokerIpcClient", 0);
ipcBaseEndpoint=AQH_IpcEndpoint_CreateIpcTcpClient(brokerAddress, brokerPort, "brokerPhysEndpoint", 0);
AQH_IpcEndpoint_SetServiceName(ipcBaseEndpoint, brokerClientId);
GWEN_MsgEndpoint_Tree2_AddChild(ep, ipcBaseEndpoint);
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
aqh->brokerEndpoint=ep;
rv=GWEN_MultilayerEndpoint_StartConnect(ep);
if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) {
DBG_ERROR(NULL, "Error connecting to broker server %s:%d (%d), will retry later", brokerAddress, brokerPort, rv);
return rv;
}
}
return 0;
}
int _setupMqtt(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs)
{
const char *mqttAddress;
int mqttPort;
const char *mqttClientId;
int mqttKeepAlive;
mqttAddress=GWEN_DB_GetCharValue(dbArgs, "mqttAddress", 0, NULL);
if (!(mqttAddress && *mqttAddress))
mqttAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/mqttAddr", 0, "127.0.0.1");
mqttPort=GWEN_DB_GetIntValue(dbArgs, "mqttPort", 0, 1883);
if (mqttPort<0)
mqttPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/mqttPort", 0, 1883);
mqttClientId=GWEN_DB_GetCharValue(dbArgs, "mqttClientId", 0, "aqhome-mqttlog");
if (!(mqttClientId && *mqttClientId))
mqttClientId=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/mqttClientId", 0, "aqhome-mqttlog");
mqttKeepAlive=GWEN_DB_GetIntValue(dbArgs, "mqttKeepAlive", 0, 600);
if (mqttAddress && *mqttAddress && mqttPort) {
GWEN_MSG_ENDPOINT *epMqtt;
DBG_INFO(AQH_LOGDOMAIN, "Connecting to %s (port %d)", mqttAddress, mqttPort);
epMqtt=AQH_MqttClientEndpoint_new(mqttClientId, mqttAddress, mqttPort, NULL, 0);
if (epMqtt==NULL) {
DBG_ERROR(AQH_LOGDOMAIN, "Error creating endpoint TCP");
return GWEN_ERROR_IO;
}
AQH_MqttClientEndpoint_SetKeepAliveTime(epMqtt, mqttKeepAlive);
GWEN_MsgEndpoint_AddFlags(epMqtt, AQH_ENDPOINT2_MQTTCLIENT_FLAGS_SUBSCRIBEALL);
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, epMqtt);
aqh->mqttEndpoint=epMqtt;
}
return 0;
}
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
{
int rv;
const GWEN_ARGS args[]= {
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"loglevel", /* name */
0, /* minnum */
1, /* maxnum */
"L", /* short option */
"loglevel", /* long option */
I18S("Specify loglevel"), /* short description */
I18S("Specify loglevel") /* long description */
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"cfgdir", /* name */
0, /* minnum */
1, /* maxnum */
"D", /* short option */
"cfgdir", /* long option */
I18S("Specify the configuration folder"),
I18S("Specify the configuration folder")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"charset", /* name */
0, /* minnum */
1, /* maxnum */
0, /* short option */
"charset", /* long option */
I18S("Specify the output character set"), /* short description */
I18S("Specify the output character set") /* long description */
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"brokerAddress", /* name */
0, /* minnum */
1, /* maxnum */
"ba", /* short option */
"brokeraddress", /* long option */
I18S("Specify the address of the broker server to connect to (disabled if missing)"),
I18S("Specify the address of the broker server to connect to (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"brokerPort", /* name */
0, /* minnum */
1, /* maxnum */
"bp", /* short option */
"brokerport", /* long option */
I18S("Specify the port of the broker server (default: 1899)"),
I18S("Specify the port of the broker server (default: 1899)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"brokerClientId", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"brokerclientid", /* long option */
I18S("Specify client id for the broker server (default: \"nodes\")"),
I18S("Specify client id for the broker server (default: \"nodes\")")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"mqttAddress", /* name */
0, /* minnum */
1, /* maxnum */
"ma", /* short option */
"mqttaddress", /* long option */
I18S("Specify the address of the MQTT server to connect to (disabled if missing)"),
I18S("Specify the address of the MQTT server to connect to (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"mqttPort", /* name */
0, /* minnum */
1, /* maxnum */
"mp", /* short option */
"mqttport", /* long option */
I18S("Specify the port of the MQTT server (default: 1883)"),
I18S("Specify the port of the MQTT server (default: 1883)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"mqttClientId", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"mqttclientid", /* long option */
I18S("Specify client id for the MQTT server (default: \"aqhomed\")"),
I18S("Specify client id for the MQTT server (default: \"aqhomed\")")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"mqttKeepAlive", /* name */
0, /* minnum */
1, /* maxnum */
"mk", /* short option */
"mqttkeepalive", /* long option */
I18S("Specify keepalive time in seconds (defaults: 600)"),
I18S("Specify keepalive time in seconds (defaults: 600)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"pidfile", /* name */
0, /* minnum */
1, /* maxnum */
"p", /* short option */
"pidfile", /* long option */
I18S("Specify the PID file"),
I18S("Specify the PID file")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"timeout", /* name */
0, /* minnum */
1, /* maxnum */
"T", /* short option */
"timeout", /* long option */
I18S("Specify timeout in second (default: no timeout)"),
I18S("Specify timeout in second (default: no timeout)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"devicefile", /* name */
0, /* minnum */
1, /* maxnum */
"d", /* short option */
"devicefile", /* long option */
I18S("Specify the device file"),
I18S("Specify the device file")
},
{
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
GWEN_ArgsType_Int, /* type */
"help", /* name */
0, /* minnum */
0, /* maxnum */
"h", /* short option */
"help",
I18S("Show this help screen."),
I18S("Show this help screen.")
}
};
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
if (rv==GWEN_ARGS_RESULT_ERROR) {
fprintf(stderr, "ERROR: Could not parse arguments main\n");
return GWEN_ERROR_INVALID;
}
else if (rv==GWEN_ARGS_RESULT_HELP) {
GWEN_BUFFER *ubuf;
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
GWEN_Buffer_AppendArgs(ubuf,
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
AQHOME_VERSION_STRING,
argv[0]);
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
fprintf(stderr, "ERROR: Could not create help string\n");
return 1;
}
GWEN_Buffer_AppendString(ubuf, "\n");
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
GWEN_Buffer_free(ubuf);
return GWEN_ERROR_CLOSE;
}
return 0;
}

View File

@@ -1,27 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMEMQTT_INIT_H
#define AQHOMEMQTT_INIT_H
#include "./aqhome_mqtt.h"
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv);
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh);
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh);
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh);
#endif

View File

@@ -1,57 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop.h"
#include "./loop_ipc.h"
#include "./loop_mqtt.h"
#include "./c_setdata.h"
#include "./aqhome_mqtt_p.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/json_read.h>
#include <gwenhywfar/db.h>
//#define FULL_DEBUG
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeMqttLog_Loop(AQHOME_MQTT *aqh, int timeoutInMsecs)
{
if (aqh) {
GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs);
AqHomeMqttLog_ReadAndHandleMqttMessages(aqh);
AqHomeMqttLog_ReadAndHandleIpcMessages(aqh);
}
}

View File

@@ -1,26 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMEMQTT_LOOP_H
#define AQHOMEMQTT_LOOP_H
#include "./aqhome_mqtt.h"
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/msg.h>
void AqHomeMqttLog_Loop(AQHOME_MQTT *aqh, int timeoutInMsecs);
#endif

View File

@@ -1,87 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_ipc.h"
#include "./aqhome_mqtt_p.h"
#include "./c_setdata.h"
#include "aqhome/ipc/data/ipc_data.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/json_read.h>
#include <gwenhywfar/db.h>
#define FULL_DEBUG
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _handleIpcMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomeMqttLog_ReadAndHandleIpcMessages(AQHOME_MQTT *aqh)
{
GWEN_MSG_ENDPOINT *epTcp;
GWEN_MSG *msg;
epTcp=aqh->brokerEndpoint;
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) {
_handleIpcMsg(aqh, epTcp, msg);
GWEN_Msg_free(msg);
}
}
void _handleIpcMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
{
uint16_t code;
uint8_t protoId;
/* exec IPC message */
code=GWEN_IpcMsg_GetCode(msg);
protoId=GWEN_IpcMsg_GetProtoId(msg);
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet %d (%x)", (int) code, code);
switch(code) {
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeMqttLog_HandleSetData(aqh, ep, msg); break;
default: break;
}
}
else if (protoId==0 && code==AQH_MSGTYPE_IPC_DATA_RESULT) {
/* result received */
}
else {
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
}
}

View File

@@ -1,26 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMEMQTT_LOOP_IPC_H
#define AQHOMEMQTT_LOOP_IPC_H
#include "./aqhome_mqtt.h"
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/msg.h>
void AqHomeMqttLog_ReadAndHandleIpcMessages(AQHOME_MQTT *aqh);
#endif

View File

@@ -10,10 +10,7 @@
# include <config.h>
#endif
#include "./init.h"
#include "./fini.h"
#include "./loop.h"
#include "./loop_mqtt.h"
#include "./server.h"
#include "aqhome/aqhome.h"
@@ -46,8 +43,9 @@
#define I18N(msg) msg
#define I18S(msg) msg
#define AQHOME_MQTTLOG_PING_INTERVAL 120
#define AQHOME_MQTTLOG_SAVE_INTERVAL 60
#define CONNCHECK_INTERVAL_IN_SECS 10
#define PING_INTERVAL_IN_SECS 120
#define SAVE_INTERVAL_IN_SECS 60
#define FULL_DEBUG
@@ -58,13 +56,14 @@
* ------------------------------------------------------------------------------------------------
*/
static void _serve(AQHOME_MQTT *aqh);
static void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop);
static int _diffInSeconds(time_t t1, time_t t0);
#ifdef HAVE_SIGNAL_H
static int _setSignalHandlers(void);
static int _setupSigAction(struct sigaction *sa, int sig);
static void _signalHandler(int s);
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT, saPIPE;
#endif
@@ -85,11 +84,10 @@ static int stopService=0;
int main(int argc, char **argv)
{
AQHOME_MQTT *aqh;
GWEN_DB_NODE *dbArgs;
AQH_EVENT_LOOP *eventLoop;
AQH_OBJECT *aqh;
int rv;
GWEN_GUI *gui;
const char *s;
rv=GWEN_Init();
if (rv) {
@@ -98,7 +96,14 @@ int main(int argc, char **argv)
}
GWEN_Logger_Open(0, "aqhome-mqttlog", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
//GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Notice);
rv=_setSignalHandlers();
if (rv<0) {
DBG_INFO(NULL, "here (%d)", rv);
return rv;
}
rv=AQH_Init();
if (rv<0) {
@@ -106,8 +111,13 @@ int main(int argc, char **argv)
return 2;
}
aqh=AqHomeMqtt_new();
rv=AqHomeMqtt_Init(aqh, argc, argv);
gui=GWEN_Gui_CGui_new();
GWEN_Gui_SetGui(gui);
eventLoop=AQH_EventLoop_new();
aqh=AQH_MqttLogServer_new(eventLoop);
rv=AQH_MqttLogServer_Init(aqh, argc, argv);
if (rv<0) {
if (rv==GWEN_ERROR_CLOSE)
return 1;
@@ -115,18 +125,11 @@ int main(int argc, char **argv)
return 2;
}
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
_runService(aqh, eventLoop);
gui=GWEN_Gui_CGui_new();
s=GWEN_DB_GetCharValue(dbArgs, "charset", 0, NULL);
if (s && *s)
GWEN_Gui_SetCharSet(gui, s);
GWEN_Gui_SetGui(gui);
_serve(aqh);
AqHomeMqtt_Fini(aqh);
AqHomeMqtt_free(aqh);
AQH_MqttLogServer_Fini(aqh);
AQH_Object_free(aqh);
GWEN_Gui_SetGui(NULL);
GWEN_Gui_free(gui);
@@ -136,77 +139,65 @@ int main(int argc, char **argv)
void _serve(AQHOME_MQTT *aqh)
void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
{
int rv;
time_t timeStart;
int timeout;
time_t startTime;
time_t lastPingSendTime;
time_t lastSaveTime;
GWEN_DB_NODE *dbArgs;
time_t timeLastConnCheck;
time_t timeLastSave;
time_t timeLastPingSend;
int rv;
startTime=time(NULL);
lastSaveTime=time(NULL);
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
rv=_setSignalHandlers();
if (rv<0) {
DBG_ERROR(NULL, "Error setting signal handlers (%d)", rv);
return;
}
timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
lastPingSendTime=time(NULL);
timeout=AQH_MqttLogServer_GetTimeout(aqh);
timeStart=time(NULL);
timeLastConnCheck=time(NULL);
timeLastSave=time(NULL);
timeLastPingSend=time(NULL);
while(!stopService) {
DBG_DEBUG(NULL, "Next loop");
AqHomeMqttLog_Loop(aqh, 2000);
time_t now;
if (timeout) {
time_t now;
AQH_EventLoop_Run(eventLoop, 2000);
AQH_MqttLogServer_HandleMqttMsgs(aqh);
AQH_MqttLogServer_HandleBrokerMsgs(aqh);
now=time(NULL);
if ((now-startTime)>timeout) {
DBG_ERROR(NULL, "Timeout, stopping service");
break;
}
}
if (1){
time_t now;
now=time(NULL);
now=time(NULL);
if (now-lastPingSendTime>AQHOME_MQTTLOG_PING_INTERVAL) {
rv=AqHomeMqttLog_SendPing(aqh);
if (rv<0) {
DBG_INFO(NULL, "Error sending PING");
}
lastPingSendTime=time(NULL);
}
if (_diffInSeconds(now, timeLastConnCheck)>CONNCHECK_INTERVAL_IN_SECS) {
DBG_INFO(NULL, "Check connections");
AQH_MqttLogServer_CheckBrokerConnection(aqh);
AQH_MqttLogServer_CheckMqttConnection(aqh);
timeLastConnCheck=now;
}
if (1){
time_t now;
now=time(NULL);
if (now-lastSaveTime>AQHOME_MQTTLOG_SAVE_INTERVAL) {
DBG_ERROR(NULL, "Writing device files");
rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
if (rv<0) {
DBG_INFO(NULL, "Error writing runtime data");
}
lastSaveTime=time(NULL);
if (_diffInSeconds(now, timeLastPingSend)>PING_INTERVAL_IN_SECS) {
rv=AQH_MqttLogServer_SendPing(aqh);
if (rv<0) {
DBG_INFO(NULL, "Error sending PING");
}
timeLastPingSend=time(NULL);
}
if (_diffInSeconds(now, timeLastSave)>SAVE_INTERVAL_IN_SECS) {
DBG_INFO(NULL, "Writing device files");
rv=AQH_MqttLogServer_SaveRuntimeDeviceFiles(aqh);
if (rv<0) {
DBG_INFO(NULL, "Error writing device file");
}
timeLastSave=time(NULL);
}
if (timeout && (_diffInSeconds(now, timeStart)>timeout)) {
DBG_INFO(NULL, "Timeout");
break;
}
} /* while */
DBG_ERROR(NULL, "Leaving server");
rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
rv=AQH_MqttLogServer_SaveRuntimeDeviceFiles(aqh);
if (rv<0) {
DBG_INFO(NULL, "Error writing runtime data");
}
}
@@ -228,6 +219,10 @@ int _setSignalHandlers(void)
if (rv)
return rv;
rv=_setupSigAction(&saPIPE, SIGPIPE);
if (rv)
return rv;
# ifdef SIGTSTP
rv=_setupSigAction(&saTSTP, SIGTSTP);
if (rv)
@@ -269,6 +264,9 @@ void _signalHandler(int s)
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
stopService=1;
break;
case SIGPIPE:
DBG_WARN(0, "Received PIPE signal");
break;
default:
DBG_WARN(0, "Unknown signal %d",s);
break;
@@ -277,3 +275,8 @@ void _signalHandler(int s)
int _diffInSeconds(time_t t1, time_t t0)
{
return t1-t0;
}

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
@@ -10,41 +10,38 @@
# include <config.h>
#endif
#include "./loop_mqtt.h"
#include "./aqhome_mqtt_p.h"
#include "aqhome/aqhome.h"
#include "aqhome/mqtt/msg_mqtt_publish.h"
#include "aqhome/ipc/data/msg_data_multidata.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "./s_publish.h"
#include "./server_p.h"
#include <aqhome/aqhome.h>
#include <aqhome/msg/ipc/data/m_ipcd.h>
#include <aqhome/msg/ipc/data/m_ipcd_multidata.h>
#include <aqhome/msg/ipc/data/m_ipcd_values.h>
#include <aqhome/ipc2/endpoint.h>
#include <aqhome/msg/mqtt/m_mqtt_publish.h>
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/json_read.h>
#include <gwenhywfar/db.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/debug.h>
//#define FULL_DEBUG
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _handleMqttMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
static void _handlePublishMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
static int _handlePublish(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *topic, const char *value);
static void _handleNumTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *dev, AQHMQTT_TOPIC *t, const char *rcvdValue);
static void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *dev, AQHMQTT_TOPIC *t, const char *rcvdValue);
static void _sendMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue);
static void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device);
static void _sendAnnounceValueMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value);
static int _handlePublish(AQH_OBJECT *o, const char *rcvdTopic, const char *rcvdValue);
static void _handleNumTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
AQHMQTT_TOPIC *topic, const char *rcvdValue);
static void _handleJsonTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
AQHMQTT_TOPIC *topic, const char *rcvdValue);
static void _sendMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue);
static void _announceDeviceToBroker(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device);
static void _sendAnnounceValueMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value);
static AQH_VALUE *_mkMessageValue(const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value);
static int _mqttValueTypeMessageValueType(int t);
static int _registerNewDeviceForTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue);
static int _registerNewDeviceForTopic(AQH_MQTTLOG_SERVER *xo, const char *rcvdTopic);
static AQHMQTT_TOPIC *_findMaskMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir);
static AQHMQTT_TOPIC *_findTopicMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir);
static GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcvdTopic);
@@ -52,120 +49,66 @@ static GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcv
/* ------------------------------------------------------------------------------------------------
* implementations
* code
* ------------------------------------------------------------------------------------------------
*/
void AqHomeMqttLog_ReadAndHandleMqttMessages(AQHOME_MQTT *aqh)
void AQH_MqttLogServer_HandlePublishMsg(AQH_OBJECT *o, GWEN_UNUSED AQH_OBJECT *ep, const AQH_MESSAGE *msg)
{
GWEN_MSG_ENDPOINT *epTcp;
GWEN_MSG *msg;
if (o && msg) {
AQH_MQTTLOG_SERVER *xo;
epTcp=aqh->mqttEndpoint;
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) {
#ifdef FULL_DEBUG
DBG_ERROR(NULL, "Received this message:");
GWEN_Text_DumpString((const char*) GWEN_Msg_GetConstBuffer(msg), GWEN_Msg_GetBytesInBuffer(msg), 2);
#endif
_handleMqttMsg(aqh, epTcp, msg);
GWEN_Msg_free(msg);
}
}
xo=AQH_MqttLogServer_GetServerData(o);
if (xo && xo->registeredDeviceList) {
char *topic;
char *value;
int AqHomeMqttLog_SendPing(AQHOME_MQTT *aqh)
{
GWEN_MSG_ENDPOINT *epTcp;
GWEN_MSG *msgOut;
DBG_INFO(AQH_LOGDOMAIN, "Sending PING");
epTcp=aqh->mqttEndpoint;
msgOut=GWEN_MqttMsg_new(AQH_MQTTMSG_MSGTYPE_PINGREQ, 0, NULL);
if (msgOut==NULL) {
DBG_ERROR(NULL, "Error creating message");
return GWEN_ERROR_INTERNAL;
}
GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut);
return 0;
}
void _handleMqttMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PUBLISH & 0xf0)) {
DBG_INFO(AQH_LOGDOMAIN, "PUBLISH message received");
#ifdef FULL_DEBUG
GWEN_BUFFER *buf;
buf=GWEN_Buffer_new(0, 256, 0, 1);
AQH_PublishMqttMsg_DumpToBuffer(msg, buf, "received");
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
#endif
_handlePublishMsg(aqh, ep, msg);
}
else if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PINGRESP & 0xf0)) {
DBG_INFO(AQH_LOGDOMAIN, "PING response received");
}
else {
#ifdef FULL_DEBUG
DBG_ERROR(NULL, "Received this message:");
GWEN_Text_DumpString((const char*) GWEN_Msg_GetConstBuffer(msg), GWEN_Msg_GetBytesInBuffer(msg), 2);
#endif
}
}
void _handlePublishMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
char *topic;
char *value;
topic=AQH_MqttMessagePublish_ExtractTopic(msg);
value=AQH_MqttMessagePublish_ExtractValue(msg);
topic=AQH_PublishMqttMsg_ExtractTopic(msg);
value=AQH_PublishMqttMsg_ExtractValue(msg);
if (topic && value) {
int rv;
if (topic && value) {
int rv;
rv=_handlePublish(aqh, ep, topic, value);
if (rv!=1) {
DBG_INFO(NULL, "New topic \"%s\", trying to register", topic);
rv=_registerNewDeviceForTopic(aqh, ep, topic, value);
if (rv==1) {
rv=_handlePublish(aqh, ep, topic, value);
rv=_handlePublish(o, topic, value);
if (rv!=1) {
DBG_ERROR(NULL, "Topic \"%s\" still not handled, SNH!", topic);
DBG_INFO(NULL, "New topic \"%s\", trying to register", topic);
rv=_registerNewDeviceForTopic(xo, topic);
if (rv==1) {
rv=_handlePublish(o, topic, value);
if (rv!=1) {
DBG_ERROR(NULL, "Topic \"%s\" still not handled, SNH!", topic);
}
}
}
}
else {
DBG_ERROR(NULL, "Either topic or value missing in PUBLISH msg");
}
free(value);
free(topic);
}
}
else {
DBG_ERROR(NULL, "Either topic or value missing in PUBLISH msg");
}
free(value);
free(topic);
}
int _handlePublish(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue)
int _handlePublish(AQH_OBJECT *o, const char *rcvdTopic, const char *rcvdValue)
{
if (rcvdTopic && *rcvdTopic) {
if (aqh->registeredDeviceList) {
if (o && rcvdTopic && *rcvdTopic) {
AQH_MQTTLOG_SERVER *xo;
xo=AQH_MqttLogServer_GetServerData(o);
if (xo && xo->registeredDeviceList) {
AQHMQTT_DEVICE *device;
device=AQHMQTT_Device_List_First(aqh->registeredDeviceList);
device=AQHMQTT_Device_List_First(xo->registeredDeviceList);
while(device) {
AQHMQTT_TOPIC_LIST *topicList;
const char *sDeviceName;
const char *sDeviceId;
AQHMQTT_TOPIC_LIST *topicList;
const char *sDeviceName;
const char *sDeviceId;
sDeviceName=AQHMQTT_Device_GetName(device);
sDeviceId=AQHMQTT_Device_GetId(device);
sDeviceName=AQHMQTT_Device_GetName(device);
sDeviceId=AQHMQTT_Device_GetId(device);
topicList=AQHMQTT_Device_GetTopicList(device);
if (topicList) {
@@ -173,42 +116,43 @@ int _handlePublish(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopi
topic=_findTopicMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
#if 0
if (topic==NULL) {
if (topic==NULL) {
topic=_findMaskMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
if (topic)
AQHMQTT_Topic_SetTopic(topic, rcvdTopic);
}
#endif
if (topic) {
DBG_INFO(AQH_LOGDOMAIN,
"Handling topic \"%s\" for device type %s (id: %s)",
rcvdTopic,
sDeviceName, sDeviceId?sDeviceId:"<no id>");
DBG_INFO(AQH_LOGDOMAIN,
"Handling topic \"%s\" for device type %s (id: %s)",
rcvdTopic,
sDeviceName, sDeviceId?sDeviceId:"<no id>");
if (AQHMQTT_Topic_GetTopicType(topic)==AQHMQTT_TopicType_Json)
_handleJsonTopic(aqh, ep, device, topic, rcvdValue);
_handleJsonTopic(xo, device, topic, rcvdValue);
else
_handleNumTopic(aqh, ep, device, topic, rcvdValue);
_handleNumTopic(xo, device, topic, rcvdValue);
return 1;
}
}
device=AQHMQTT_Device_List_Next(device);
}
DBG_INFO(AQH_LOGDOMAIN, "ignoring topic \"%s\"", rcvdTopic);
}
DBG_INFO(AQH_LOGDOMAIN, "ignoring topic \"%s\"", rcvdTopic);
}
return 0;
}
void _handleNumTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *device, AQHMQTT_TOPIC *topic, const char *rcvdValue)
void _handleNumTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
AQHMQTT_TOPIC *topic, const char *rcvdValue)
{
AQHMQTT_VALUE_LIST *valueList;
valueList=AQHMQTT_Topic_GetValueList(topic);
if (valueList)
_sendMessage(aqh, device, AQHMQTT_Value_List_First(valueList), rcvdValue);
_sendMessage(xo, device, AQHMQTT_Value_List_First(valueList), rcvdValue);
else {
DBG_INFO(NULL, "No value list in device \"%s\"", AQHMQTT_Device_GetId(device));
}
@@ -216,7 +160,8 @@ void _handleNumTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *de
void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *device, AQHMQTT_TOPIC *topic, const char *rcvdValue)
void _handleJsonTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
AQHMQTT_TOPIC *topic, const char *rcvdValue)
{
GWEN_JSON_ELEM *jeRoot;
@@ -245,7 +190,7 @@ void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *d
s=GWEN_JsonElement_GetData(je);
if (s && *s)
_sendMessage(aqh, device, value, s);
_sendMessage(xo, device, value, s);
}
}
value=AQHMQTT_Value_List_Next(value);
@@ -257,35 +202,38 @@ void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *d
void _sendMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue)
void _sendMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue)
{
int rv;
union {double f; uint64_t i;} u;
double f;
const char *deviceName;
deviceName=AQHMQTT_Device_GetId(device);
rv=GWEN_Text_StringToDouble(rcvdValue, &(u.f));
rv=GWEN_Text_StringToDouble(rcvdValue, &f);
if (rv<0) {
DBG_ERROR(NULL, "Invalid value received from MQTT server (%s)", rcvdValue?rcvdValue:"<empty>");
}
else {
GWEN_MSG *pubMsg;
uint64_t arrayToSend[2];
uint64_t now;
AQH_VALUE *msgValue;
arrayToSend[0]=(uint64_t) time(NULL);
arrayToSend[1]=u.i;
now=(uint64_t) time(NULL);
msgValue=_mkMessageValue(device, value);
if (xo->brokerEndpoint) {
AQH_MESSAGE *pubMsg;
pubMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
msgValue, arrayToSend, 1);
if (pubMsg) {
pubMsg=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0,
msgValue, now, f);
DBG_INFO(AQH_LOGDOMAIN, "BROKER UPDATE_DATA %s/%s: %f",
deviceName?deviceName:"<no device name>",
AQH_Value_GetName(msgValue), u.f);
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg);
AQH_Value_GetName(msgValue), f);
AQH_Endpoint_AddMsgOut(xo->brokerEndpoint, pubMsg);
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Skipping BROKER UPDATE_DATA %s/%s: %f",
deviceName?deviceName:"<no device name>",
AQH_Value_GetName(msgValue), f);
}
AQH_Value_free(msgValue);
}
@@ -293,7 +241,7 @@ void _sendMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_
void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device)
void _announceDeviceToBroker(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device)
{
AQHMQTT_TOPIC_LIST *topicList;
@@ -311,7 +259,7 @@ void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device)
value=AQHMQTT_Value_List_First(valueList);
while(value) {
_sendAnnounceValueMessage(aqh, device, value);
_sendAnnounceValueMessage(xo, device, value);
value=AQHMQTT_Value_List_Next(value);
}
}
@@ -323,20 +271,25 @@ void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device)
void _sendAnnounceValueMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value)
void _sendAnnounceValueMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value)
{
GWEN_MSG *pubMsg;
AQH_MESSAGE *pubMsg;
AQH_VALUE *msgValue;
msgValue=_mkMessageValue(device, value);
pubMsg=AQH_ValuesDataIpcMsg_newForOneValue(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
0, msgValue);
if (pubMsg) {
DBG_INFO(AQH_LOGDOMAIN, "BROKER ANNOUNCE_VALUE %s", AQH_Value_GetName(msgValue));
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg);
if (xo->brokerEndpoint) {
pubMsg=AQH_IpcdMessageValues_newForOne(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0,
0, msgValue);
if (pubMsg) {
DBG_INFO(AQH_LOGDOMAIN, "BROKER ANNOUNCE_VALUE %s", AQH_Value_GetName(msgValue));
AQH_Endpoint_AddMsgOut(xo->brokerEndpoint, pubMsg);
}
AQH_Value_free(msgValue);
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Ignoring BROKER ANNOUNCE_VALUE %s", AQH_Value_GetName(msgValue));
}
AQH_Value_free(msgValue);
}
@@ -368,13 +321,13 @@ int _mqttValueTypeMessageValueType(int t)
int _registerNewDeviceForTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue)
int _registerNewDeviceForTopic(AQH_MQTTLOG_SERVER *xo, const char *rcvdTopic)
{
if (rcvdTopic && *rcvdTopic) {
if (aqh->availableDeviceList) {
if (xo->availableDeviceList) {
AQHMQTT_DEVICE *device;
device=AQHMQTT_Device_List_First(aqh->availableDeviceList);
device=AQHMQTT_Device_List_First(xo->availableDeviceList);
while(device) {
AQHMQTT_TOPIC_LIST *topicList;
@@ -394,11 +347,11 @@ int _registerNewDeviceForTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const ch
AQHMQTT_Device_SetId(newDevice, GWEN_Buffer_GetStart(buf));
topic=_findMaskMatchingTopic(AQHMQTT_Device_GetTopicList(newDevice), rcvdTopic, AQHMQTT_TopicDir_In);
AQHMQTT_Topic_SetTopic(topic, rcvdTopic);
if (aqh->registeredDeviceList==NULL)
aqh->registeredDeviceList=AQHMQTT_Device_List_new();
if (xo->registeredDeviceList==NULL)
xo->registeredDeviceList=AQHMQTT_Device_List_new();
DBG_ERROR(NULL, "Registered device \"%s\" (%s)", AQHMQTT_Device_GetId(newDevice), AQHMQTT_Device_GetName(newDevice));
AQHMQTT_Device_List_Add(newDevice, aqh->registeredDeviceList);
_announceDeviceToBroker(aqh, newDevice);
AQHMQTT_Device_List_Add(newDevice, xo->registeredDeviceList);
_announceDeviceToBroker(xo, newDevice);
GWEN_Buffer_free(buf);
return 1;
}
@@ -494,8 +447,3 @@ GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcvdTopic)

View File

@@ -1,25 +1,25 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_MQTTLOG_C_SETDATA_H
#define AQHOME_MQTTLOG_C_SETDATA_H
#ifndef AQHOMEMQTT_S_PUBLISH_H
#define AQHOMEMQTT_S_PUBLISH_H
#include "./aqhome_mqtt.h"
#include <aqhome/events2/object.h>
#include <aqhome/ipc2/message.h>
void AqHomeMqttLog_HandleSetData(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
void AQH_MqttLogServer_HandlePublishMsg(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg);
#endif

View File

@@ -0,0 +1,180 @@
/****************************************************************************
* 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 "./s_setdata.h"
#include "./server_p.h"
#include "aqhome/data/value.h"
#include "aqhome/msg/ipc/data/m_ipcd_setdata.h"
#include "aqhome/msg/mqtt/m_mqtt_publish.h"
#include "aqhome/ipc2/endpoint.h"
#include <gwenhywfar/debug.h>
#define DEBUG_DRY_RUN 1 /* don't actually set value if "1" */
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device,
const char *valueName, const char *valueData);
static void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const char *deviceId,
const AQHMQTT_TOPIC *topic, const char *valueData);
static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o,
const AQH_MESSAGE *msg,
const GWEN_TAG16_LIST *tagList)
{
if (o && msg) {
AQH_MQTTLOG_SERVER *xo;
xo=AQH_MqttLogServer_GetServerData(o);
if (xo) {
AQH_VALUE *recvdValue;
DBG_ERROR(NULL, "Received SETDATA request");
recvdValue=AQH_IpcdMessageSetData_ReadValue(tagList);
if (recvdValue) {
const char *valueName;
const char *deviceName;
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
if (valueName && deviceName) {
AQHMQTT_DEVICE *device;
device=AQH_MqttLogServer_FindRegisteredDevice(o, deviceName);
if (device) {
char *valueDataFreeable;
DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
valueDataFreeable=AQH_IpcdMessageSetData_ReadData(tagList);
_sendDataForDevice(xo, device, valueName, valueDataFreeable);
free(valueDataFreeable);
}
else {
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
AQH_MqttLogServer_DumpRegisteredDevices(o);
}
}
else {
DBG_ERROR(NULL, "Either value name or device name missing in request");
}
AQH_Value_free(recvdValue);
}
else {
DBG_ERROR(NULL, "Request does not contain a value object");
}
}
}
}
void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo,
const AQHMQTT_DEVICE *device,
const char *valueName, const char *valueData)
{
const char *deviceId;
deviceId=AQHMQTT_Device_GetId(device);
if (deviceId && *deviceId) {
AQHMQTT_TOPIC_LIST *topicList;
topicList=AQHMQTT_Device_GetTopicList(device);
if (topicList) {
AQHMQTT_TOPIC *topic;
topic=AQHMQTT_Topic_List_First(topicList);
while(topic) {
if (AQHMQTT_Topic_GetDirection(topic)==AQHMQTT_TopicDir_Out) {
AQHMQTT_VALUE_LIST *valueList;
AQHMQTT_VALUE *value;
valueList=AQHMQTT_Topic_GetValueList(topic);
value=valueList?AQHMQTT_Value_List_GetByName(valueList, valueName):NULL;
if (value) {
/* found value, create publish msg, send */
DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName);
_sendValueToMqtt(xo, deviceId, topic, valueData);
}
} /* if out */
topic=AQHMQTT_Topic_List_Next(topic);
} /* while topic */
}
}
else {
DBG_ERROR(NULL, "Device has no id");
}
}
void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData)
{
GWEN_BUFFER *buf;
#if !DEBUG_DRY_RUN
AQH_MESSAGE *msgOut;
#endif
buf=_createBufferForTopic(deviceId, topic);
#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);
}
GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic)
{
GWEN_BUFFER *buf;
const char *s;
buf=GWEN_Buffer_new(0, 256, 0, 1);
s=AQHMQTT_Topic_GetBeforeId(topic);
if (s && *s)
GWEN_Buffer_AppendString(buf, s);
GWEN_Buffer_AppendString(buf, deviceId);
s=AQHMQTT_Topic_GetAfterId(topic);
if (s && *s)
GWEN_Buffer_AppendString(buf, s);
return buf;
}

View File

@@ -1,24 +1,24 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMEMQTT_LOOP_MQTT_H
#define AQHOMEMQTT_LOOP_MQTT_H
#ifndef AQHOMEMQTT_S_SETDATA_H
#define AQHOMEMQTT_S_SETDATA_H
#include "./aqhome_mqtt.h"
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/msg.h>
#include <aqhome/events2/object.h>
#include <aqhome/ipc2/message.h>
#include <gwenhywfar/tag16.h>
void AqHomeMqttLog_ReadAndHandleMqttMessages(AQHOME_MQTT *aqh);
int AqHomeMqttLog_SendPing(AQHOME_MQTT *aqh);
void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);

1143
apps/aqhome-mqttlog/server.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
/****************************************************************************
* 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 SERVER_H
#define SERVER_H
#include "aqhome-mqttlog/types/device.h"
#include "aqhome/events2/object.h"
#define AQH_ENDPOINT_PERMS_LISTVALUES 0x0001
#define AQH_ENDPOINT_PERMS_READVALUE 0x0002
#define AQH_ENDPOINT_PERMS_ADDVALUE 0x0004
#define AQH_ENDPOINT_PERMS_LISTDATA 0x0010
#define AQH_ENDPOINT_PERMS_READDATA 0x0020
#define AQH_ENDPOINT_PERMS_ADDDATA 0x0040
#define AQH_ENDPOINT_PERMS_SETDATA 0x0080
#define AQH_ENDPOINT_PERMS_LISTDEVICES 0x0100
#define AQH_ENDPOINT_PERMS_READDEVICE 0x0200
#define AQH_ENDPOINT_PERMS_ADDDEVICE 0x0400
#define AQH_ENDPOINT_PERMS_MODDEVICE 0x0800
AQH_OBJECT *AQH_MqttLogServer_new(AQH_EVENT_LOOP *eventLoop);
int AQH_MqttLogServer_Init(AQH_OBJECT *o, int argc, char **argv);
void AQH_MqttLogServer_Fini(AQH_OBJECT *o);
void AQH_MqttLogServer_ReloadDeviceFiles(AQH_OBJECT *o);
void AQH_MqttLogServer_LoadRuntimeDeviceFiles(AQH_OBJECT *o);
int AQH_MqttLogServer_SaveRuntimeDeviceFiles(AQH_OBJECT *o);
/* loop functions */
void AQH_MqttLogServer_HandleBrokerMsgs(AQH_OBJECT *o);
void AQH_MqttLogServer_HandleMqttMsgs(AQH_OBJECT *o);
void AQH_MqttLogServer_CheckBrokerConnection(AQH_OBJECT *o);
void AQH_MqttLogServer_CheckMqttConnection(AQH_OBJECT *o);
int AQH_MqttLogServer_SendPing(AQH_OBJECT *o);
/* getters and setters */
int AQH_MqttLogServer_GetTimeout(const AQH_OBJECT *o);
void AQH_MqttLogServer_SetPidFile(AQH_OBJECT *o, const char *s);
void AQH_MqttLogServer_SetDeviceFile(AQH_OBJECT *o, const char *s);
/* device management */
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_GetAvailableDeviceList(const AQH_OBJECT *o);
void AQH_MqttLogServer_SetAvailableDeviceList(AQH_OBJECT *o, AQHMQTT_DEVICE_LIST *dl);
void AQH_MqttLogServer_SetRegisteredDeviceList(AQH_OBJECT *o, AQHMQTT_DEVICE_LIST *dl);
AQHMQTT_DEVICE *AQH_MqttLogServer_FindRegisteredDevice(AQH_OBJECT *o, const char *wantedDeviceId);
void AQH_MqttLogServer_DumpRegisteredDevices(const AQH_OBJECT *o);
#endif

View File

@@ -1,20 +1,24 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOME_MQTT_P_H
#define AQHOME_MQTT_P_H
#ifndef SERVER_P_H
#define SERVER_P_H
#include "./aqhome_mqtt.h"
#include "./server.h"
#include "aqhome-nodes/types/device.h"
#include <gwenhywfar/mutex.h>
#include "aqhome/ipc2/msgrequest.h"
#include <termios.h>
/* default values */
#define AQHOME_MQTT_DEFAULT_PIDFILE "/var/run/aqhome-mqtt.pid"
#define AQHOME_MQTT_DEFAULT_DATADIR "/var/lib/aqhome-mqtt"
#define AQHOME_MQTT_DEFAULT_DEVICEFILE "mqttlog/registereddevices.xml"
@@ -24,22 +28,40 @@
struct AQHOME_MQTT {
GWEN_MSG_ENDPOINT *rootEndpoint;
GWEN_MSG_ENDPOINT *brokerEndpoint; /* do not free (is part of tree pointed to by rootEndpoint) */
GWEN_MSG_ENDPOINT *mqttEndpoint; /* do not free (is part of tree pointed to by rootEndpoint) */
typedef struct AQH_MQTTLOG_SERVER AQH_MQTTLOG_SERVER;
struct AQH_MQTTLOG_SERVER {
AQH_OBJECT *mqttEndpoint;
AQH_OBJECT *brokerEndpoint;
GWEN_DB_NODE *dbArgs;
char *pidFile;
int timeout; /* timeout for run e.g. inside valgrind */
AQHMQTT_DEVICE_LIST *availableDeviceList;
AQHMQTT_DEVICE_LIST *registeredDeviceList;
char *deviceFile;
char *pidFile;
int timeout; /* timeout for run e.g. inside valgrind */
char *mqttAddress;
int mqttPort;
char *mqttClientId;
int mqttKeepAlive;
char *brokerAddress;
int brokerPort;
char *brokerClientId;
time_t timestampMqttDown;
time_t timestampBrokerDown;
int timeoutInSeconds;
};
AQH_MQTTLOG_SERVER *AQH_MqttLogServer_GetServerData(const AQH_OBJECT *o);
#endif

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
@@ -11,7 +11,7 @@
#endif
#include "./xmlread.h"
#include "./aqhome_mqtt_p.h"
#include "./server_p.h"
#include "aqhome-mqttlog/types/topic.h"
#include "aqhome-mqttlog/types/value.h"
#include "aqhome-mqttlog/types/translation.h"
@@ -41,16 +41,16 @@
* ------------------------------------------------------------------------------------------------
*/
static AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *sl);
static int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList);
static int _readXmlDevices(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList);
static AQHMQTT_DEVICE *_readXmlDevice(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceNode);
static AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode);
static AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode);
static AQHMQTT_VALUE_LIST *_readXmlValueList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode);
static AQHMQTT_VALUE *_readXmlValue(AQHOME_MQTT *aqh, GWEN_XMLNODE *valueNode);
static AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode);
static AQHMQTT_TRANSLATION *_readXmlTranslation(AQHOME_MQTT *aqh, GWEN_XMLNODE *translationNode);
static AQHMQTT_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl);
static int _readDeviceFileToList(const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList);
static int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList);
static AQHMQTT_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode);
static AQHMQTT_TOPIC_LIST *_readXmlTopicList(GWEN_XMLNODE *parentNode);
static AQHMQTT_TOPIC *_readXmlTopic(GWEN_XMLNODE *topicNode);
static AQHMQTT_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *parentNode);
static AQHMQTT_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode);
static AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(GWEN_XMLNODE *parentNode);
static AQHMQTT_TRANSLATION *_readXmlTranslation(GWEN_XMLNODE *translationNode);
@@ -60,61 +60,76 @@ static AQHMQTT_TRANSLATION *_readXmlTranslation(AQHOME_MQTT *aqh, GWEN_XMLNODE *
* ------------------------------------------------------------------------------------------------
*/
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDeviceFile(AQHOME_MQTT *aqh, const char *sFilename)
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDeviceFile(AQH_OBJECT *o, const char *sFilename)
{
int rv;
if (o) {
AQH_MQTTLOG_SERVER *xo;
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE);
if (rv<0) {
DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename);
return NULL;
}
else {
AQHMQTT_DEVICE_LIST *deviceList;
xo=AQH_MqttLogServer_GetServerData(o);
if (xo) {
int rv;
deviceList=AQHMQTT_Device_List_new();
rv=_readDeviceFileToList(aqh, sFilename, deviceList);
if (rv<0) {
DBG_ERROR(NULL, "File \"%s\" not found", sFilename);
AQHMQTT_Device_List_free(deviceList);
return NULL;
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE);
if (rv<0) {
DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename);
return NULL;
}
else {
AQHMQTT_DEVICE_LIST *deviceList;
deviceList=AQHMQTT_Device_List_new();
rv=_readDeviceFileToList(sFilename, deviceList);
if (rv<0) {
DBG_ERROR(NULL, "File \"%s\" not found", sFilename);
AQHMQTT_Device_List_free(deviceList);
return NULL;
}
if (AQHMQTT_Device_List_GetCount(deviceList)<1) {
AQHMQTT_Device_List_free(deviceList);
return NULL;
}
return deviceList;
}
}
if (AQHMQTT_Device_List_GetCount(deviceList)<1) {
AQHMQTT_Device_List_free(deviceList);
return NULL;
}
return deviceList;
}
return NULL;
}
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDataDeviceFiles(AQHOME_MQTT *aqh)
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDataDeviceFiles(AQH_OBJECT *o)
{
GWEN_STRINGLIST *sl;
if (o) {
AQH_MQTTLOG_SERVER *xo;
sl=AQH_GetListOfMatchingDataFiles("aqhome/devices/mqtt", "*.xml");
if (sl) {
AQHMQTT_DEVICE_LIST *deviceList;
xo=AQH_MqttLogServer_GetServerData(o);
if (xo) {
GWEN_STRINGLIST *sl;
deviceList=_readDeviceFiles(aqh, sl);
GWEN_StringList_free(sl);
if (deviceList==NULL) {
DBG_INFO(NULL, "Error reading data device files");
return NULL;
sl=AQH_GetListOfMatchingDataFiles("aqhome/devices/mqtt", "*.xml");
if (sl) {
AQHMQTT_DEVICE_LIST *deviceList;
deviceList=_readDeviceFiles(sl);
GWEN_StringList_free(sl);
if (deviceList==NULL) {
DBG_INFO(NULL, "Error reading data device files");
return NULL;
}
return deviceList;
}
else {
DBG_ERROR(NULL, "No data device files");
}
}
return deviceList;
}
else {
DBG_ERROR(NULL, "No data device files");
return NULL;
}
return NULL;
}
AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *sl)
AQHMQTT_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl)
{
GWEN_STRINGLISTENTRY *se;
AQHMQTT_DEVICE_LIST *deviceList;
@@ -129,7 +144,7 @@ AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *s
int rv;
DBG_INFO(NULL, "Reading device file \"%s\"", s);
rv=_readDeviceFileToList(aqh, s, deviceList);
rv=_readDeviceFileToList(s, deviceList);
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
DBG_WARN(NULL, "Error reading device file \"%s\" (%d), ignoring", s, rv);
}
@@ -147,7 +162,7 @@ AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *s
int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList)
int _readDeviceFileToList(const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList)
{
GWEN_XMLNODE *rootNode;
GWEN_XMLNODE *deviceListNode;
@@ -165,7 +180,7 @@ int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVIC
if (deviceListNode==NULL)
deviceListNode=rootNode;
rv=_readXmlDevices(aqh, deviceListNode, deviceList);
rv=_readXmlDevices(deviceListNode, deviceList);
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
DBG_ERROR(AQH_LOGDOMAIN, "Error reading devices from file \"%s\" (%d)", sFilename, rv);
GWEN_XMLNode_free(rootNode);
@@ -179,7 +194,7 @@ int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVIC
int _readXmlDevices(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList)
int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList)
{
GWEN_XMLNODE *deviceNode;
@@ -192,7 +207,7 @@ int _readXmlDevices(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVI
if (driverName && *driverName && strcasecmp(driverName, "mqtt")==0) {
AQHMQTT_DEVICE *device;
device=_readXmlDevice(aqh, deviceNode);
device=_readXmlDevice(deviceNode);
if (device==NULL) {
DBG_INFO(NULL, "Error reading device from XML");
return GWEN_ERROR_BAD_DATA;
@@ -227,7 +242,7 @@ int _readXmlDevices(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVI
AQHMQTT_DEVICE *_readXmlDevice(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceNode)
AQHMQTT_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode)
{
AQHMQTT_DEVICE *device;
GWEN_XMLNODE *topicsNode;
@@ -241,7 +256,7 @@ AQHMQTT_DEVICE *_readXmlDevice(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceNode)
if (topicsNode) {
AQHMQTT_TOPIC_LIST *topicList;
topicList=_readXmlTopicList(aqh, topicsNode);
topicList=_readXmlTopicList(topicsNode);
if (topicList)
AQHMQTT_Device_SetTopicList(device, topicList);
else {
@@ -261,7 +276,7 @@ AQHMQTT_DEVICE *_readXmlDevice(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceNode)
AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode)
AQHMQTT_TOPIC_LIST *_readXmlTopicList(GWEN_XMLNODE *parentNode)
{
AQHMQTT_TOPIC_LIST *topicList;
GWEN_XMLNODE *topicNode;
@@ -269,7 +284,7 @@ AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode
topicList=AQHMQTT_Topic_List_new();
topicNode=GWEN_XMLNode_FindFirstTag(parentNode, "mqtttopic", NULL, NULL);
while(topicNode) {
AQHMQTT_TOPIC *topic=_readXmlTopic(aqh, topicNode);
AQHMQTT_TOPIC *topic=_readXmlTopic(topicNode);
if (topic)
AQHMQTT_Topic_List_Add(topic, topicList);
else {
@@ -289,7 +304,7 @@ AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode
AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode)
AQHMQTT_TOPIC *_readXmlTopic(GWEN_XMLNODE *topicNode)
{
AQHMQTT_TOPIC *topic;
GWEN_XMLNODE *valuesNode;
@@ -325,7 +340,7 @@ AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode)
if (valuesNode) {
AQHMQTT_VALUE_LIST *valueList;
valueList=_readXmlValueList(aqh, valuesNode);
valueList=_readXmlValueList(valuesNode);
if (valueList)
AQHMQTT_Topic_SetValueList(topic, valueList);
else {
@@ -345,7 +360,7 @@ AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode)
AQHMQTT_VALUE_LIST *_readXmlValueList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode)
AQHMQTT_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *parentNode)
{
AQHMQTT_VALUE_LIST *valueList;
GWEN_XMLNODE *valueNode;
@@ -353,7 +368,7 @@ AQHMQTT_VALUE_LIST *_readXmlValueList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode
valueList=AQHMQTT_Value_List_new();
valueNode=GWEN_XMLNode_FindFirstTag(parentNode, "value", NULL, NULL);
while(valueNode) {
AQHMQTT_VALUE *value=_readXmlValue(aqh, valueNode);
AQHMQTT_VALUE *value=_readXmlValue(valueNode);
if (value)
AQHMQTT_Value_List_Add(value, valueList);
else {
@@ -373,7 +388,7 @@ AQHMQTT_VALUE_LIST *_readXmlValueList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode
AQHMQTT_VALUE *_readXmlValue(AQHOME_MQTT *aqh, GWEN_XMLNODE *valueNode)
AQHMQTT_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode)
{
AQHMQTT_VALUE *value;
GWEN_XMLNODE *translationNode;
@@ -398,7 +413,7 @@ AQHMQTT_VALUE *_readXmlValue(AQHOME_MQTT *aqh, GWEN_XMLNODE *valueNode)
if (translationNode) {
AQHMQTT_TRANSLATION_LIST *translationList;
translationList=_readXmlTranslationList(aqh, translationNode);
translationList=_readXmlTranslationList(translationNode);
if (translationList) {
DBG_INFO(NULL, "Translations read");
AQHMQTT_Value_SetTranslationList(value, translationList);
@@ -413,7 +428,7 @@ AQHMQTT_VALUE *_readXmlValue(AQHOME_MQTT *aqh, GWEN_XMLNODE *valueNode)
AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode)
AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(GWEN_XMLNODE *parentNode)
{
AQHMQTT_TRANSLATION_LIST *translationList;
GWEN_XMLNODE *translationNode;
@@ -421,7 +436,7 @@ AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(AQHOME_MQTT *aqh, GWEN_XMLNODE
translationList=AQHMQTT_Translation_List_new();
translationNode=GWEN_XMLNode_FindFirstTag(parentNode, "translation", NULL, NULL);
while(translationNode) {
AQHMQTT_TRANSLATION *translation=_readXmlTranslation(aqh, translationNode);
AQHMQTT_TRANSLATION *translation=_readXmlTranslation(translationNode);
if (translation)
AQHMQTT_Translation_List_Add(translation, translationList);
else {
@@ -441,7 +456,7 @@ AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(AQHOME_MQTT *aqh, GWEN_XMLNODE
AQHMQTT_TRANSLATION *_readXmlTranslation(AQHOME_MQTT *aqh, GWEN_XMLNODE *translationNode)
AQHMQTT_TRANSLATION *_readXmlTranslation(GWEN_XMLNODE *translationNode)
{
const char *sAqhValue;
const char *sDriverValue;

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
@@ -9,14 +9,14 @@
#ifndef AQHOME_MQTTLOG_XMLREAD_H
#define AQHOME_MQTTLOG_XMLREAD_H
#include "aqhome-mqttlog/server.h"
#include "aqhome-mqttlog/aqhome_mqtt.h"
#include "aqhome-mqttlog/types/device.h"
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDataDeviceFiles(AQHOME_MQTT *aqh);
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDeviceFile(AQHOME_MQTT *aqh, const char *sFilename);
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDataDeviceFiles(AQH_OBJECT *o);
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDeviceFile(AQH_OBJECT *o, const char *sFilename);

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
@@ -54,7 +54,7 @@ static void _setXmlCharValueIfNotNull(GWEN_XMLNODE *n, const char *name, const c
int AqHomeMqttLog_WriteDevicesFile(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename)
int AQH_MqttLogServer_WriteDevicesFile(const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename)
{
int rv;

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
@@ -9,13 +9,13 @@
#ifndef AQHOME_MQTTLOG_XMLWRITE_H
#define AQHOME_MQTTLOG_XMLWRITE_H
#include "aqhome-mqttlog/server.h"
#include "aqhome-mqttlog/aqhome_mqtt.h"
#include "aqhome-mqttlog/types/device.h"
int AqHomeMqttLog_WriteDevicesFile(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename);
int AQH_MqttLogServer_WriteDevicesFile(const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename);

View File

@@ -35,40 +35,29 @@
</setVar>
<headers dist="true" >
aqhomed.h
aqhomed_p.h
init.h
fini.h
loop.h
loop_broker.h
loop_tty.h
loop_tty_ipc.h
loop_tty_broker.h
loop_ipc.h
db.h
tty_log.h
devicesread.h
devicesdump.h
r_setdata.h
r_connect.h
r_forward.h
r_setaccmsggrps.h
r_getnodes.h
</headers>
<sources>
$(local/typefiles)
main.c
aqhomed.c
init.c
fini.c
loop.c
loop_broker.c
loop_tty.c
loop_tty_ipc.c
loop_tty_broker.c
loop_ipc.c
server.c
db.c
tty_log.c
devicesread.c
devicesdump.c
r_setdata.c
r_connect.c
r_forward.c
r_setaccmsggrps.c
r_getnodes.c
main.c
</sources>
<useTargets>

View File

@@ -1,221 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
AQHOMED *AqHomed_new(void)
{
AQHOMED *aqh;
GWEN_NEW_OBJECT(AQHOMED, aqh);
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
aqh->nodeDb=AQH_NodeDb_new();
aqh->requestTree=GWEN_MsgRequest_new();
return aqh;
}
void AqHomed_free(AQHOMED *aqh)
{
if (aqh) {
GWEN_MsgRequest_free(aqh->requestTree);
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
aqh->rootEndpoint=NULL;
aqh->ttyEndpoint=NULL;
aqh->ipcdEndpoint=NULL;
aqh->brokerEndpoint=NULL;
GWEN_DB_Group_free(aqh->dbArgs);
AQH_NodeDb_free(aqh->nodeDb);
aqh->dbArgs=NULL;
free(aqh->logFile);
free(aqh->pidFile);
free(aqh->dbFile);
GWEN_FREE_OBJECT(aqh);
}
}
GWEN_MSG_ENDPOINT *AqHomed_GetTtyEndpoint(const AQHOMED *aqh)
{
return aqh?aqh->ttyEndpoint:NULL;
}
GWEN_MSG_ENDPOINT *AqHomed_GetIpcdEndpoint(const AQHOMED *aqh)
{
return aqh?aqh->ipcdEndpoint:NULL;
}
GWEN_MSG_ENDPOINT *AqHomed_GetBrokerEndpoint(const AQHOMED *aqh)
{
return aqh?aqh->brokerEndpoint:NULL;
}
GWEN_DB_NODE *AqHomed_GetDbArgs(const AQHOMED *aqh)
{
return aqh?aqh->dbArgs:NULL;
}
const char *AqHomed_GetLogFile(const AQHOMED *aqh)
{
return aqh?aqh->logFile:NULL;
}
void AqHomed_SetLogFile(AQHOMED *aqh, const char *s)
{
if (aqh) {
free(aqh->logFile);
aqh->logFile=s?strdup(s):NULL;
}
}
const char *AqHomed_GetPidFile(const AQHOMED *aqh)
{
return aqh?aqh->pidFile:NULL;
}
void AqHomed_SetPidFile(AQHOMED *aqh, const char *s)
{
if (aqh) {
free(aqh->pidFile);
aqh->pidFile=s?strdup(s):NULL;
}
}
const char *AqHomed_GetDbFile(const AQHOMED *aqh)
{
return aqh?aqh->dbFile:NULL;
}
void AqHomed_SetDbFile(AQHOMED *aqh, const char *s)
{
if (aqh) {
free(aqh->dbFile);
aqh->dbFile=s?strdup(s):NULL;
}
}
int AqHomed_GetTimeout(const AQHOMED *aqh)
{
return aqh?aqh->timeout:0;
}
GWEN_MSG_REQUEST *AqHomed_GetRequestTree(const AQHOMED *aqh)
{
return aqh?aqh->requestTree:NULL;
}
void AqHomed_AddRequestToTree(AQHOMED *aqh, GWEN_MSG_REQUEST *rq)
{
if (aqh && rq)
GWEN_MsgRequest_Tree2_AddChild(aqh->requestTree, rq);
}
const AQHNODE_DEVICE_LIST *AqHomed_GetDeviceDefList(const AQHOMED *aqh)
{
return aqh?aqh->deviceDefList:NULL;
}
const AQHNODE_DEVICE *AqHomed_FindDeviceDef(const AQHOMED *aqh, uint32_t manufacturer, uint16_t deviceType, uint16_t deviceVersion)
{
if (aqh && aqh->deviceDefList) {
const AQHNODE_DEVICE *device;
device=AQHNODE_Device_List_First(aqh->deviceDefList);
while(device) {
if (AQHNODE_Device_GetManufacturer(device)==manufacturer &&
AQHNODE_Device_GetDeviceType(device)==deviceType &&
AQHNODE_Device_GetDeviceVersion(device)==(deviceVersion & 0xff00))
return device;
device=AQHNODE_Device_List_Next(device);
}
}
return NULL;
}
const AQHNODE_DEVICE *AqHomed_GetDeviceDefByName(const AQHOMED *aqh, const char *name)
{
if (aqh && aqh->deviceDefList && name)
return AQHNODE_Device_List_GetByName(aqh->deviceDefList, name);
return NULL;
}

View File

@@ -1,59 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_H
#define AQHOMED_H
#include <gwenhywfar/endpoint.h>
#include <gwenhywfar/db.h>
#include <gwenhywfar/request.h>
#define AQHOME_ENDPOINTGROUP_NODE 1
#define AQHOME_ENDPOINTGROUP_IPC 2
#define AQHOME_ENDPOINTGROUP_MQTT 4
typedef struct AQHOMED AQHOMED;
#include "aqhome-nodes/types/device.h"
AQHOMED *AqHomed_new(void);
void AqHomed_free(AQHOMED *aqh);
GWEN_MSG_ENDPOINT *AqHomed_GetTtyEndpoint(const AQHOMED *aqh);
GWEN_MSG_ENDPOINT *AqHomed_GetIpcdEndpoint(const AQHOMED *aqh);
GWEN_MSG_ENDPOINT *AqHomed_GetBrokerEndpoint(const AQHOMED *aqh);
GWEN_DB_NODE *AqHomed_GetDbArgs(const AQHOMED *aqh);
const char *AqHomed_GetLogFile(const AQHOMED *aqh);
void AqHomed_SetLogFile(AQHOMED *aqh, const char *s);
const char *AqHomed_GetPidFile(const AQHOMED *aqh);
void AqHomed_SetPidFile(AQHOMED *aqh, const char *s);
const char *AqHomed_GetDbFile(const AQHOMED *aqh);
void AqHomed_SetDbFile(AQHOMED *aqh, const char *s);
int AqHomed_GetTimeout(const AQHOMED *aqh);
GWEN_MSG_REQUEST *AqHomed_GetRequestTree(const AQHOMED *aqh);
void AqHomed_AddRequestToTree(AQHOMED *aqh, GWEN_MSG_REQUEST *rq);
const AQHNODE_DEVICE_LIST *AqHomed_GetDeviceDefList(const AQHOMED *aqh);
const AQHNODE_DEVICE *AqHomed_FindDeviceDef(const AQHOMED *aqh, uint32_t manufacturer, uint16_t deviceType, uint16_t deviceVersion);
const AQHNODE_DEVICE *AqHomed_GetDeviceDefByName(const AQHOMED *aqh, const char *name);
#endif

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
@@ -12,28 +12,25 @@
#include "./db.h"
#include "./aqhomed_p.h"
#include "./server_p.h"
#include "aqhome/aqhome.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/msg/msg_sendstats.h"
#include "aqhome/msg/msg_recvstats.h"
#include "aqhome/msg/msg_value2.h"
#include "aqhome/msg/msg_value3.h"
#include "aqhome/msg/msg_needaddr.h"
#include "aqhome/msg/msg_claimaddr.h"
#include "aqhome/msg/msg_haveaddr.h"
#include "aqhome/msg/msg_device.h"
#include "aqhome/msg/msg_flashready.h"
#include "aqhome/msg/node/m_node.h"
#include "aqhome/msg/node/m_sendstats.h"
#include "aqhome/msg/node/m_recvstats.h"
#include "aqhome/msg/node/m_value.h"
#include "aqhome/msg/node/m_addr.h"
#include "aqhome/msg/node/m_device.h"
#include "aqhome/msg/node/m_flashready.h"
#include "aqhome/data/value.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_values.h"
#include "aqhome/msg/ipc/data/m_ipcd.h"
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
#include "aqhome/ipc2/endpoint.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/timestamp.h>
@@ -43,23 +40,20 @@
* ------------------------------------------------------------------------------------------------
*/
static void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgValue3(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgNeedAddress(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgClaimAddress(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgHaveAddress(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgComSendStat(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgComRecvStat(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg);
static void _handleMsgValue(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _handleAddressMsg(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _handleMsgComSendStat(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _handleMsgComRecvStat(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _handleMsgDevice(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static void _handleMsgFlashReady(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
static AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *msg, uint32_t uid);
static AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg, uint32_t uid);
static void _updateTimestampLastChange(AQH_NODE_INFO *ni);
static void _assignDeviceId(AQHOMED *aqh, AQH_NODE_INFO *ni, uint32_t uid);
static void _assignDeviceId(AQH_OBJECT *o, AQH_NODE_INFO *ni, uint32_t uid);
static void _announceNodeValues(AQHOMED *aqh, const AQH_NODE_INFO *ni);
static void _announceNodeValues(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_NODE_INFO *ni);
static void _setDeviceName(AQH_VALUE *value, uint32_t uid);
static void _announceValue(AQHOMED *aqh, uint32_t uid, const AQHNODE_VALUE *v);
static void _announceValue(AQH_NODE_SERVER *xo, uint32_t uid, const AQHNODE_VALUE *v);
@@ -69,61 +63,57 @@ static void _announceValue(AQHOMED *aqh, uint32_t uid, const AQHNODE_VALUE *v);
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_NodeMsgToDb(AQHOMED *aqh, const GWEN_MSG *msg)
void AQH_NodeServer_NodeMsgToDb(AQH_OBJECT *o, const AQH_MESSAGE *msg)
{
int msgIsValid;
uint8_t msgType;
AQH_NODE_SERVER *xo;
DBG_INFO(AQH_LOGDOMAIN,
" - msg %d (%s) from %d to %d",
AQH_NodeMsg_GetMsgType(msg),
AQH_NodeMsg_MsgTypeToChar(AQH_NodeMsg_GetMsgType(msg)),
AQH_NodeMsg_GetSourceAddress(msg),
AQH_NodeMsg_GetDestAddress(msg));
xo=AQH_NodeServer_GetServerData(o);
if (xo) {
uint8_t msgType;
msgIsValid=(AQH_NodeMsg_IsChecksumValid(msg) && AQH_NodeMsg_IsMsgComplete(msg));
msgType=AQH_NodeMsg_GetMsgType(msg);
msgType=AQH_NodeMessage_GetMsgType(msg);
if (msgIsValid) {
switch(msgType) {
case AQH_MSG_TYPE_COMSENDSTATS: _handleMsgComSendStat(aqh, msg); break;
case AQH_MSG_TYPE_COMRECVSTATS: _handleMsgComRecvStat(aqh, msg); break;
case AQH_MSG_TYPE_VALUE2: _handleMsgValue2(aqh, msg); break;
case AQH_MSG_TYPE_VALUE_REPORT: _handleMsgValue3(aqh, msg); break;
case AQH_MSG_TYPE_NEED_ADDRESS: _handleMsgNeedAddress(aqh, msg); break;
case AQH_MSG_TYPE_CLAIM_ADDRESS: _handleMsgClaimAddress(aqh, msg); break;
case AQH_MSG_TYPE_HAVE_ADDRESS: _handleMsgHaveAddress(aqh, msg); break;
case AQH_MSG_TYPE_DEVICE: _handleMsgDevice(aqh, msg); break;
case AQH_MSG_TYPE_FLASH_READY: _handleMsgFlashReady(aqh, msg); break;
default: break;
case AQH_MSG_TYPE_COMSENDSTATS: _handleMsgComSendStat(xo, msg); break;
case AQH_MSG_TYPE_COMRECVSTATS: _handleMsgComRecvStat(xo, msg); break;
case AQH_MSG_TYPE_VALUE_REPORT: _handleMsgValue(xo, msg); break;
case AQH_MSG_TYPE_NEED_ADDRESS: _handleAddressMsg(xo, msg); break;
case AQH_MSG_TYPE_CLAIM_ADDRESS: _handleAddressMsg(xo, msg); break;
case AQH_MSG_TYPE_HAVE_ADDRESS: _handleAddressMsg(xo, msg); break;
case AQH_MSG_TYPE_DEVICE: _handleMsgDevice(o, xo, msg); break;
case AQH_MSG_TYPE_FLASH_READY: _handleMsgFlashReady(o, xo, msg); break;
default: break;
}
}
}
void AqHomed_WriteNodeDb(AQHOMED *aqh)
void AQH_NodeServer_WriteNodeDb(AQH_OBJECT *o)
{
if (aqh->dbFile) {
AQH_NODE_SERVER *xo;
xo=AQH_NodeServer_GetServerData(o);
if (xo && xo->dbFile) {
GWEN_DB_NODE *dbNodeDb;
AQH_NodeDb_ClearModified(aqh->nodeDb);
AQH_NodeDb_ClearModified(xo->nodeDb);
dbNodeDb=GWEN_DB_Group_new("nodeDb");
AQH_NodeDb_toDb(aqh->nodeDb, dbNodeDb);
GWEN_DB_WriteFile(dbNodeDb, aqh->dbFile, GWEN_DB_FLAGS_DEFAULT);
AQH_NodeDb_toDb(xo->nodeDb, dbNodeDb);
GWEN_DB_WriteFile(dbNodeDb, xo->dbFile, GWEN_DB_FLAGS_DEFAULT);
GWEN_DB_Group_free(dbNodeDb);
}
}
void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg)
void _handleMsgValue(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_Value2Msg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
uid=AQH_ValueMessage_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
if (ni==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
}
@@ -131,13 +121,13 @@ void _handleMsgValue2(AQHOMED *aqh, const GWEN_MSG *msg)
void _handleMsgValue3(AQHOMED *aqh, const GWEN_MSG *msg)
void _handleAddressMsg(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_Value3Msg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
uid=AQH_AddrMessage_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
if (ni==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
}
@@ -145,111 +135,69 @@ void _handleMsgValue3(AQHOMED *aqh, const GWEN_MSG *msg)
void _handleMsgNeedAddress(AQHOMED *aqh, const GWEN_MSG *msg)
void _handleMsgComSendStat(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_NeedAddrMsg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
uid=AQH_SendStatsMessage_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
if (ni==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
}
}
void _handleMsgClaimAddress(AQHOMED *aqh, const GWEN_MSG *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_ClaimAddrMsg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
if (ni==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
}
}
void _handleMsgHaveAddress(AQHOMED *aqh, const GWEN_MSG *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_HaveAddrMsg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
if (ni==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
}
}
void _handleMsgComSendStat(AQHOMED *aqh, const GWEN_MSG *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_SendStatsMsg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
if (ni==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
}
AQH_NodeInfo_SetStatsPacketsOut(ni, AQH_SendStatsMsg_GetPacketsOut(msg));
AQH_NodeInfo_SetStatsCollisions(ni, AQH_SendStatsMsg_GetCollisions(msg));
AQH_NodeInfo_SetStatsBusy(ni, AQH_SendStatsMsg_GetBusyErrors(msg));
AQH_NodeDb_SetModified(aqh->nodeDb);
AQH_NodeInfo_SetStatsPacketsOut(ni, AQH_SendStatsMessage_GetPacketsOut(msg));
AQH_NodeInfo_SetStatsCollisions(ni, AQH_SendStatsMessage_GetCollisions(msg));
AQH_NodeInfo_SetStatsBusy(ni, AQH_SendStatsMessage_GetBusyErrors(msg));
AQH_NodeDb_SetModified(xo->nodeDb);
_updateTimestampLastChange(ni);
}
void _handleMsgComRecvStat(AQHOMED *aqh, const GWEN_MSG *msg)
void _handleMsgComRecvStat(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_RecvStatsMsg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
uid=AQH_RecvStatsMessage_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
if (ni==NULL) {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
}
AQH_NodeInfo_SetStatsPacketsIn(ni, AQH_RecvStatsMsg_GetPacketsIn(msg));
AQH_NodeInfo_SetStatsCrcErrors(ni, AQH_RecvStatsMsg_GetCrcErrors(msg));
AQH_NodeInfo_SetStatsIoErrors(ni, AQH_RecvStatsMsg_GetIoErrors(msg));
AQH_NodeDb_SetModified(aqh->nodeDb);
AQH_NodeInfo_SetStatsPacketsIn(ni, AQH_RecvStatsMessage_GetPacketsIn(msg));
AQH_NodeInfo_SetStatsCrcErrors(ni, AQH_RecvStatsMessage_GetCrcErrors(msg));
AQH_NodeInfo_SetStatsIoErrors(ni, AQH_RecvStatsMessage_GetIoErrors(msg));
AQH_NodeDb_SetModified(xo->nodeDb);
_updateTimestampLastChange(ni);
}
void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg)
void _handleMsgDevice(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_DeviceMsg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
uid=AQH_DeviceMessage_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
if (ni) {
const char *s;
AQH_NodeInfo_SetManufacturer(ni, AQH_DeviceMsg_GetManufacturer(msg));
AQH_NodeInfo_SetDeviceType(ni, AQH_DeviceMsg_GetDeviceType(msg));
AQH_NodeInfo_SetDeviceVersion(ni, (AQH_DeviceMsg_GetDeviceVersion(msg)<<8)+AQH_DeviceMsg_GetDeviceRevision(msg));
AQH_NodeInfo_SetManufacturer(ni, AQH_DeviceMessage_GetManufacturer(msg));
AQH_NodeInfo_SetDeviceType(ni, AQH_DeviceMessage_GetDeviceType(msg));
AQH_NodeInfo_SetDeviceVersion(ni, (AQH_DeviceMessage_GetDeviceVersion(msg)<<8)+AQH_DeviceMessage_GetDeviceRevision(msg));
AQH_NodeInfo_SetFirmwareVersion(ni,
(AQH_DeviceMsg_GetFirmwareVariant(msg)<<24) |
(AQH_DeviceMsg_GetFirmwareVersionMajor(msg)<<16) |
(AQH_DeviceMsg_GetFirmwareVersionMinor(msg)<<8) |
AQH_DeviceMsg_GetFirmwareVersionPatchlevel(msg));
(AQH_DeviceMessage_GetFirmwareVariant(msg)<<24) |
(AQH_DeviceMessage_GetFirmwareVersionMajor(msg)<<16) |
(AQH_DeviceMessage_GetFirmwareVersionMinor(msg)<<8) |
AQH_DeviceMessage_GetFirmwareVersionPatchlevel(msg));
s=AQH_NodeInfo_GetDeviceId(ni);
if (!(s && *s))
_assignDeviceId(aqh, ni, uid);
_assignDeviceId(o, ni, uid);
_updateTimestampLastChange(ni);
AQH_NodeDb_SetModified(aqh->nodeDb);
AQH_NodeDb_SetModified(xo->nodeDb);
if (uid!=0x00000000L && uid!=0xffffffff)
_announceNodeValues(aqh, ni);
_announceNodeValues(o, xo, ni);
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
@@ -258,7 +206,7 @@ void _handleMsgDevice(AQHOMED *aqh, const GWEN_MSG *msg)
void _announceNodeValues(AQHOMED *aqh, const AQH_NODE_INFO *ni)
void _announceNodeValues(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_NODE_INFO *ni)
{
const char *devName;
@@ -266,7 +214,7 @@ void _announceNodeValues(AQHOMED *aqh, const AQH_NODE_INFO *ni)
if (devName) {
const AQHNODE_DEVICE *devInfo;
devInfo=AqHomed_GetDeviceDefByName(aqh, devName);
devInfo=AQH_NodeServer_GetDeviceDefByName(o, devName);
if (devInfo) {
const AQHNODE_VALUE_LIST *valueList;
@@ -280,7 +228,7 @@ void _announceNodeValues(AQHOMED *aqh, const AQH_NODE_INFO *ni)
AQH_NodeInfo_GetUid(ni), AQHNODE_Value_GetName(v),
AQHNODE_Value_GetModality(v),
AQH_ValueModality_toString(AQHNODE_Value_GetModality(v)));
_announceValue(aqh, AQH_NodeInfo_GetUid(ni), v);
_announceValue(xo, AQH_NodeInfo_GetUid(ni), v);
v=AQHNODE_Value_List_Next(v);
}
}
@@ -308,10 +256,10 @@ void _setDeviceName(AQH_VALUE *value, uint32_t uid)
void _announceValue(AQHOMED *aqh, uint32_t uid, const AQHNODE_VALUE *v)
void _announceValue(AQH_NODE_SERVER *xo, uint32_t uid, const AQHNODE_VALUE *v)
{
AQH_VALUE *value;
GWEN_MSG *msg;
AQH_MESSAGE *msg;
value=AQH_Value_new();
_setDeviceName(value, uid);
@@ -320,41 +268,41 @@ void _announceValue(AQHOMED *aqh, uint32_t uid, const AQHNODE_VALUE *v)
AQH_Value_SetValueUnits(value, AQHNODE_Value_GetValueUnits(v));
AQH_Value_SetValueType(value, AQHNODE_Value_GetValueType(v));
AQH_Value_SetModality(value, AQHNODE_Value_GetModality(v));
msg=AQH_ValuesDataIpcMsg_newForOneValue(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
0, value);
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, msg);
msg=AQH_IpcdMessageValues_newForOne(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0,
0, value);
AQH_Endpoint_AddMsgOut(xo->brokerEndpoint, msg);
AQH_Value_free(value);
}
void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg)
void _handleMsgFlashReady(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
{
AQH_NODE_INFO *ni;
uint32_t uid;
uid=AQH_FlashReadyMsg_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(aqh, msg, uid);
uid=AQH_FlashReadyMessage_GetUid(msg);
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
if (ni) {
const char *s;
AQH_NodeInfo_SetManufacturer(ni, AQH_FlashReadyMsg_GetManufacturer(msg));
AQH_NodeInfo_SetDeviceType(ni, AQH_FlashReadyMsg_GetDeviceType(msg));
AQH_NodeInfo_SetDeviceVersion(ni, (AQH_FlashReadyMsg_GetDeviceVersion(msg)<<8)+AQH_FlashReadyMsg_GetDeviceRevision(msg));
AQH_NodeInfo_SetManufacturer(ni, AQH_FlashReadyMessage_GetManufacturer(msg));
AQH_NodeInfo_SetDeviceType(ni, AQH_FlashReadyMessage_GetDeviceType(msg));
AQH_NodeInfo_SetDeviceVersion(ni, (AQH_FlashReadyMessage_GetDeviceVersion(msg)<<8)+AQH_FlashReadyMessage_GetDeviceRevision(msg));
AQH_NodeInfo_SetFirmwareVersion(ni,
(AQH_FlashReadyMsg_GetFirmwareVariant(msg)<<24) |
(AQH_FlashReadyMsg_GetFirmwareVersionMajor(msg)<<16) |
(AQH_FlashReadyMsg_GetFirmwareVersionMinor(msg)<<8) |
AQH_FlashReadyMsg_GetFirmwareVersionPatchlevel(msg));
(AQH_FlashReadyMessage_GetFirmwareVariant(msg)<<24) |
(AQH_FlashReadyMessage_GetFirmwareVersionMajor(msg)<<16) |
(AQH_FlashReadyMessage_GetFirmwareVersionMinor(msg)<<8) |
AQH_FlashReadyMessage_GetFirmwareVersionPatchlevel(msg));
s=AQH_NodeInfo_GetDeviceId(ni);
if (!(s && *s))
_assignDeviceId(aqh, ni, uid);
_assignDeviceId(o, ni, uid);
_updateTimestampLastChange(ni);
AQH_NodeDb_SetModified(aqh->nodeDb);
AQH_NodeDb_SetModified(xo->nodeDb);
if (uid!=0x00000000L && uid!=0xffffffff)
_announceNodeValues(aqh, ni);
_announceNodeValues(o, xo, ni);
}
else {
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
@@ -363,13 +311,13 @@ void _handleMsgFlashReady(AQHOMED *aqh, const GWEN_MSG *msg)
AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *msg, uint32_t uid)
AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg, uint32_t uid)
{
uint8_t busAddr;
AQH_NODE_INFO *ni;
busAddr=AQH_NodeMsg_GetSourceAddress(msg);
ni=AQH_NodeDb_GetNodeInfoByUid(aqh->nodeDb, uid);
busAddr=AQH_NodeMessage_GetSourceAddress(msg);
ni=AQH_NodeDb_GetNodeInfoByUid(xo->nodeDb, uid);
if (ni) {
uint8_t storedBusAddr;
@@ -378,7 +326,7 @@ AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *ms
DBG_INFO(AQH_LOGDOMAIN, "Changed busaddr for %08x from %02x to %02x", uid, storedBusAddr, busAddr);
AQH_NodeInfo_SetBusAddress(ni, busAddr);
_updateTimestampLastChange(ni);
AQH_NodeDb_SetModified(aqh->nodeDb);
AQH_NodeDb_SetModified(xo->nodeDb);
}
}
else {
@@ -388,7 +336,7 @@ AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *ms
AQH_NodeInfo_SetBusAddress(ni, busAddr);
AQH_NodeInfo_SetUid(ni, uid);
_updateTimestampLastChange(ni);
rv=AQH_NodeDb_AddNodeInfo(aqh->nodeDb, ni);
rv=AQH_NodeDb_AddNodeInfo(xo->nodeDb, ni);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
AQH_NodeInfo_free(ni);
@@ -403,14 +351,14 @@ AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQHOMED *aqh, const GWEN_MSG *ms
void _assignDeviceId(AQHOMED *aqh, AQH_NODE_INFO *ni, uint32_t uid)
void _assignDeviceId(AQH_OBJECT *o, AQH_NODE_INFO *ni, uint32_t uid)
{
const AQHNODE_DEVICE *dev;
dev=AqHomed_FindDeviceDef(aqh,
AQH_NodeInfo_GetManufacturer(ni),
AQH_NodeInfo_GetDeviceType(ni),
AQH_NodeInfo_GetDeviceVersion(ni));
dev=AQH_NodeServer_FindDeviceDef(o,
AQH_NodeInfo_GetManufacturer(ni),
AQH_NodeInfo_GetDeviceType(ni),
AQH_NodeInfo_GetDeviceVersion(ni));
if (dev==NULL) {
DBG_ERROR(NULL,
"Unknown NODE device encountered (%08x, %04x, %04x)",

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
@@ -10,13 +10,15 @@
#define AQHOMED_DB_H
#include "./aqhomed.h"
#include "./server.h"
#include "aqhome/events2/object.h"
#include "aqhome/ipc2/message.h"
void AQH_NodeServer_NodeMsgToDb(AQH_OBJECT *o, const AQH_MESSAGE *msg);
void AqHomed_NodeMsgToDb(AQHOMED *aqh, const GWEN_MSG *msg);
void AqHomed_WriteNodeDb(AQHOMED *aqh);
void AQH_NodeServer_WriteNodeDb(AQH_OBJECT *o);

View File

@@ -12,7 +12,7 @@
#include "./devicesdump.h"
#include "./aqhomed_p.h"
#include "./server_p.h"
#include "aqhome/aqhome.h"
#include <gwenhywfar/debug.h>
@@ -34,7 +34,7 @@ static void _dumpValue(const AQHNODE_VALUE *value, GWEN_BUFFER *dbuf, int indent
* ------------------------------------------------------------------------------------------------
*/
void AqHomeNodes_DumpDevices(const AQHNODE_DEVICE_LIST *devList, GWEN_BUFFER *dbuf)
void AQH_NodeServer_DumpDevices(const AQHNODE_DEVICE_LIST *devList, GWEN_BUFFER *dbuf)
{
if (devList && AQHNODE_Device_List_GetCount(devList)) {

View File

@@ -10,12 +10,12 @@
#define AQHOME_NODES_DEVICESDUMP_H
#include "./aqhomed.h"
#include "./server.h"
#include "aqhome-nodes/types/device.h"
void AqHomeNodes_DumpDevices(const AQHNODE_DEVICE_LIST *devList, GWEN_BUFFER *dbuf);
void AQH_NodeServer_DumpDevices(const AQHNODE_DEVICE_LIST *devList, GWEN_BUFFER *dbuf);

View File

@@ -12,7 +12,7 @@
#include "./devicesread.h"
#include "./aqhomed_p.h"
#include "./server_p.h"
#include "aqhome/aqhome.h"
#include <gwenhywfar/directory.h>
@@ -51,7 +51,7 @@ static int _readDeviceVersion(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode);
* ------------------------------------------------------------------------------------------------
*/
AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDeviceFile(const char *sFilename)
AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDeviceFile(const char *sFilename)
{
int rv;
@@ -81,7 +81,7 @@ AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDeviceFile(const char *sFilename)
AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDataDeviceFiles()
AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDataDeviceFiles()
{
GWEN_STRINGLIST *sl;

View File

@@ -1,6 +1,6 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
@@ -10,13 +10,13 @@
#define AQHOME_NODES_DEVICESREAD_H
#include "./aqhomed.h"
#include "./server.h"
#include "aqhome-nodes/types/device.h"
AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDeviceFile(const char *sFilename);
AQHNODE_DEVICE_LIST *AqHomeNodes_ReadDataDeviceFiles(void);
AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDeviceFile(const char *sFilename);
AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDataDeviceFiles(void);

View File

@@ -1,89 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./fini.h"
#include "./db.h"
#include "./aqhomed_p.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <unistd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_Fini(AQHOMED *aqh)
{
if (aqh) {
if (aqh->rootEndpoint) {
_disconnectTree(aqh->rootEndpoint);
GWEN_MsgEndpoint_Disconnect(aqh->rootEndpoint);
}
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
aqh->rootEndpoint=NULL;
aqh->ttyEndpoint=NULL;
aqh->ipcdEndpoint=NULL;
aqh->brokerEndpoint=NULL;
AqHomed_WriteNodeDb(aqh);
if (aqh->pidFile)
remove(aqh->pidFile);
}
}
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
{
GWEN_MSG_ENDPOINT *epChild;
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
while(epChild) {
_disconnectTree(epChild);
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
} /* while */
GWEN_MsgEndpoint_Disconnect(ep);
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_FINI_H
#define AQHOMED_FINI_H
#include "./aqhomed.h"
void AqHomed_Fini(AQHOMED *aqh);
#endif

View File

@@ -1,540 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./init.h"
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "./devicesread.h"
#include "./devicesdump.h"
#include "aqhome/aqhome.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/endpoint_ipcclient.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <gwenhywfar/endpoint_multilayer.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static int _setupTty(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
static void _setupIpcd(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
static void _setupBroker(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
static void _setupLog(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
static void _setupDb(AQHOMED *aqh, GWEN_DB_NODE *dbArgs);
static int _loadDeviceList(AQHOMED *aqh);
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
static int _createPidFile(const char *pidFilename);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AqHomed_Init(AQHOMED *aqh, int argc, char **argv)
{
GWEN_DB_NODE *dbArgs;
int rv;
const char *s;
dbArgs=GWEN_DB_Group_new("args");
rv=_readArgs(argc, argv, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error reading args (%d)", rv);
return rv;
}
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
aqh->dbArgs=dbArgs;
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
if (s && *s) {
GWEN_LOGGER_LEVEL ll;
ll=GWEN_Logger_Name2Level(s);
GWEN_Logger_SetLevel(NULL, ll);
}
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOMED_DEFAULT_PIDFILE);
if (s && *s) {
AqHomed_SetPidFile(aqh, s);
rv=_createPidFile(s);
if (rv<0) {
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
return rv;
}
}
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
aqh->nodeAddress=GWEN_DB_GetIntValue(dbArgs, "nodeAddress", 0, AQHOMED_DEFAULT_NODEADDR);
rv=_loadDeviceList(aqh);
if (rv<0) {
DBG_ERROR(NULL, "Error loading device list(%d)", rv);
return rv;
}
#if 0
else {
GWEN_BUFFER *dbuf;
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
AqHomeNodes_DumpDevices(aqh->deviceDefList, dbuf);
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(dbuf));
GWEN_Buffer_free(dbuf);
}
#endif
_setupDb(aqh, dbArgs);
rv=_setupTty(aqh, dbArgs);
if (rv<0) {
DBG_ERROR(NULL, "Error setting up TTY endpoint (%d)", rv);
return rv;
}
_setupIpcd(aqh, dbArgs);
_setupBroker(aqh, dbArgs);
_setupLog(aqh, dbArgs);
return 0;
}
int _setupTty(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
{
const char *devicePath;
devicePath=GWEN_DB_GetCharValue(dbArgs, "device", 0, AQHOMED_DEFAULT_DEVICE);
if (devicePath && *devicePath) {
GWEN_MSG_ENDPOINT *epTty;
epTty=AQH_TtyEndpoint_new(devicePath, AQHOME_ENDPOINTGROUP_NODE);
if (epTty==NULL) {
DBG_ERROR(NULL, "Error creating endpoint TTY");
return GWEN_ERROR_GENERIC;
}
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, epTty);
aqh->ttyEndpoint=epTty;
}
else {
DBG_ERROR(NULL, "Missing device path");
return GWEN_ERROR_GENERIC;
}
return 0;
}
void _setupIpcd(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
{
const char *tcpAddress;
int tcpPort;
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
if (!(tcpAddress && *tcpAddress))
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/nodesAddress", 0, NULL);
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, -1);
if (tcpPort<0)
tcpPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/nodesPort", 0, AQHOMED_DEFAULT_IPC_PORT);
if (tcpAddress && *tcpAddress && tcpPort) {
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, AQHOME_ENDPOINTGROUP_IPC);
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptIpcFn, aqh);
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
aqh->ipcdEndpoint=ep;
}
}
void _setupBroker(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
{
const char *brokerAddress;
int brokerPort;
const char *brokerClientId;
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "brokerAddress", 0, NULL);
if (!(brokerAddress && *brokerAddress))
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, "127.0.0.1");
brokerPort=GWEN_DB_GetIntValue(dbArgs, "brokerPort", 0, -1);
if (brokerPort<0)
brokerPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOMED_DEFAULT_BROKER_PORT);
brokerClientId=GWEN_DB_GetCharValue(dbArgs, "brokerClientId", 0, AQHOMED_DEFAULT_BROKER_CLIENTID);
if (brokerAddress && *brokerAddress && brokerPort) {
GWEN_MSG_ENDPOINT *ep;
GWEN_MSG_ENDPOINT *ipcBaseEndpoint;
int rv;
ep=AQH_ClientIpcEndpoint_new("brokerIpcClient", 0);
ipcBaseEndpoint=AQH_IpcEndpoint_CreateIpcTcpClient(brokerAddress, brokerPort, "brokerPhysEndpoint", 0);
AQH_IpcEndpoint_SetServiceName(ipcBaseEndpoint, brokerClientId);
GWEN_MsgEndpoint_Tree2_AddChild(ep, ipcBaseEndpoint);
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
aqh->brokerEndpoint=ep;
rv=GWEN_MultilayerEndpoint_StartConnect(ep);
if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) {
DBG_ERROR(NULL, "Error connecting to broker server %s:%d (%d), will retry later", brokerAddress, brokerPort, rv);
}
}
}
GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_UNUSED GWEN_MSG_ENDPOINT *ep,
GWEN_SOCKET *sk,
GWEN_UNUSED const GWEN_INETADDRESS *addr,
GWEN_UNUSED void *data)
{
/* AQHOMED *aqh;
*
* aqh=(AQHOMED*) data;
*/
DBG_INFO(NULL, "Incoming IPC connection");
return AQH_IpcEndpoint_CreateIpcTcpServiceForSocket(sk, NULL, AQHOME_ENDPOINTGROUP_IPC);
}
void _setupLog(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
{
const char *logFile;
logFile=GWEN_DB_GetCharValue(dbArgs, "logfile", 0, NULL);
if (logFile && *logFile)
AqHomed_SetLogFile(aqh, logFile);
}
void _setupDb(AQHOMED *aqh, GWEN_DB_NODE *dbArgs)
{
const char *s;
s=GWEN_DB_GetCharValue(dbArgs, "dbfile", 0, NULL);
if (s && *s) {
GWEN_DB_NODE *dbNodeDb;
int rv;
AqHomed_SetDbFile(aqh, s);
dbNodeDb=GWEN_DB_Group_new("dbNodes");
rv=GWEN_DB_ReadFile(dbNodeDb, s, GWEN_DB_FLAGS_DEFAULT|GWEN_PATH_FLAGS_CREATE_GROUP);
if (rv==0) {
AQH_NodeDb_fromDb(aqh->nodeDb, dbNodeDb);
}
GWEN_DB_Group_free(dbNodeDb);
}
}
int _loadDeviceList(AQHOMED *aqh)
{
AQHNODE_DEVICE_LIST *deviceList;
deviceList=AqHomeNodes_ReadDataDeviceFiles();
if (deviceList==NULL) {
DBG_ERROR(NULL, "Error reading device list");
return GWEN_ERROR_GENERIC;
}
aqh->deviceDefList=deviceList;
return 0;
}
int _createPidFile(const char *pidFilename)
{
FILE *f;
int pidfd;
if (remove(pidFilename)==0) {
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
}
#ifdef HAVE_SYS_STAT_H
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (pidfd < 0) {
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
f = fdopen(pidfd, "w");
#else /* HAVE_STAT_H */
f=fopen(pidFilename,"w+");
#endif /* HAVE_STAT_H */
/* write pid */
#ifdef HAVE_GETPID
fprintf(f,"%d\n",getpid());
#else
fprintf(f,"-1\n");
#endif
if (fclose(f)) {
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
return GWEN_ERROR_IO;
}
return 0;
}
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
{
int rv;
const GWEN_ARGS args[]= {
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"loglevel", /* name */
0, /* minnum */
1, /* maxnum */
"L", /* short option */
"loglevel", /* long option */
I18S("Specify loglevel"), /* short description */
I18S("Specify loglevel") /* long description */
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"cfgdir", /* name */
0, /* minnum */
1, /* maxnum */
"D", /* short option */
"cfgdir", /* long option */
I18S("Specify the configuration folder"),
I18S("Specify the configuration folder")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"charset", /* name */
0, /* minnum */
1, /* maxnum */
0, /* short option */
"charset", /* long option */
I18S("Specify the output character set"), /* short description */
I18S("Specify the output character set") /* long description */
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"device", /* name */
0, /* minnum */
1, /* maxnum */
"d", /* short option */
"device", /* long option */
I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)"),
I18S("Specify the device to communicate with (e.g. /dev/ttyUSB0)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"nodeAddress", /* name */
0, /* minnum */
1, /* maxnum */
"n", /* short option */
"node", /* long option */
I18S("Specify the node address for the AqHome node adaptor (default 240)"),
I18S("Specify the node address for the AqHome node adaptor (default 240)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"logFile", /* name */
0, /* minnum */
1, /* maxnum */
"l", /* short option */
"logfile", /* long option */
I18S("Specify a logfile to log received messages to"),
I18S("Specify a logfile to log received messages to")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"tcpAddress", /* name */
0, /* minnum */
1, /* maxnum */
"t", /* short option */
"tcpaddress", /* long option */
I18S("Specify the TCP address to listen on (disabled if missing)"),
I18S("Specify the TCP address to listen on (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"tcpPort", /* name */
0, /* minnum */
1, /* maxnum */
"P", /* short option */
"tcpport", /* long option */
I18S("Specify the TCP port to listen on (default: 45454)"),
I18S("Specify the TCP port to listen on (default: 45454)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"brokerAddress", /* name */
0, /* minnum */
1, /* maxnum */
"ba", /* short option */
"brokeraddress", /* long option */
I18S("Specify the address of the broker server to connect to (disabled if missing)"),
I18S("Specify the address of the broker server to connect to (disabled if missing)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"brokerPort", /* name */
0, /* minnum */
1, /* maxnum */
"bp", /* short option */
"brokerport", /* long option */
I18S("Specify the port of the broker server (default: 1899)"),
I18S("Specify the port of the broker server (default: 1899)")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"brokerClientId", /* name */
0, /* minnum */
1, /* maxnum */
NULL, /* short option */
"brokerclientid", /* long option */
I18S("Specify client id for the broker server (default: \"nodes\")"),
I18S("Specify client id for the broker server (default: \"nodes\")")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"dbfile", /* name */
0, /* minnum */
1, /* maxnum */
"db", /* short option */
"dbfile", /* long option */
I18S("Specify DB file to read/write node database"),
I18S("Specify DB file to read/write node database")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Char, /* type */
"pidfile", /* name */
0, /* minnum */
1, /* maxnum */
"p", /* short option */
"pidfile", /* long option */
I18S("Specify the PID file"),
I18S("Specify the PID file")
},
{
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
GWEN_ArgsType_Int, /* type */
"timeout", /* name */
0, /* minnum */
1, /* maxnum */
"T", /* short option */
"timeout", /* long option */
I18S("Specify timeout in second (default: no timeout)"),
I18S("Specify timeout in second (default: no timeout)")
},
{
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
GWEN_ArgsType_Int, /* type */
"help", /* name */
0, /* minnum */
0, /* maxnum */
"h", /* short option */
"help",
I18S("Show this help screen."),
I18S("Show this help screen.")
}
};
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
if (rv==GWEN_ARGS_RESULT_ERROR) {
fprintf(stderr, "ERROR: Could not parse arguments main\n");
return GWEN_ERROR_INVALID;
}
else if (rv==GWEN_ARGS_RESULT_HELP) {
GWEN_BUFFER *ubuf;
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
GWEN_Buffer_AppendArgs(ubuf,
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
AQHOME_VERSION_STRING,
argv[0]);
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
fprintf(stderr, "ERROR: Could not create help string\n");
return 1;
}
GWEN_Buffer_AppendString(ubuf, "\n");
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
GWEN_Buffer_free(ubuf);
return GWEN_ERROR_CLOSE;
}
return 0;
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_INIT_H
#define AQHOMED_INIT_H
#include "./aqhomed.h"
int AqHomed_Init(AQHOMED *aqh, int argc, char **argv);
#endif

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_LOOP_IPC_H
#define AQHOMED_LOOP_IPC_H
#include "./aqhomed.h"
void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg);
#endif

View File

@@ -1,91 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop.h"
#include "./loop_tty.h"
#include "./loop_ipc.h"
#include "./loop_broker.h"
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "./db.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/msg/msg_value2.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
#include "aqhome/ipc/nodes/msg_ipc_value.h"
#include "aqhome/ipc/requests.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_Loop(AQHOMED *aqh, int timeoutInMsecs)
{
if (aqh) {
GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs);
AqHomed_ReadAndHandleTtyMessages(aqh);
AqHomed_ReadAndHandleIpcMessages(aqh);
AqHomed_ReadAndHandleBrokerMessages(aqh);
AQH_Requests_CheckTimeouts(aqh->requestTree);
AQH_Requests_Cleanup(aqh->requestTree);
#if 0
DBG_ERROR(NULL, "Messages in TTY queue: %d in, %d out",
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetReceivedMessageList(aqh->ttyEndpoint)),
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetSendMessageList(aqh->ttyEndpoint)));
DBG_ERROR(NULL, "Messages in IPC queue: %d in, %d out",
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetReceivedMessageList(aqh->ipcdEndpoint)),
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetSendMessageList(aqh->ipcdEndpoint)));
DBG_ERROR(NULL, "Messages in Broker queue: %d in, %d out",
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetReceivedMessageList(aqh->brokerEndpoint)),
GWEN_Msg_List_GetCount(GWEN_MsgEndpoint_GetSendMessageList(aqh->brokerEndpoint)));
#endif
if (AQH_NodeDb_IsModified(aqh->nodeDb))
AqHomed_WriteNodeDb(aqh);
}
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_LOOP_H
#define AQHOMED_LOOP_H
#include "./aqhomed.h"
void AqHomed_Loop(AQHOMED *aqh, int timeoutInMsecs);
#endif

View File

@@ -1,101 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_broker.h"
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "./db.h"
#include "./r_setdata.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/msg/msg_value2.h"
#include "aqhome/msg/msg_ping.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/requests.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_ReadAndHandleBrokerMessages(AQHOMED *aqh)
{
if (aqh->brokerEndpoint) {
GWEN_MSG_ENDPOINT *epTcp;
GWEN_MSG *msg;
epTcp=aqh->brokerEndpoint;
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) {
uint16_t code;
code=GWEN_IpcMsg_GetCode(msg);
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet %d (%x)", (int) code, code);
if (AQH_Requests_HandleIpcMsg(aqh->requestTree, epTcp, msg)!=GWEN_MSG_REQUEST_RESULT_HANDLED)
_handleIpcMsg(aqh, epTcp, msg);
GWEN_Msg_free(msg);
}
}
}
void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
{
uint16_t code;
/* exec IPC message */
code=GWEN_IpcMsg_GetCode(msg);
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet");
switch(code) {
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeNodes_HandleSetData(aqh, ep, msg); break;
default: break;
}
}

View File

@@ -1,197 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_ipc.h"
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "./db.h"
#include "./r_setdata.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/msg/msg_value2.h"
#include "aqhome/msg/msg_value3.h"
#include "aqhome/msg/msg_ping.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/nodes/ipc_nodes.h"
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
#include "aqhome/ipc/nodes/msg_ipc_value.h"
#include "aqhome/ipc/nodes/msg_ipc_ping.h"
#include "aqhome/ipc/nodes/msg_ipc_setaccmsggrps.h"
#include "aqhome/ipc/nodes/msg_ipc_getdevices_rsp.h"
#include "aqhome/ipc/data/ipc_data.h"
#include "aqhome/ipc/data/msg_data_set.h"
#include "aqhome/ipc/msg_ipc_result.h"
#include "aqhome/ipc/requests.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
#include <stdio.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _handleIpcEndpoint(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep);
static void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
void _handleIpcMsgPing(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
void _handleIpcMsgSetAccMsgGrps(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
void _handleIpcMsgForward(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
void _handleIpcMsgGetDevicesReq(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_ReadAndHandleIpcMessages(AQHOMED *aqh)
{
if (aqh->ipcdEndpoint) {
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
while(ep) {
_handleIpcEndpoint(aqh, ep);
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
}
}
}
void _handleIpcEndpoint(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep)
{
GWEN_MSG *msg;
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) {
if (AQH_Requests_HandleIpcMsg(aqh->requestTree, ep, msg)!=GWEN_MSG_REQUEST_RESULT_HANDLED)
_handleIpcMsg(aqh, ep, msg);
GWEN_Msg_free(msg);
}
}
void _handleIpcMsg(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
{
uint16_t code;
/* exec IPC message */
code=GWEN_IpcMsg_GetCode(msg);
DBG_INFO(AQH_LOGDOMAIN, "Received IPC packet (%d, %04x)", code, code);
switch(code) {
case AQH_MSGTYPE_IPC_NODES_PING: _handleIpcMsgPing(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_NODES_SETACCMSGGRPS: _handleIpcMsgSetAccMsgGrps(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_NODES_FORWARD: _handleIpcMsgForward(aqh, ep, msg); break;
case AQH_MSGTYPE_IPC_NODES_GETDEVICES_REQ: _handleIpcMsgGetDevicesReq(aqh, ep, msg); break;
// case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeNodes_HandleNodeSetData(aqh, ep, msg); break;
default: break;
}
}
void _handleIpcMsgPing(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
if (aqh->ttyEndpoint && GWEN_MsgEndpoint_GetState(aqh->ttyEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
GWEN_MSG *msgOut;
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC PING message");
msgOut=AQH_PingMsg_new(aqh->nodeAddress, AQH_PingIpcMsg_GetDestAddr(msg), AQH_MSG_TYPE_PING);
GWEN_MsgEndpoint_AddSendMessage(aqh->ttyEndpoint, msgOut);
}
}
void _handleIpcMsgSetAccMsgGrps(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
uint32_t groups;
DBG_INFO(AQH_LOGDOMAIN, "Received IPC SET_ACCEPTED_MSG_GROUPS message");
groups=AQH_SetAcceptedMsgGroupsIpcMsg_GetMsgGroups(msg);
AQH_IpcEndpoint_SetAcceptedMsgGroups(ep, groups);
// TODO: send response?
}
void _handleIpcMsgForward(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
if (aqh->ttyEndpoint && GWEN_MsgEndpoint_GetState(aqh->ttyEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
GWEN_MSG *msgOut;
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC FORWARD message");
msgOut=AQH_ForwardIpcMsg_GetCopyOfNodeMsg(msg);
if (msgOut)
GWEN_MsgEndpoint_AddSendMessage(aqh->ttyEndpoint, msgOut);
}
}
void _handleIpcMsgGetDevicesReq(AQHOMED *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
{
AQH_NODE_INFO_LIST *nodeInfoList;
DBG_INFO(AQH_LOGDOMAIN, "Received IPC GetDevicesRequest message");
nodeInfoList=AQH_NodeDb_GetAllNodeInfos(aqh->nodeDb);
if (nodeInfoList && AQH_NodeInfo_List_GetCount(nodeInfoList)) {
const AQH_NODE_INFO *ni;
ni=AQH_NodeInfo_List_First(nodeInfoList);
while(ni) {
const AQH_NODE_INFO *niNext;
GWEN_MSG *msgOut;
niNext=AQH_NodeInfo_List_Next(ni);
DBG_INFO(AQH_LOGDOMAIN, "Sending response for node %02x (%08x)", AQH_NodeInfo_GetBusAddress(ni), AQH_NodeInfo_GetUid(ni));
msgOut=AQH_GetDevicesResponseIpcMsg_new(AQH_MSGTYPE_IPC_NODES_GETDEVICES_RSP,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
niNext?0:AQH_MSGIPC_GETDEVICES_RSP_FLAGS_LAST, ni);
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
ni=niNext;
}
}
else {
GWEN_MSG *msgOut;
DBG_INFO(AQH_LOGDOMAIN, "No nodes");
msgOut=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_NODES_RESULT,
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
AQH_MSG_IPC_ERROR_NODATA);
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
}
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_LOOP_IPC_H
#define AQHOMED_LOOP_IPC_H
#include "./aqhomed.h"
void AqHomed_ReadAndHandleIpcMessages(AQHOMED *aqh);
#endif

View File

@@ -1,87 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_tty.h"
#include "./loop_tty_ipc.h"
#include "./loop_tty_broker.h"
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "./db.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/msg/msg_value2.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
#include "aqhome/ipc/nodes/msg_ipc_value.h"
#include "aqhome/ipc/requests.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _handleTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_ReadAndHandleTtyMessages(AQHOMED *aqh)
{
GWEN_MSG *msg;
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(aqh->ttyEndpoint)) ) {
_handleTtyMsg(aqh, msg);
AQH_Requests_HandleTtyMsg(aqh->requestTree, aqh->ttyEndpoint, msg);
GWEN_Msg_free(msg);
}
}
void _handleTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg)
{
if (aqh->logFile)
AqHomed_LogTtyMsg(aqh, msg);
if (aqh->nodeDb)
AqHomed_NodeMsgToDb(aqh, msg);
if (aqh->ipcdEndpoint)
AqHomed_ForwardTtyMsgToIpcClients(aqh, msg);
if (aqh->brokerEndpoint)
AqHomed_ForwardTtyMsgToBroker(aqh, msg);
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_LOOP_TTY_H
#define AQHOMED_LOOP_TTY_H
#include "./aqhomed.h"
void AqHomed_ReadAndHandleTtyMessages(AQHOMED *aqh);
#endif

View File

@@ -1,234 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_tty_broker.h"
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "./db.h"
#include "aqhome/aqhome.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/msg/msg_value2.h"
#include "aqhome/msg/msg_value3.h"
#include "aqhome/msg/msg_sendstats.h"
#include "aqhome/msg/msg_recvstats.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/data/msg_data_multidata.h"
#include "aqhome/ipc/data/ipc_data.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _processValue3Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
static void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
static void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
static void _publishInt(AQHOMED *aqh, uint32_t uid, const char *vPath, int vModality, const char *vUnits, int v);
static void _publishDouble(AQHOMED *aqh, uint32_t uid, const char *vPath, int vType, const char *vUnits, double v);
static void _setDeviceName(AQH_VALUE *value, uint32_t uid);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_ForwardTtyMsgToBroker(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
{
if (GWEN_MsgEndpoint_GetState(aqh->brokerEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
DBG_DEBUG(AQH_LOGDOMAIN, "Processing output message");
switch(AQH_NodeMsg_GetMsgType(nodeMsg)) {
case AQH_MSG_TYPE_VALUE_REPORT:
_processValue3Message(aqh, nodeMsg);
break;
case AQH_MSG_TYPE_COMSENDSTATS:
_processSendStatsMessage(aqh, nodeMsg);
break;
case AQH_MSG_TYPE_COMRECVSTATS:
_processRecvStatsMessage(aqh, nodeMsg);
break;
default:
break;
}
}
}
void _processValue3Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
{
uint32_t uid;
uint8_t valueId;
AQH_NODE_INFO *ni;
double v;
uid=AQH_Value3Msg_GetUid(nodeMsg);
valueId=AQH_Value3Msg_GetValueId(nodeMsg);
v=AQH_Value3Msg_GetValue(nodeMsg);
ni=AQH_NodeDb_GetNodeInfoByUid(aqh->nodeDb, uid);
if (ni) {
const char *devName;
devName=AQH_NodeInfo_GetDeviceId(ni);
if (devName) {
const AQHNODE_DEVICE *devInfo;
devInfo=AqHomed_GetDeviceDefByName(aqh, devName);
if (devInfo) {
const AQHNODE_VALUE *value;
value=AQHNODE_Value_List_GetById(AQHNODE_Device_GetValueList(devInfo), valueId);
if (value) {
const char *vname;
vname=AQHNODE_Value_GetName(value);
if (vname && *vname)
_publishDouble(aqh, uid, vname, AQHNODE_Value_GetModality(value), AQHNODE_Value_GetValueUnits(value), v);
}
}
}
}
}
void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
{
uint16_t packetsOutInt;
packetsOutInt=AQH_SendStatsMsg_GetPacketsOut(nodeMsg);
if (packetsOutInt) {
uint32_t uid;
double packetsOut;
double collisions;
double busy;
double collisionsPercentage=0.0;
double busyPercentage=0.0;
uid=AQH_SendStatsMsg_GetUid(nodeMsg);
packetsOut=/*(double)*/ packetsOutInt;
collisions=/*(double)*/ AQH_SendStatsMsg_GetCollisions(nodeMsg);
busy=/*(double)*/ AQH_SendStatsMsg_GetBusyErrors(nodeMsg);
collisionsPercentage=collisions*100.0/packetsOut;
busyPercentage=busy*100.0/packetsOut;
_publishInt( aqh, uid, "net/packetsOut", 0, NULL, packetsOutInt);
_publishInt( aqh, uid, "net/collisions", 0, NULL, (int) AQH_SendStatsMsg_GetCollisions(nodeMsg));
_publishDouble(aqh, uid, "net/collisionsPercent", 0, "%", collisionsPercentage);
_publishDouble(aqh, uid, "net/busyPercent", 0, "%", busyPercentage);
}
}
void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
{
uint16_t packetsInInt;
packetsInInt=AQH_RecvStatsMsg_GetPacketsIn(nodeMsg);
if (packetsInInt) {
uint32_t uid;
double packetsIn;
double crcErrors;
double ioErrors;
double crcErrorsPercentage=0.0;
double ioErrorsPercentage=0.0;
uid=AQH_SendStatsMsg_GetUid(nodeMsg);
packetsIn=/*(double)*/ packetsInInt;
crcErrors=/*(double)*/AQH_RecvStatsMsg_GetCrcErrors(nodeMsg);
ioErrors=/*(double)*/AQH_RecvStatsMsg_GetIoErrors(nodeMsg);
crcErrorsPercentage=crcErrors*100.0/packetsIn;
ioErrorsPercentage=ioErrors*100.0/packetsIn;
_publishInt( aqh, uid, "net/packetsIn", 0, NULL, packetsInInt);
_publishInt( aqh, uid, "net/crcerrors", 0, NULL, (int) AQH_RecvStatsMsg_GetCrcErrors(nodeMsg));
_publishInt( aqh, uid, "net/ioerrors", 0, NULL, (int) AQH_RecvStatsMsg_GetIoErrors(nodeMsg));
_publishDouble(aqh, uid, "net/crcerrorsPercent", 0, "%", crcErrorsPercentage);
_publishDouble(aqh, uid, "net/ioerrorsPercent", 0, "%", ioErrorsPercentage);
}
}
void _publishInt(AQHOMED *aqh, uint32_t uid, const char *vPath, int vModality, const char *vUnits, int v)
{
_publishDouble(aqh, uid, vPath, vModality, vUnits, /*(double)*/ v);
}
void _publishDouble(AQHOMED *aqh, uint32_t uid, const char *vPath, int vModality, const char *vUnits, double v)
{
GWEN_MSG *pubMsg;
union {double f; uint64_t i;} u;
uint64_t arrayToSend[2];
AQH_VALUE *value;
u.f=v;
arrayToSend[0]=(uint64_t) time(NULL);
arrayToSend[1]=u.i;
value=AQH_Value_new();
_setDeviceName(value, uid);
AQH_Value_SetName(value, vPath);
AQH_Value_SetValueUnits(value, vUnits);
AQH_Value_SetValueType(value, AQH_ValueType_Sensor);
AQH_Value_SetModality(value, vModality);
pubMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
value, arrayToSend, 1);
if (pubMsg) {
DBG_INFO(AQH_LOGDOMAIN, "BROKER PUBLISH %s: %f", AQH_Value_GetName(value), v);
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg);
}
AQH_Value_free(value);
}
void _setDeviceName(AQH_VALUE *value, uint32_t uid)
{
GWEN_BUFFER *buf;
buf=GWEN_Buffer_new(0, 64, 0, 1);
GWEN_Buffer_AppendArgs(buf, "%08x", uid);
AQH_Value_SetDeviceName(value, GWEN_Buffer_GetStart(buf));
GWEN_Buffer_free(buf);
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_LOOP_TTY_BROKER_H
#define AQHOMED_LOOP_TTY_BROKER_H
#include "./aqhomed.h"
void AqHomed_ForwardTtyMsgToBroker(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
#endif

View File

@@ -1,120 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_tty_ipc.h"
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "./db.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/msg/msg_value2.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
#include "aqhome/ipc/nodes/msg_ipc_value.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _forwardValue2MsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg);
static void _forwardAnyMsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg)
{
uint32_t msgGroup;
msgGroup=AQH_NodeMsg_GetMsgGroup(AQH_NodeMsg_GetMsgType(msg));
if (msgGroup) {
GWEN_MSG_ENDPOINT *ep;
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
while(ep) {
if (msgGroup & AQH_IpcEndpoint_GetAcceptedMsgGroups(ep)) {
DBG_INFO(NULL, "Endpoint accepts msg group %d", msgGroup);
switch(AQH_NodeMsg_GetMsgType(msg)) {
case AQH_MSG_TYPE_VALUE2:
_forwardValue2MsgToIpc(ep, msg);
break;
default:
_forwardAnyMsgToIpc(ep, msg);
break;
}
}
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
}
}
else {
DBG_ERROR(NULL, "Message type %d not in any message group, ignoring message", AQH_NodeMsg_GetMsgType(msg));
}
}
void _forwardValue2MsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg)
{
GWEN_MSG *ipcMsg;
ipcMsg=AQH_ValueIpcMsg_new(AQH_MSGTYPE_IPC_NODES_VALUE,
GWEN_MsgEndpoint_GetNextMessageId(ep), 0,
AQH_Value2Msg_GetUid(nodeMsg),
AQH_Value2Msg_GetValueId(nodeMsg),
AQH_Value2Msg_GetValueType(nodeMsg),
AQH_Value2Msg_GetValueNom(nodeMsg),
AQH_Value2Msg_GetValueDenom(nodeMsg));
GWEN_MsgEndpoint_AddSendMessage(ep, ipcMsg);
}
void _forwardAnyMsgToIpc(GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *nodeMsg)
{
GWEN_MSG *ipcMsg;
ipcMsg=AQH_ForwardIpcMsg_new(AQH_MSGTYPE_IPC_NODES_FORWARD,
GWEN_MsgEndpoint_GetNextMessageId(ep), 0,
GWEN_Msg_GetConstBuffer(nodeMsg), GWEN_Msg_GetBytesInBuffer(nodeMsg));
GWEN_MsgEndpoint_AddSendMessage(ep, ipcMsg);
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_LOOP_TTY_IPC_H
#define AQHOMED_LOOP_TTY_IPC_H
#include "./aqhomed.h"
void AqHomed_ForwardTtyMsgToIpcClients(AQHOMED *aqh, const GWEN_MSG *msg);
#endif

View File

@@ -1,215 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./loop_tty_mqtt.h"
#include "./aqhomed_p.h"
#include "./tty_log.h"
#include "./tty_write.h"
#include "./db.h"
#include "aqhome/msg/endpoint_tty.h"
#include "aqhome/msg/msg_node.h"
#include "aqhome/msg/msg_value2.h"
#include "aqhome/msg/msg_sendstats.h"
#include "aqhome/msg/msg_recvstats.h"
#include "aqhome/ipc/endpoint_ipc.h"
#include "aqhome/ipc/nodes/msg_ipc_forward.h"
#include "aqhome/ipc/nodes/msg_ipc_value.h"
#include "aqhome/mqtt/endpoint_mqttc.h"
#include "aqhome/mqtt/msg_mqtt_publish.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/endpoint_tcpd.h>
/* ------------------------------------------------------------------------------------------------
* defines
* ------------------------------------------------------------------------------------------------
*/
#define I18N(msg) msg
#define I18S(msg) msg
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
static void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
static void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg);
static void _publishDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, double v);
static void _publishInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, int v);
static void _publishString(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, const char *v);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
void AqHomed_ForwardTtyMsgToMqttServer(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
{
if (GWEN_MsgEndpoint_GetState(aqh->mqttEndpoint)==GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
DBG_DEBUG(AQH_LOGDOMAIN, "Processing output message");
switch(AQH_NodeMsg_GetMsgType(nodeMsg)) {
case AQH_MSG_TYPE_VALUE2:
_processValue2Message(aqh, nodeMsg);
break;
case AQH_MSG_TYPE_COMSENDSTATS:
_processSendStatsMessage(aqh, nodeMsg);
break;
case AQH_MSG_TYPE_COMRECVSTATS:
_processRecvStatsMessage(aqh, nodeMsg);
break;
default:
break;
}
}
}
void _processValue2Message(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
{
if (AQH_Value2Msg_GetValueType(nodeMsg)==AQH_MSG_VALUE2_TYPE_DOOR)
_publishString(aqh,
AQH_Value2Msg_GetUid(nodeMsg),
AQH_Value2Msg_GetValueId(nodeMsg),
AQH_Value2Msg_GetValueTypeName(nodeMsg),
AQH_Value2Msg_GetValueAsWindowStateString(nodeMsg));
else
_publishDouble(aqh,
AQH_Value2Msg_GetUid(nodeMsg),
AQH_Value2Msg_GetValueId(nodeMsg),
AQH_Value2Msg_GetValueTypeName(nodeMsg),
AQH_Value2Msg_GetValue(nodeMsg));
}
void _processSendStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
{
uint16_t packetsOutInt;
packetsOutInt=AQH_SendStatsMsg_GetPacketsOut(nodeMsg);
if (packetsOutInt) {
double packetsOut;
double collisions;
double busy;
double collisionsPercentage=0.0;
double busyPercentage=0.0;
packetsOut=(double) packetsOutInt;
collisions=(double)AQH_SendStatsMsg_GetCollisions(nodeMsg);
busy=(double)AQH_SendStatsMsg_GetBusyErrors(nodeMsg);
collisionsPercentage=collisions*100.0/packetsOut;
busyPercentage=busy*100.0/packetsOut;
_publishInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/packetsOut", packetsOutInt);
_publishInt(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisions", (int) AQH_SendStatsMsg_GetCollisions(nodeMsg));
_publishDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisionsPercent", collisionsPercentage);
_publishDouble(aqh, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/busyPercent", busyPercentage);
}
}
void _processRecvStatsMessage(AQHOMED *aqh, const GWEN_MSG *nodeMsg)
{
uint16_t packetsInInt;
packetsInInt=AQH_RecvStatsMsg_GetPacketsIn(nodeMsg);
if (packetsInInt) {
double packetsIn;
double crcErrors;
double ioErrors;
double crcErrorsPercentage=0.0;
double ioErrorsPercentage=0.0;
packetsIn=(double) packetsInInt;
crcErrors=(double)AQH_RecvStatsMsg_GetCrcErrors(nodeMsg);
ioErrors=(double)AQH_RecvStatsMsg_GetIoErrors(nodeMsg);
crcErrorsPercentage=crcErrors*100.0/packetsIn;
ioErrorsPercentage=ioErrors*100.0/packetsIn;
_publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/packetsIn", packetsInInt);
_publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrors", (int) AQH_RecvStatsMsg_GetCrcErrors(nodeMsg));
_publishInt(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrors", (int) AQH_RecvStatsMsg_GetIoErrors(nodeMsg));
_publishDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrorsPercent", crcErrorsPercentage);
_publishDouble(aqh, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrorsPercent", ioErrorsPercentage);
}
}
void _publishDouble(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, double v)
{
char numBuf[16];
snprintf(numBuf, sizeof(numBuf)-1, "%f", v);
numBuf[sizeof(numBuf)-1]=0;
_publishString(aqh, uid, valueId, valuePath, numBuf);
}
void _publishInt(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, int v)
{
char numBuf[16];
snprintf(numBuf, sizeof(numBuf)-1, "%d", v);
numBuf[sizeof(numBuf)-1]=0;
_publishString(aqh, uid, valueId, valuePath, numBuf);
}
void _publishString(AQHOMED *aqh, uint32_t uid, int valueId, const char *valuePath, const char *v)
{
GWEN_BUFFER *bufTopic;
GWEN_MSG *pubMsg;
bufTopic=GWEN_Buffer_new(0, 64, 0, 1);
if (valueId>0)
GWEN_Buffer_AppendArgs(bufTopic, "%s/%08x/%d/%s",
aqh->mqttTopicPrefix,
uid,
valueId,
valuePath);
else
GWEN_Buffer_AppendArgs(bufTopic, "%s/%08x/%s",
aqh->mqttTopicPrefix,
uid,
valuePath);
pubMsg=AQH_PublishMqttMsg_new(0, 0, GWEN_Buffer_GetStart(bufTopic), (const uint8_t*) v, strlen(v));
if (pubMsg) {
DBG_INFO(AQH_LOGDOMAIN, "MQTT PUBLISH %s: %s", GWEN_Buffer_GetStart(bufTopic), v);
GWEN_MsgEndpoint_AddSendMessage(aqh->mqttEndpoint, pubMsg);
}
GWEN_Buffer_free(bufTopic);
}

View File

@@ -1,23 +0,0 @@
/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifndef AQHOMED_LOOP_TTY_MQTT_H
#define AQHOMED_LOOP_TTY_MQTT_H
#include "./aqhomed.h"
void AqHomed_ForwardTtyMsgToMqttServer(AQHOMED *aqh, const GWEN_MSG *msg);
#endif

View File

@@ -13,10 +13,7 @@
#include <aqhome/api.h>
#include <aqhome/aqhome.h>
#include "./aqhomed.h"
#include "./init.h"
#include "./fini.h"
#include "./loop.h"
#include "./server.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/logger.h>
@@ -37,6 +34,9 @@
#define I18N(msg) msg
#define I18S(msg) msg
#define CONNCLEAN_INTERVAL_IN_SECS 2
#define CONNCHECK_INTERVAL_IN_SECS 10
/* ------------------------------------------------------------------------------------------------
@@ -44,12 +44,13 @@
* ------------------------------------------------------------------------------------------------
*/
static void _runService(AQHOMED *aqh);
static void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop);
#ifdef HAVE_SIGNAL_H
static int _setSignalHandlers(void);
static int _setupSigAction(struct sigaction *sa, int sig);
static void _signalHandler(int s);
#endif
static int _diffInSeconds(time_t t1, time_t t0);
@@ -59,7 +60,7 @@ static void _signalHandler(int s);
*/
#ifdef HAVE_SIGNAL_H
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT, saPIPE;
#endif
static int stopService=0;
@@ -74,7 +75,8 @@ static int stopService=0;
int main(int argc, char **argv)
{
int rv;
AQHOMED *aqh;
AQH_EVENT_LOOP *eventLoop;
AQH_OBJECT *aqh;
GWEN_GUI *gui;
rv=GWEN_Init();
@@ -83,7 +85,7 @@ int main(int argc, char **argv)
return 2;
}
GWEN_Logger_Open(0, "aqhomed", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
GWEN_Logger_Open(0, "aqhome-nodes", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
rv=_setSignalHandlers();
@@ -101,17 +103,20 @@ int main(int argc, char **argv)
gui=GWEN_Gui_CGui_new();
GWEN_Gui_SetGui(gui);
aqh=AqHomed_new();
rv=AqHomed_Init(aqh, argc, argv);
eventLoop=AQH_EventLoop_new();
aqh=AQH_NodeServer_new(eventLoop);
rv=AQH_NodeServer_Init(aqh, argc, argv);
if (rv<0) {
if (rv==GWEN_ERROR_CLOSE)
return 1;
DBG_INFO(NULL, "here (%d)", rv);
return 2;
}
_runService(aqh);
_runService(aqh, eventLoop);
AqHomed_Fini(aqh);
AqHomed_free(aqh);
//AQH_NodeServer_Fini(aqh);
AQH_Object_free(aqh);
GWEN_Gui_SetGui(NULL);
GWEN_Gui_free(gui);
@@ -121,24 +126,44 @@ int main(int argc, char **argv)
void _runService(AQHOMED *aqh)
void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
{
time_t timeStart;
int timeout;
time_t timeLastConnectionCleanup;
time_t timeLastConnCheck;
timeout=AqHomed_GetTimeout(aqh);
timeout=AQH_NodeServer_GetTimeout(aqh);
timeStart=time(NULL);
timeLastConnectionCleanup=time(NULL);
timeLastConnCheck=time(NULL);
while(!stopService) {
AqHomed_Loop(aqh, 2000);
if (timeout) {
time_t now;
time_t now;
now=time(NULL);
if (timeout && ((int)difftime(now, timeStart))>timeout) {
DBG_INFO(NULL, "Timeout");
break;
}
AQH_EventLoop_Run(eventLoop, 2000);
AQH_NodeServer_HandleTtyMsgs(aqh);
AQH_NodeServer_HandleClientMsgs(aqh);
AQH_NodeServer_HandleBrokerMsgs(aqh);
now=time(NULL);
if (_diffInSeconds(now, timeLastConnectionCleanup)>CONNCLEAN_INTERVAL_IN_SECS) {
DBG_ERROR(NULL, "Cleanup connections");
AQH_NodeServer_CleanupClients(aqh);
timeLastConnectionCleanup=now;
}
if (_diffInSeconds(now, timeLastConnCheck)>CONNCHECK_INTERVAL_IN_SECS) {
DBG_ERROR(NULL, "Check connections");
AQH_NodeServer_CheckBrokerConnection(aqh);
AQH_NodeServer_CheckTtyConnection(aqh);
timeLastConnCheck=now;
}
if (timeout && (_diffInSeconds(now, timeStart)>timeout)) {
DBG_INFO(NULL, "Timeout");
break;
}
} /* while */
}
@@ -162,6 +187,10 @@ int _setSignalHandlers(void)
if (rv)
return rv;
rv=_setupSigAction(&saPIPE, SIGPIPE);
if (rv)
return rv;
# ifdef SIGTSTP
rv=_setupSigAction(&saTSTP, SIGTSTP);
if (rv)
@@ -203,6 +232,9 @@ void _signalHandler(int s)
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
stopService=1;
break;
case SIGPIPE:
DBG_WARN(0, "Received PIPE signal");
break;
default:
DBG_WARN(0, "Unknown signal %d",s);
break;
@@ -210,3 +242,10 @@ void _signalHandler(int s)
}
int _diffInSeconds(time_t t1, time_t t0)
{
return t1-t0;
}

View File

@@ -0,0 +1,82 @@
/****************************************************************************
* 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 "./r_connect.h"
#include "./server_p.h"
#include "aqhome/ipc2/endpoint.h"
#include "aqhome/msg/ipc/m_ipc.h"
#include "aqhome/msg/ipc/nodes/m_ipcn.h"
#include "aqhome/msg/ipc/m_ipc_connect.h"
#include "aqhome/msg/ipc/m_ipc_result.h"
#include "aqhome/msg/ipc/m_ipc_tag16.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_NodeServer_HandleConnect(GWEN_UNUSED AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
{
if (tagList) {
AQH_MESSAGE *outMsg;
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
char *clientId=NULL;
char *userId=NULL;
char *passw=NULL;
uint32_t flags;
clientId=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_CLIENTID, NULL);
userId=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_USERID, NULL);
flags=AQH_Tag16_GetTagDataAsUint32(tagList, AQH_MSG_CONNECT_TAGS_FLAGS, 0);
passw=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_PASSWORD, NULL);
if (clientId)
AQH_Endpoint_SetServiceName(ep, clientId);
if (userId)
AQH_Endpoint_SetUserName(ep, userId);
if (flags & AQH_MSG_CONNECT_FLAGS_WANTUPDATES)
AQH_Endpoint_AddFlags(ep, AQH_ENDPOINT_FLAGS_WANTUPDATES);
/* TODO: add user management, for now we allow all */
AQH_Endpoint_SetPermissions(ep,
AQH_ENDPOINT_PERMS_LISTVALUES |
AQH_ENDPOINT_PERMS_READVALUE |
AQH_ENDPOINT_PERMS_ADDVALUE |
AQH_ENDPOINT_PERMS_LISTDATA |
AQH_ENDPOINT_PERMS_READDATA |
AQH_ENDPOINT_PERMS_ADDDATA |
AQH_ENDPOINT_PERMS_LISTDEVICES |
AQH_ENDPOINT_PERMS_READDEVICE |
AQH_ENDPOINT_PERMS_ADDDEVICE |
AQH_ENDPOINT_PERMS_MODDEVICE);
free(passw);
free(userId);
free(clientId);
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_NODES_ID,
AQH_IPC_PROTOCOL_NODES_VERSION,
AQH_MSGTYPE_IPC_NODES_RESULT,
AQH_Endpoint_GetNextMessageId(ep),
AQH_IpcMessage_GetMsgId(msg),
resultCode, NULL);
AQH_Endpoint_AddMsgOut(ep, outMsg);
}
}

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