aqhome-data, aqhome-tool: more work on new protocol.
This commit is contained in:
@@ -45,6 +45,12 @@
|
||||
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
|
||||
c_connect.h
|
||||
c_updatedata.h
|
||||
c_getvalues.h
|
||||
@@ -76,6 +82,12 @@
|
||||
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>
|
||||
|
||||
|
||||
71
apps/aqhome-data/s_addvalue.c
Normal file
71
apps/aqhome-data/s_addvalue.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_MESSAGE *outMsg;
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(msg, 0);
|
||||
if (tagList) {
|
||||
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);
|
||||
}
|
||||
GWEN_Tag16_List_free(tagList);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/s_addvalue.h
Normal file
25
apps/aqhome-data/s_addvalue.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleAddValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
54
apps/aqhome-data/s_annvalue.c
Normal file
54
apps/aqhome-data/s_annvalue.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(msg, 0);
|
||||
if (tagList) {
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
recvdValue=AQH_IpcdMessageValues_ReadFirstValue(tagList);
|
||||
if (recvdValue) {
|
||||
AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(o, ep, recvdValue);
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
GWEN_Tag16_List_free(tagList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
25
apps/aqhome-data/s_annvalue.h
Normal file
25
apps/aqhome-data/s_annvalue.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleAnnounceValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
236
apps/aqhome-data/s_getdatapoints.c
Normal file
236
apps/aqhome-data/s_getdatapoints.c
Normal file
@@ -0,0 +1,236 @@
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
{
|
||||
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) {
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(recvdMsg, 0);
|
||||
if (tagList) {
|
||||
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);
|
||||
}
|
||||
GWEN_Tag16_List_free(tagList);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No value");
|
||||
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), ×tamp, &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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/s_getdatapoints.h
Normal file
25
apps/aqhome-data/s_getdatapoints.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
112
apps/aqhome-data/s_moddevice.c
Normal file
112
apps/aqhome-data/s_moddevice.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
|
||||
if (AQH_Endpoint_GetPermissions(ep) & AQH_ENDPOINT_PERMS_MODDEVICE) {
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(recvdMsg, 0);
|
||||
if (tagList) {
|
||||
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_INFO(NULL, "No tag16 list in message");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_BADDATA;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No permissions to read data");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
|
||||
}
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, AQH_IpcMessage_GetMsgId(recvdMsg), resultCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/s_moddevice.h
Normal file
25
apps/aqhome-data/s_moddevice.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleModDevice(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
286
apps/aqhome-data/s_setdata.c
Normal file
286
apps/aqhome-data/s_setdata.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
uint32_t msgId;
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
|
||||
msgId=AQH_IpcMessage_GetMsgId(recvdMsg);
|
||||
DBG_INFO(NULL, "Received IPC SetDataRequest message (msgId=%d)", msgId);
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(recvdMsg, 0);
|
||||
if (tagList) {
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
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);
|
||||
}
|
||||
GWEN_Tag16_List_free(tagList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
25
apps/aqhome-data/s_setdata.h
Normal file
25
apps/aqhome-data/s_setdata.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_MESSAGE *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
175
apps/aqhome-data/s_updatedata.c
Normal file
175
apps/aqhome-data/s_updatedata.c
Normal file
@@ -0,0 +1,175 @@
|
||||
/****************************************************************************
|
||||
* 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)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_MESSAGE *outMsg;
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(msg, 0);
|
||||
if (tagList) {
|
||||
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;
|
||||
}
|
||||
GWEN_Tag16_List_free(tagList);
|
||||
}
|
||||
|
||||
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_DEBUG(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-data/s_updatedata.h
Normal file
25
apps/aqhome-data/s_updatedata.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleUpdateData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15,11 +15,18 @@
|
||||
#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/data/m_ipcd.h>
|
||||
|
||||
#include <gwenhywfar/args.h>
|
||||
@@ -71,6 +78,7 @@ 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, 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);
|
||||
|
||||
@@ -421,22 +429,55 @@ void _handleMsgFromClient(AQH_OBJECT *o, AQH_OBJECT *ep, AQH_MESSAGE *msg)
|
||||
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
|
||||
DBG_ERROR(NULL, "Received IPC packet %d (%x)", (int) code, code);
|
||||
switch(code) {
|
||||
case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: AqHomeDataServer_HandleConnect(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeDataServer_HandleGetValues(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: break;
|
||||
case AQH_MSGTYPE_IPC_DATA_SETDATA: break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ADDVALUE: break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: AqHomeDataServer_HandleGetDevices(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: break;
|
||||
case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: AqHomeDataServer_HandleConnect(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: AqHomeDataServer_HandleUpdateData(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeDataServer_HandleGetValues(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: AqHomeDataServer_HandleGetDataPoints(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeDataServer_HandleSetData(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ADDVALUE: AqHomeDataServer_HandleAddValue(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: AqHomeDataServer_HandleAnnounceValue(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: AqHomeDataServer_HandleGetDevices(o, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: AqHomeDataServer_HandleModDevice(o, ep, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -563,6 +604,98 @@ int AqHomeDataServer_WriteStorageIfChanged(AQH_OBJECT *o)
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#include <aqhome/ipc2/msgrequest.h>
|
||||
|
||||
|
||||
#define AQH_ENDPOINT_FLAGS_WANTUPDATES 0x0001
|
||||
|
||||
#define AQH_ENDPOINT_PERMS_LISTVALUES 0x0001
|
||||
#define AQH_ENDPOINT_PERMS_READVALUE 0x0002
|
||||
#define AQH_ENDPOINT_PERMS_ADDVALUE 0x0004
|
||||
@@ -39,9 +37,10 @@ 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);
|
||||
@@ -50,6 +49,7 @@ 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);
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user