We will now have a broker (aqhome-data) which stores data and distributes value change messages among connected clients. aqhomed will connect to that broker and send its values there. aqhome-mqtt will also connect to the broker and send its values there. Other clients can later connect to check for changes and react according to rules.
211 lines
6.1 KiB
C
211 lines
6.1 KiB
C
/****************************************************************************
|
|
* 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 "aqhome/ipc/data/ipc_data.h"
|
|
#include "aqhome/ipc/data/msg_data_datapoints.h"
|
|
#include "aqhome/ipc/endpoint_ipc.h"
|
|
#include "aqhome/ipc/msg_ipc_result.h"
|
|
|
|
#include <gwenhywfar/debug.h>
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* defines
|
|
* ------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* forward declarations
|
|
* ------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
static int _readDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, uint32_t numValues);
|
|
static void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
|
|
const uint64_t *dataPoints, uint32_t numValues);
|
|
static AQH_VALUE *_getOrCreateValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const char *nameForDriver, const char *units);
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------------------------------
|
|
* implementations
|
|
* ------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *recvdMsg)
|
|
{
|
|
GWEN_MSG *outMsg;
|
|
int resultCode=AQH_MSG_IPC_SUCCESS;
|
|
|
|
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_ADDDATA) {
|
|
if (AQH_DataPointsDataIpcMsg_IsValid(recvdMsg)) {
|
|
uint32_t numValues;
|
|
|
|
numValues=AQH_DataPointsDataIpcMsg_GetNumValues(recvdMsg);
|
|
if (numValues) {
|
|
const char *s;
|
|
|
|
s=AQH_DataPointsDataIpcMsg_GetValueName(recvdMsg);
|
|
if (s && *s) {
|
|
AQH_VALUE *v;
|
|
|
|
v=_getOrCreateValue(aqh, ep, s, AQH_DataPointsDataIpcMsg_GetUnits(recvdMsg));
|
|
if (v==NULL) {
|
|
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
|
}
|
|
else {
|
|
const uint64_t *dataPoints;
|
|
|
|
dataPoints=AQH_DataPointsDataIpcMsg_GetDataPoints(recvdMsg);
|
|
if (dataPoints)
|
|
resultCode=_readDataPoints(aqh, v, dataPoints, numValues);
|
|
else {
|
|
DBG_INFO(NULL, "No datapoints");
|
|
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
|
|
}
|
|
if (resultCode==AQH_MSG_IPC_SUCCESS)
|
|
_sendDataChangedMsgToAllClients(aqh, ep, v, dataPoints, numValues);
|
|
}
|
|
}
|
|
else {
|
|
DBG_INFO(NULL, "Value without name ");
|
|
resultCode=AQH_MSG_IPC_ERROR_INVALID;
|
|
}
|
|
}
|
|
else {
|
|
DBG_INFO(NULL, "No datapoints");
|
|
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
|
|
}
|
|
}
|
|
else {
|
|
DBG_INFO(NULL, "Invalid message received");
|
|
resultCode=AQH_MSG_IPC_ERROR_BADDATA;
|
|
}
|
|
}
|
|
else {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to add data");
|
|
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
|
}
|
|
|
|
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode);
|
|
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
|
}
|
|
|
|
|
|
|
|
int _readDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, uint32_t numValues)
|
|
{
|
|
uint32_t i;
|
|
|
|
for(i=0; i<numValues; i++) {
|
|
uint64_t timestamp;
|
|
union {double f; uint64_t i;} u;
|
|
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_INFO(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_INFO(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep));
|
|
msg=AQH_DataPointsDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
|
|
0, /* flags */
|
|
AQH_Value_GetId(v),
|
|
AQH_Value_GetNameForSystem(v),
|
|
AQH_Value_GetValueUnits(v),
|
|
dataPoints, numValues);
|
|
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
|
|
}
|
|
else {
|
|
DBG_INFO(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep));
|
|
}
|
|
}
|
|
else {
|
|
DBG_INFO(AQH_LOGDOMAIN, "Not sending update msg to source of updates");
|
|
}
|
|
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
AQH_VALUE *_getOrCreateValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const char *nameForDriver, const char *units)
|
|
{
|
|
const char *serviceName;
|
|
AQH_VALUE *v;
|
|
GWEN_BUFFER *buf;
|
|
|
|
serviceName=AQH_IpcEndpoint_GetServiceName(ep);
|
|
|
|
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
if (serviceName && *serviceName) {
|
|
GWEN_Buffer_AppendString(buf, serviceName);
|
|
GWEN_Buffer_AppendString(buf, "/");
|
|
}
|
|
else {
|
|
GWEN_Buffer_AppendString(buf, "unknown/");
|
|
}
|
|
GWEN_Buffer_AppendString(buf, nameForDriver);
|
|
|
|
v=AQH_Storage_GetValueByNameForSystem(aqh->storage, GWEN_Buffer_GetStart(buf));
|
|
if (v==NULL) {
|
|
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_ADDVALUE) {
|
|
DBG_INFO(AQH_LOGDOMAIN, "Creating value \"%s\"", GWEN_Buffer_GetStart(buf));
|
|
v=AQH_Value_new();
|
|
AQH_Value_SetDriver(v, serviceName);
|
|
AQH_Value_SetNameForDriver(v, nameForDriver);
|
|
AQH_Value_SetNameForSystem(v, GWEN_Buffer_GetStart(buf));
|
|
AQH_Value_SetValueUnits(v, units);
|
|
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;
|
|
}
|
|
|
|
|
|
|