/**************************************************************************** * 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 #endif #include "./xmlwrite.h" #include "./aqhome_mqtt_p.h" #include "aqhome-mqttlog/types/topic.h" #include "aqhome-mqttlog/types/value.h" #include "aqhome-mqttlog/types/translation.h" #include #include #include #include #include #include #include #include #include #include #include /* ------------------------------------------------------------------------------------------------ * 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 AqHomeMqttLog_WriteDevicesFile(AQHOME_MQTT *aqh, 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) { _setXmlPropertyIfNotNull(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); }