Files
Martin Preuss d0c8b3b284 let setData use double values instead of strings.
this allows for storing value set with setData which can then be used in
the cgi module to retrieve the last value set.
2025-10-07 23:50:50 +02:00

249 lines
7.8 KiB
C

/****************************************************************************
* 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 "./xmlwrite.h"
#include "aqhome-mqttlog/types/topic.h"
#include "aqhome-mqttlog/types/value.h"
#include "aqhome-mqttlog/types/translation.h"
#include <aqhome/api.h>
#include <aqhome/aqhome.h>
#include <gwenhywfar/endpoint_multilayer.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/xml.h>
#include <gwenhywfar/directory.h>
#include <gwenhywfar/debug.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _writeDevicesToXml(const AQHMQTT_DEVICE_LIST *deviceList, GWEN_XMLNODE *node);
static void _writeDeviceToXml(const AQHMQTT_DEVICE *device, GWEN_XMLNODE *node);
static void _writeTopicToXml(const AQHMQTT_TOPIC *topic, GWEN_XMLNODE *node);
static void _writeValueToXml(const AQHMQTT_VALUE *value, GWEN_XMLNODE *node);
static void _writeTranslationToXml(const AQHMQTT_TRANSLATION *t, GWEN_XMLNODE *nTranslation);
static void _setXmlPropertyIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value);
static void _setXmlCharValueIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AQH_MqttLogServer_WriteDevicesFile(const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename)
{
int rv;
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_VARIABLE);
if (rv<0) {
DBG_ERROR(NULL, "Could not access file \"%s\"", sFilename);
return GWEN_ERROR_GENERIC;
}
else {
GWEN_XMLNODE *rootNode;
GWEN_BUFFER *nbuf;
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "root");
_writeDevicesToXml(deviceList, rootNode);
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(nbuf, sFilename);
GWEN_Buffer_AppendString(nbuf, ".tmp");
unlink(GWEN_Buffer_GetStart(nbuf));
rv=GWEN_XMLNode_WriteFile(rootNode,
GWEN_Buffer_GetStart(nbuf),
GWEN_XML_FLAGS_SIMPLE | GWEN_XML_FLAGS_HANDLE_HEADERS | GWEN_XML_FLAGS_INDENT);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error writing XML file \"%s\": %d", GWEN_Buffer_GetStart(nbuf), rv);
GWEN_Buffer_free(nbuf);
GWEN_XMLNode_free(rootNode);
return rv;
}
if (rename(GWEN_Buffer_GetStart(nbuf), sFilename)<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error renaming \"%s\"->\"%s\": %d (%s)",
GWEN_Buffer_GetStart(nbuf), sFilename, errno, strerror(errno));
GWEN_Buffer_free(nbuf);
GWEN_XMLNode_free(rootNode);
return rv;
}
GWEN_Buffer_free(nbuf);
GWEN_XMLNode_free(rootNode);
return 0;
}
}
void _writeDevicesToXml(const AQHMQTT_DEVICE_LIST *deviceList, GWEN_XMLNODE *node)
{
if (deviceList && AQHMQTT_Device_List_GetCount(deviceList)) {
GWEN_XMLNODE *nDevices;
const AQHMQTT_DEVICE *device;
nDevices=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "devices");
device=AQHMQTT_Device_List_First(deviceList);
while(device) {
GWEN_XMLNODE *nDevice;
nDevice=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "device");
_writeDeviceToXml(device, nDevice);
GWEN_XMLNode_AddChild(nDevices, nDevice);
device=AQHMQTT_Device_List_Next(device);
}
GWEN_XMLNode_AddChild(node, nDevices);
}
}
void _writeDeviceToXml(const AQHMQTT_DEVICE *device, GWEN_XMLNODE *node)
{
const AQHMQTT_TOPIC_LIST *topicList;
_setXmlPropertyIfNotNull(node, "id", AQHMQTT_Device_GetId(device));
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Device_GetName(device));
_setXmlPropertyIfNotNull(node, "driver", AQHMQTT_Device_GetDriver(device));
topicList=AQHMQTT_Device_GetTopicList(device);
if (topicList && AQHMQTT_Topic_List_GetCount(topicList)) {
GWEN_XMLNODE *nTopics;
const AQHMQTT_TOPIC *topic;
nTopics=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "mqtttopics");
topic=AQHMQTT_Topic_List_First(topicList);
while(topic) {
GWEN_XMLNODE *nTopic;
nTopic=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "mqtttopic");
_writeTopicToXml(topic, nTopic);
GWEN_XMLNode_AddChild(nTopics, nTopic);
topic=AQHMQTT_Topic_List_Next(topic);
}
GWEN_XMLNode_AddChild(node, nTopics);
}
}
void _writeTopicToXml(const AQHMQTT_TOPIC *topic, GWEN_XMLNODE *node)
{
const AQHMQTT_VALUE_LIST *valueList;
GWEN_XMLNode_SetProperty(node, "type", AQHMQTT_TopicType_toString(AQHMQTT_Topic_GetTopicType(topic)));
GWEN_XMLNode_SetProperty(node, "direction", AQHMQTT_TopicDir_toString(AQHMQTT_Topic_GetDirection(topic)));
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Topic_GetName(topic));
_setXmlCharValueIfNotNull(node, "topic", AQHMQTT_Topic_GetTopic(topic));
_setXmlCharValueIfNotNull(node, "mask", AQHMQTT_Topic_GetMask(topic));
_setXmlCharValueIfNotNull(node, "beforeId", AQHMQTT_Topic_GetBeforeId(topic));
_setXmlCharValueIfNotNull(node, "afterId", AQHMQTT_Topic_GetAfterId(topic));
valueList=AQHMQTT_Topic_GetValueList(topic);
if (valueList && AQHMQTT_Value_List_GetCount(valueList)) {
GWEN_XMLNODE *nValues;
const AQHMQTT_VALUE *value;
nValues=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "values");
value=AQHMQTT_Value_List_First(valueList);
while(value) {
GWEN_XMLNODE *nValue;
nValue=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "value");
_writeValueToXml(value, nValue);
GWEN_XMLNode_AddChild(nValues, nValue);
value=AQHMQTT_Value_List_Next(value);
}
GWEN_XMLNode_AddChild(node, nValues);
}
}
void _writeValueToXml(const AQHMQTT_VALUE *value, GWEN_XMLNODE *node)
{
const AQHMQTT_TRANSLATION_LIST *translationList;
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Value_GetName(value));
_setXmlPropertyIfNotNull(node, "units", AQHMQTT_Value_GetValueUnits(value));
_setXmlPropertyIfNotNull(node, "path", AQHMQTT_Value_GetPath(value));
GWEN_XMLNode_SetProperty(node, "type", AQHMQTT_ValueType_toString(AQHMQTT_Value_GetValueType(value)));
translationList=AQHMQTT_Value_GetTranslationList(value);
if (translationList && AQHMQTT_Translation_List_GetCount(translationList)) {
GWEN_XMLNODE *nTranslations;
const AQHMQTT_TRANSLATION *translation;
nTranslations=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "translations");
translation=AQHMQTT_Translation_List_First(translationList);
while(translation) {
GWEN_XMLNODE *nTranslation;
nTranslation=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "transaction");
_writeTranslationToXml(translation, nTranslation);
GWEN_XMLNode_AddChild(nTranslations, nTranslation);
translation=AQHMQTT_Translation_List_Next(translation);
}
GWEN_XMLNode_AddChild(node, nTranslations);
}
}
void _writeTranslationToXml(const AQHMQTT_TRANSLATION *t, GWEN_XMLNODE *nTranslation)
{
GWEN_XMLNode_SetIntProperty(nTranslation, "aqhValue", AQHMQTT_Translation_GetAqhValue(t));
_setXmlPropertyIfNotNull(nTranslation, "driverValue", AQHMQTT_Translation_GetDriverValue(t));
}
void _setXmlPropertyIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value)
{
if (value && *value)
GWEN_XMLNode_SetProperty(n, name, value);
}
void _setXmlCharValueIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value)
{
if (value && *value)
GWEN_XMLNode_SetCharValue(n, name, value);
}