/**************************************************************************** * 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 #endif #include "./s_setdata.h" #include "./server_p.h" #include "aqhome/data/value.h" #include "aqhome/msg/ipc/data/m_ipcd_setdata.h" #include "aqhome/msg/mqtt/m_mqtt_publish.h" #include "aqhome/ipc2/endpoint.h" #include #define DEBUG_DRY_RUN 0 /* don't actually set value if "1" */ /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const char *valueName, double valueData); static void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_TOPIC *topic, const AQHMQTT_VALUE *value, double valueData); static const char *_valueTranslatedForDriver(const AQHMQTT_VALUE *value, double valueData); static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic); /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList) { if (o && msg) { AQH_MQTTLOG_SERVER *xo; xo=AQH_MqttLogServer_GetServerData(o); if (xo) { AQH_VALUE *recvdValue; DBG_ERROR(NULL, "Received SETDATA request"); recvdValue=AQH_IpcdMessageSetData_ReadValue(tagList); if (recvdValue) { const char *valueName; const char *deviceName; valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL; deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL; if (valueName && deviceName) { AQHMQTT_DEVICE *device; device=AQH_MqttLogServer_FindRegisteredDevice(o, deviceName); if (device) { double valueData; DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName); valueData=AQH_IpcdMessageSetData_ReadData(tagList); _sendDataForDevice(xo, device, valueName, valueData); } else { DBG_ERROR(NULL, "Device \"%s\" not found", deviceName); AQH_MqttLogServer_DumpRegisteredDevices(o); } } else { DBG_ERROR(NULL, "Either value name or device name missing in request"); } AQH_Value_free(recvdValue); } else { DBG_ERROR(NULL, "Request does not contain a value object"); } } } } void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const char *valueName, double valueData) { const char *deviceId; deviceId=AQHMQTT_Device_GetId(device); if (deviceId && *deviceId) { AQHMQTT_TOPIC_LIST *topicList; topicList=AQHMQTT_Device_GetTopicList(device); if (topicList) { AQHMQTT_TOPIC *topic; topic=AQHMQTT_Topic_List_First(topicList); while(topic) { if (AQHMQTT_Topic_GetDirection(topic)==AQHMQTT_TopicDir_Out) { AQHMQTT_VALUE_LIST *valueList; AQHMQTT_VALUE *value; valueList=AQHMQTT_Topic_GetValueList(topic); value=valueList?AQHMQTT_Value_List_GetByName(valueList, valueName):NULL; if (value) { /* found value, create publish msg, send */ DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName); _sendValueToMqtt(xo, device, topic, value, valueData); } } /* if out */ topic=AQHMQTT_Topic_List_Next(topic); } /* while topic */ } } else { DBG_ERROR(NULL, "Device has no id"); } } void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_TOPIC *topic, const AQHMQTT_VALUE *value, double valueData) { const char *deviceId; const char *translatedValue; GWEN_BUFFER *buf; #if !DEBUG_DRY_RUN AQH_MESSAGE *msgOut; #endif deviceId=AQHMQTT_Device_GetId(device); buf=_createBufferForTopic(deviceId, topic); translatedValue=_valueTranslatedForDriver(value, valueData); if (translatedValue && *translatedValue) { DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), translatedValue); msgOut=AQH_MqttMessagePublish_new(0, 0, GWEN_Buffer_GetStart(buf), (const uint8_t*)translatedValue, strlen(translatedValue)); } else { GWEN_BUFFER *vbuf; vbuf=GWEN_Buffer_new(0, 64, 0, 1); GWEN_Buffer_AppendArgs(vbuf, "%f", valueData); DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetStart(vbuf)); msgOut=AQH_MqttMessagePublish_new(0, 0, GWEN_Buffer_GetStart(buf), (const uint8_t*)GWEN_Buffer_GetStart(vbuf), GWEN_Buffer_GetUsedBytes(vbuf)); GWEN_Buffer_free(vbuf); } #if !DEBUG_DRY_RUN if (msgOut) AQH_Endpoint_AddMsgOut(xo->mqttEndpoint, msgOut); else { DBG_ERROR(NULL, "Error creating message"); } #endif GWEN_Buffer_free(buf); } const char *_valueTranslatedForDriver(const AQHMQTT_VALUE *value, double valueData) { const AQHMQTT_TRANSLATION_LIST *translationList; translationList=AQHMQTT_Value_GetTranslationList(value); if (translationList) { const AQHMQTT_TRANSLATION *t; int valueAsInt; valueAsInt=(int) valueData; t=AQHMQTT_Translation_List_GetByAqhValue(translationList, valueAsInt); if (t) { const char *s; s=AQHMQTT_Translation_GetDriverValue(t); DBG_ERROR(NULL, "Translated value %d to %s", valueAsInt, s); return s; } else { DBG_ERROR(NULL, "No translation found for %d", valueAsInt); } } else { DBG_ERROR(NULL, "No translation list"); } return NULL; } GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic) { GWEN_BUFFER *buf; const char *s; buf=GWEN_Buffer_new(0, 256, 0, 1); s=AQHMQTT_Topic_GetBeforeId(topic); if (s && *s) GWEN_Buffer_AppendString(buf, s); GWEN_Buffer_AppendString(buf, deviceId); s=AQHMQTT_Topic_GetAfterId(topic); if (s && *s) GWEN_Buffer_AppendString(buf, s); return buf; }