/**************************************************************************** * 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 "aqhome/msg/endpoint_write_p.h" #include "aqhome/msg/endpoint_node.h" #include "aqhome/msg/msg_value2.h" #include "aqhome/msg/msg_sendstats.h" #include "aqhome/msg/msg_recvstats.h" #include "aqhome/msg/msg_memstats.h" #include "aqhome/msg/msg_sysstats.h" #include #include #include #include #include #include #include #include #define AQH_MSG_ENDPOINT_WRITE_NAME "write" GWEN_INHERIT(GWEN_MSG_ENDPOINT, AQH_MSG_ENDPOINT_WRITE) static void GWENHYWFAR_CB _freeData(void *bp, void *p); static void _processOutMessage(GWEN_MSG_ENDPOINT *ep, GWEN_MSG *nodeMsg); static void _processValue2Message(GWEN_MSG_ENDPOINT *ep, GWEN_MSG *nodeMsg); static void _processSendStatsMessage(GWEN_MSG_ENDPOINT *ep, GWEN_MSG *nodeMsg); static void _processRecvStatsMessage(GWEN_MSG_ENDPOINT *ep, GWEN_MSG *nodeMsg); static const char *_valueTypeToString(int t); static void _writeDouble(GWEN_MSG_ENDPOINT *ep, uint32_t uid, int valueId, const char *valuePath, double v); static void _writeInt(GWEN_MSG_ENDPOINT *ep, uint32_t uid, int valueId, const char *valuePath, int v); static void _writeString(GWEN_MSG_ENDPOINT *ep, uint32_t uid, int valueId, const char *valuePath, const char *v); static void _writeToFile(const char *filename, const char *txt); GWEN_MSG_ENDPOINT *AQH_WriteEndpoint_new(const char *folder, int groupId) { GWEN_MSG_ENDPOINT *ep; AQH_MSG_ENDPOINT_WRITE *xep; ep=AQH_NodeEndpoint_new(AQH_MSG_ENDPOINT_WRITE_NAME, groupId); GWEN_NEW_OBJECT(AQH_MSG_ENDPOINT_WRITE, xep); xep->folder=strdup(folder); GWEN_INHERIT_SETDATA(GWEN_MSG_ENDPOINT, AQH_MSG_ENDPOINT_WRITE, ep, xep, _freeData); AQH_NodeEndpoint_SetAcceptedMsgGroups(ep, AQH_MSG_TYPEGROUP_INFO | AQH_MSG_TYPEGROUP_VALUES); GWEN_MsgEndpoint_AddFlags(ep, GWEN_MSG_ENDPOINT_FLAGS_NOIO); GWEN_MsgEndpoint_SetProcessOutMsgFn(ep, _processOutMessage); return ep; } void _freeData(void *bp, void *p) { AQH_MSG_ENDPOINT_WRITE *xep; xep=(AQH_MSG_ENDPOINT_WRITE*) p; free(xep->folder); GWEN_FREE_OBJECT(xep); } void _processOutMessage(GWEN_MSG_ENDPOINT *ep, GWEN_MSG *nodeMsg) { DBG_DEBUG(AQH_LOGDOMAIN, "Processing output message"); switch(AQH_NodeMsg_GetMsgType(nodeMsg)) { case AQH_MSG_TYPE_VALUE2: _processValue2Message(ep, nodeMsg); break; case AQH_MSG_TYPE_COMSENDSTATS: _processSendStatsMessage(ep, nodeMsg); break; case AQH_MSG_TYPE_COMRECVSTATS: _processRecvStatsMessage(ep, nodeMsg); break; default: break; } GWEN_Msg_free(nodeMsg); } void _processValue2Message(GWEN_MSG_ENDPOINT *ep, GWEN_MSG *nodeMsg) { _writeDouble(ep, AQH_Value2Msg_GetUid(nodeMsg), AQH_Value2Msg_GetValueId(nodeMsg), _valueTypeToString(AQH_Value2Msg_GetValueId(nodeMsg)), AQH_Value2Msg_GetValue(nodeMsg)); } void _processSendStatsMessage(GWEN_MSG_ENDPOINT *ep, GWEN_MSG *nodeMsg) { uint16_t packetsOutInt; packetsOutInt=AQH_SendStatsMsg_GetPacketsOut(nodeMsg); if (packetsOutInt) { double packetsOut; double collisions; double busy; double collisionsPercentage=0.0; double busyPercentage=0.0; packetsOut=(double) packetsOutInt; collisions=(double)AQH_SendStatsMsg_GetCollisions(nodeMsg); busy=(double)AQH_SendStatsMsg_GetBusyErrors(nodeMsg); collisionsPercentage=collisions*100.0/packetsOut; busyPercentage=busy*100.0/packetsOut; _writeInt(ep, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/packetsOut", packetsOutInt); _writeInt(ep, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisions", (int) AQH_SendStatsMsg_GetCollisions(nodeMsg)); _writeDouble(ep, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/collisionsPercent", collisionsPercentage); _writeDouble(ep, AQH_SendStatsMsg_GetUid(nodeMsg), 0, "net/busyPercent", busyPercentage); } } void _processRecvStatsMessage(GWEN_MSG_ENDPOINT *ep, GWEN_MSG *nodeMsg) { uint16_t packetsInInt; packetsInInt=AQH_RecvStatsMsg_GetPacketsIn(nodeMsg); if (packetsInInt) { double packetsIn; double crcErrors; double ioErrors; double crcErrorsPercentage=0.0; double ioErrorsPercentage=0.0; packetsIn=(double) packetsInInt; crcErrors=(double)AQH_RecvStatsMsg_GetCrcErrors(nodeMsg); ioErrors=(double)AQH_RecvStatsMsg_GetIoErrors(nodeMsg); crcErrorsPercentage=crcErrors*100.0/packetsIn; ioErrorsPercentage=ioErrors*100.0/packetsIn; _writeInt(ep, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/packetsIn", packetsInInt); _writeInt(ep, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrors", (int) AQH_RecvStatsMsg_GetCrcErrors(nodeMsg)); _writeInt(ep, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrors", (int) AQH_RecvStatsMsg_GetIoErrors(nodeMsg)); _writeDouble(ep, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/crcerrorsPercent", crcErrorsPercentage); _writeDouble(ep, AQH_RecvStatsMsg_GetUid(nodeMsg), 0, "net/ioerrorsPercent", ioErrorsPercentage); } } const char *_valueTypeToString(int t) { switch(t) { case AQH_MSG_VALUE2_TYPE_TEMP: return "temperature"; case AQH_MSG_VALUE2_TYPE_HUMIDITY: return "humidity"; default: return "unknown"; } } void _writeDouble(GWEN_MSG_ENDPOINT *ep, uint32_t uid, int valueId, const char *valuePath, double v) { char numBuf[16]; snprintf(numBuf, sizeof(numBuf)-1, "%f", v); numBuf[sizeof(numBuf)-1]=0; _writeString(ep, uid, valueId, valuePath, numBuf); } void _writeInt(GWEN_MSG_ENDPOINT *ep, uint32_t uid, int valueId, const char *valuePath, int v) { char numBuf[16]; snprintf(numBuf, sizeof(numBuf)-1, "%d", v); numBuf[sizeof(numBuf)-1]=0; _writeString(ep, uid, valueId, valuePath, numBuf); } void _writeString(GWEN_MSG_ENDPOINT *ep, uint32_t uid, int valueId, const char *valuePath, const char *v) { AQH_MSG_ENDPOINT_WRITE *xep; GWEN_BUFFER *bufFilename; xep=GWEN_INHERIT_GETDATA(GWEN_MSG_ENDPOINT, AQH_MSG_ENDPOINT_WRITE, ep); bufFilename=GWEN_Buffer_new(0, 64, 0, 1); if (valueId>0) GWEN_Buffer_AppendArgs(bufFilename, "%s/%08x/%d/%s", xep->folder, uid, valueId, valuePath); else GWEN_Buffer_AppendArgs(bufFilename, "%s/%08x/%s", xep->folder, uid, valuePath); _writeToFile(GWEN_Buffer_GetStart(bufFilename), v); GWEN_Buffer_free(bufFilename); } 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); } }