/**************************************************************************** * 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 "./messages.h" #include "aqhome/mqtt/msg_mqtt_publish.h" #include #include #include #include #include static const ITEM *_getItemForTopic(const ITEM_LIST *itemList, const char *topic); void _handlePublishMsg(const char *baseFolder, const ITEM_LIST *itemList, const GWEN_MSG *msg); void _handlePublish(const char *baseFolder, const ITEM_LIST *itemList, const char *topic, const char *value); void _handleRawMsgForItem(const char *baseFolder, const ITEM *item, const char *value); void _handleJsonMsgForItem(const char *baseFolder, const ITEM *item, const char *value); void _handleJsonItemVar(const char *baseFolder, const ITEM *item, const ITEMVAR *itemVar, GWEN_JSON_ELEM *jeRoot); void _writeValueAccordingToItem(const char *baseFolder, const ITEM *item, const ITEMVAR *itemVar, const char *value); void _writeToFile(const char *filename, const char *txt); ITEM_LIST *AqHomeMqttLog_ReadItems(GWEN_DB_NODE *dbArgs) { const char *itemFile; itemFile=GWEN_DB_GetCharValue(dbArgs, "itemfile", 0, NULL); if (itemFile && *itemFile) { ITEM_LIST *itemList; GWEN_DB_NODE *dbItemList; GWEN_DB_NODE *dbItem; int rv; dbItemList=GWEN_DB_Group_new("items"); rv=GWEN_DB_ReadFile(dbItemList, itemFile, GWEN_DB_FLAGS_DEFAULT | GWEN_PATH_FLAGS_CREATE_GROUP | GWEN_DB_FLAGS_ALLOW_EMPTY_STREAM); if (rv<0) { DBG_ERROR(NULL, "Error reading item file \"%s\" (%d)", itemFile, rv); GWEN_DB_Group_free(dbItemList); return NULL; } itemList=Item_List_new(); dbItem=GWEN_DB_FindFirstGroup(dbItemList, "item"); while(dbItem) { ITEM *item; item=Item_fromDb(dbItem); Item_List_Add(item, itemList); dbItem=GWEN_DB_FindNextGroup(dbItem, "item"); } GWEN_DB_Group_free(dbItemList); if (Item_List_GetCount(itemList)==0) { DBG_INFO(NULL, "No items in file"); Item_List_free(itemList); return NULL; } return itemList; } return NULL; } void AqHomeMqttLog_HandlePublishMsg(const char *baseFolder, const ITEM_LIST *itemList, const GWEN_MSG *msg) { char *topic; char *value; topic=AQH_PublishMqttMsg_ExtractTopic(msg); value=AQH_PublishMqttMsg_ExtractValue(msg); if (topic && value) _handlePublish(baseFolder, itemList, topic, value); else { DBG_ERROR(NULL, "Either topic or value missing in PUBLISH msg"); } free(value); free(topic); } void _handlePublish(const char *baseFolder, const ITEM_LIST *itemList, const char *topic, const char *value) { const ITEM *item; item=_getItemForTopic(itemList, topic); if (item) { const char *t; DBG_INFO(AQH_LOGDOMAIN, "HANDLING topic \"%s\"", topic); t=Item_GetDataType(item); if (t && strcasecmp(t, "json")==0) _handleJsonMsgForItem(baseFolder, item, value); else _handleRawMsgForItem(baseFolder, item, value); } else { DBG_INFO(AQH_LOGDOMAIN, "ignoring topic \"%s\"", topic); } } void _handleJsonMsgForItem(const char *baseFolder, const ITEM *item, const char *value) { GWEN_JSON_ELEM *jeRoot; jeRoot=GWEN_JsonElement_fromString(value); if (jeRoot==NULL) { DBG_INFO(NULL, "Could not parse JSON value: %s", value); } else { const ITEMVAR_LIST *itemVarList; itemVarList=Item_GetVarList(item); if (itemVarList) { ITEMVAR *itemVar; itemVar=ItemVar_List_First(itemVarList); while(itemVar) { _handleJsonItemVar(baseFolder, item, itemVar, jeRoot); itemVar=ItemVar_List_Next(itemVar); } } GWEN_JsonElement_free(jeRoot); } } void _handleJsonItemVar(const char *baseFolder, const ITEM *item, const ITEMVAR *itemVar, GWEN_JSON_ELEM *jeRoot) { const char *path; path=ItemVar_GetPath(itemVar); if (path) { GWEN_JSON_ELEM *je; je=GWEN_JsonElement_GetElementByPath(jeRoot, path, 0); if (je) { const char *s; s=GWEN_JsonElement_GetData(je); if (s && *s) _writeValueAccordingToItem(baseFolder, item, itemVar, s); else { DBG_ERROR(NULL, "Path \"%s\" in JSON data contains no data", path); } } else { DBG_ERROR(NULL, "Path \"%s\" not found in JSON data", path); } } } void _handleRawMsgForItem(const char *baseFolder, const ITEM *item, const char *value) { const ITEMVAR_LIST *itemVarList; itemVarList=Item_GetVarList(item); if (itemVarList) { ITEMVAR *itemVar; itemVar=ItemVar_List_First(itemVarList); while(itemVar) { _writeValueAccordingToItem(baseFolder, item, itemVar, value); itemVar=ItemVar_List_Next(itemVar); } } } void _writeValueAccordingToItem(const char *baseFolder, const ITEM *item, const ITEMVAR *itemVar, const char *value) { const char *id; const char *name; id=Item_GetId(item); name=ItemVar_GetName(itemVar); if (id && *id && name && *name) { GWEN_BUFFER *fnameBuf; fnameBuf=GWEN_Buffer_new(0, 256, 0, 1); GWEN_Buffer_AppendString(fnameBuf, baseFolder); GWEN_Buffer_AppendString(fnameBuf, GWEN_DIR_SEPARATOR_S); GWEN_Buffer_AppendArgs(fnameBuf, "%s_%s", id, name); _writeToFile(GWEN_Buffer_GetStart(fnameBuf), value); GWEN_Buffer_free(fnameBuf); } else { DBG_ERROR(NULL, "Either id or name missing in item list file"); } } void _writeToFile(const char *filename, const char *txt) { if (txt && *txt) { GWEN_BUFFER *tmpNameBuf; int rv; tmpNameBuf=GWEN_Buffer_new(0, 256, 0, 1); GWEN_Buffer_AppendString(tmpNameBuf, filename); GWEN_Buffer_AppendString(tmpNameBuf, ".tmp"); rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(tmpNameBuf), GWEN_PATH_FLAGS_VARIABLE); if (rv<0) { DBG_INFO(AQH_LOGDOMAIN, "Error getting path for %s (%d)", GWEN_Buffer_GetStart(tmpNameBuf), rv); } else { FILE *f; f=fopen(GWEN_Buffer_GetStart(tmpNameBuf), "w"); if (f) { if (1!=fwrite(txt, strlen(txt), 1, f)) { DBG_ERROR(AQH_LOGDOMAIN, "Error writing."); fclose(f); } else { fclose(f); rename(GWEN_Buffer_GetStart(tmpNameBuf), filename); } } } GWEN_Buffer_free(tmpNameBuf); } } const ITEM *_getItemForTopic(const ITEM_LIST *itemList, const char *topic) { const ITEM *item; item=Item_List_First(itemList); while(item) { const char *s; s=Item_GetTopic(item); if (s && GWEN_Text_ComparePattern(topic, s, 0)!=-1) return item; item=Item_List_Next(item); } return NULL; }