/**************************************************************************** * 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 #endif #include "./xmlread.h" #include "./aqhome_mqtt_p.h" #include "aqhome-mqttlog/types/topic.h" #include "aqhome-mqttlog/types/value.h" #include #include #include #include #include #include /* ------------------------------------------------------------------------------------------------ * defines * ------------------------------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *sl); static AQHMQTT_DEVICE *_readDeviceFile(AQHOME_MQTT *aqh, const char *sFilename); 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); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadRuntimeDataDeviceFiles(AQHOME_MQTT *aqh) { GWEN_STRINGLIST *sl; sl=AQH_GetListOfMatchingRuntimeDataFiles("aqhome/devices", "*.xml"); if (sl) { AQHMQTT_DEVICE_LIST *deviceList; deviceList=_readDeviceFiles(aqh, sl); GWEN_StringList_free(sl); if (deviceList==NULL) { DBG_INFO(NULL, "Error reading sysconf device files"); return NULL; } return deviceList; } else { DBG_INFO(NULL, "No sysconf device files"); return NULL; } } AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDataDeviceFiles(AQHOME_MQTT *aqh) { GWEN_STRINGLIST *sl; sl=AQH_GetListOfMatchingDataFiles("aqhome/devices", "*.xml"); if (sl) { AQHMQTT_DEVICE_LIST *deviceList; deviceList=_readDeviceFiles(aqh, 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 NULL; } } AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *sl) { GWEN_STRINGLISTENTRY *se; AQHMQTT_DEVICE_LIST *deviceList; deviceList=AQHMQTT_Device_List_new(); se=GWEN_StringList_FirstEntry(sl); while(se) { const char *s; s=GWEN_StringListEntry_Data(se); if (s && *s) { AQHMQTT_DEVICE *device; device=_readDeviceFile(aqh, s); if (device) { DBG_ERROR(NULL, "Adding device \"%s\" to list", AQHMQTT_Device_GetName(device)); AQHMQTT_Device_List_Add(device, deviceList); } } se=GWEN_StringListEntry_Next(se); } if (AQHMQTT_Device_List_GetCount(deviceList)<1) { AQHMQTT_Device_List_free(deviceList); return NULL; } return deviceList; } AQHMQTT_DEVICE *_readDeviceFile(AQHOME_MQTT *aqh, const char *sFilename) { GWEN_XMLNODE *rootNode; GWEN_XMLNODE *deviceNode; int rv; rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL); rv=GWEN_XML_ReadFile(rootNode, sFilename, GWEN_XML_FLAGS_DEFAULT); if (rv<0) { DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv); GWEN_XMLNode_free(rootNode); return NULL; } deviceNode=GWEN_XMLNode_FindFirstTag(rootNode, "device", NULL, NULL); if (deviceNode) { const char *driverName; driverName=GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL); if (driverName && *driverName && strcasecmp(driverName, "mqtt")==0) { AQHMQTT_DEVICE *device; device=_readXmlDevice(aqh, deviceNode); GWEN_XMLNode_free(rootNode); if (device==NULL) { DBG_INFO(NULL, "Error reading device from XML file \"%s\" (%d)", sFilename, rv); return NULL; } return device; } else { DBG_INFO(NULL, "Device is not an MQTT device, ignoring"); } } else { DBG_INFO(NULL, "XML file \"%s\" does not contain a element", sFilename); GWEN_XMLNode_free(rootNode); return NULL; } GWEN_XMLNode_free(rootNode); return NULL; } AQHMQTT_DEVICE *_readXmlDevice(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceNode) { AQHMQTT_DEVICE *device; GWEN_XMLNODE *topicsNode; device=AQHMQTT_Device_new(); AQHMQTT_Device_SetId(device, GWEN_XMLNode_GetProperty(deviceNode, "id", NULL)); AQHMQTT_Device_SetName(device, GWEN_XMLNode_GetProperty(deviceNode, "name", NULL)); AQHMQTT_Device_SetDriver(device, GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL)); topicsNode=GWEN_XMLNode_FindFirstTag(deviceNode, "mqtttopics", NULL, NULL); if (topicsNode) { AQHMQTT_TOPIC_LIST *topicList; topicList=_readXmlTopicList(aqh, topicsNode); if (topicList) AQHMQTT_Device_SetTopicList(device, topicList); else { DBG_INFO(NULL, "No mqtt topics read"); AQHMQTT_Device_free(device); return NULL; } } else { DBG_INFO(NULL, "No element"); AQHMQTT_Device_free(device); return NULL; } return device; } AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode) { AQHMQTT_TOPIC_LIST *topicList; GWEN_XMLNODE *topicNode; topicList=AQHMQTT_Topic_List_new(); topicNode=GWEN_XMLNode_FindFirstTag(parentNode, "mqtttopic", NULL, NULL); while(topicNode) { AQHMQTT_TOPIC *topic=_readXmlTopic(aqh, topicNode); if (topic) AQHMQTT_Topic_List_Add(topic, topicList); else { DBG_INFO(NULL, "Error reading element"); AQHMQTT_Topic_List_free(topicList); return NULL; } topicNode=GWEN_XMLNode_FindNextTag(topicNode, "mqtttopic", NULL, NULL); } if (AQHMQTT_Topic_List_GetCount(topicList)<1) { AQHMQTT_Topic_List_free(topicList); return NULL; } return topicList; } AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode) { AQHMQTT_TOPIC *topic; GWEN_XMLNODE *valuesNode; int i; const char *s; topic=AQHMQTT_Topic_new(); s=GWEN_XMLNode_GetProperty(topicNode, "type", NULL); i=AQHMQTT_TopicType_fromString(s); if (i==AQHMQTT_TopicType_Unknown) { DBG_ERROR(NULL, "Invalid topic type \"%s\"", s?s:""); AQHMQTT_Topic_free(topic); return NULL; } AQHMQTT_Topic_SetTopicType(topic, i); s=GWEN_XMLNode_GetProperty(topicNode, "direction", NULL); i=AQHMQTT_TopicDir_fromString(s); if (i==AQHMQTT_TopicDir_Unknown) { DBG_ERROR(NULL, "Invalid topic direction \"%s\"", s?s:""); AQHMQTT_Topic_free(topic); return NULL; } AQHMQTT_Topic_SetDirection(topic, i); AQHMQTT_Topic_SetTopic(topic, GWEN_XMLNode_GetCharValue(topicNode, "topic", NULL)); AQHMQTT_Topic_SetMask(topic, GWEN_XMLNode_GetCharValue(topicNode, "mask", NULL)); AQHMQTT_Topic_SetBeforeId(topic, GWEN_XMLNode_GetCharValue(topicNode, "beforeId", NULL)); AQHMQTT_Topic_SetAfterId(topic, GWEN_XMLNode_GetCharValue(topicNode, "afterId", NULL)); valuesNode=GWEN_XMLNode_FindFirstTag(topicNode, "values", NULL, NULL); if (valuesNode) { AQHMQTT_VALUE_LIST *valueList; valueList=_readXmlValueList(aqh, valuesNode); if (valueList) AQHMQTT_Topic_SetValueList(topic, valueList); else { DBG_INFO(NULL, "No values read"); AQHMQTT_Topic_free(topic); return NULL; } } else { DBG_INFO(NULL, "No element"); AQHMQTT_Topic_free(topic); return NULL; } return topic; } AQHMQTT_VALUE_LIST *_readXmlValueList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode) { AQHMQTT_VALUE_LIST *valueList; GWEN_XMLNODE *valueNode; valueList=AQHMQTT_Value_List_new(); valueNode=GWEN_XMLNode_FindFirstTag(parentNode, "value", NULL, NULL); while(valueNode) { AQHMQTT_VALUE *value=_readXmlValue(aqh, valueNode); if (value) AQHMQTT_Value_List_Add(value, valueList); else { DBG_INFO(NULL, "Error reading element"); AQHMQTT_Value_List_free(valueList); return NULL; } valueNode=GWEN_XMLNode_FindNextTag(valueNode, "value", NULL, NULL); } if (AQHMQTT_Value_List_GetCount(valueList)<1) { AQHMQTT_Value_List_free(valueList); return NULL; } return valueList; } AQHMQTT_VALUE *_readXmlValue(AQHOME_MQTT *aqh, GWEN_XMLNODE *valueNode) { AQHMQTT_VALUE *value; const char *s; int i; value=AQHMQTT_Value_new(); AQHMQTT_Value_SetName(value, GWEN_XMLNode_GetProperty(valueNode, "name", NULL)); AQHMQTT_Value_SetValueUnits(value, GWEN_XMLNode_GetProperty(valueNode, "units", NULL)); AQHMQTT_Value_SetPath(value, GWEN_XMLNode_GetProperty(valueNode, "path", NULL)); s=GWEN_XMLNode_GetProperty(valueNode, "type", NULL); i=AQHMQTT_ValueType_fromString(s); if (i==AQHMQTT_ValueType_Unknown) { DBG_ERROR(NULL, "Invalid value type \"%s\"", s?s:""); AQHMQTT_Value_free(value); return NULL; } AQHMQTT_Value_SetValueType(value, i); /* TODO: read translationList */ return value; }