Improved mqttlog daemaon: persistent registered devices.
This commit is contained in:
@@ -55,6 +55,7 @@
|
||||
aqhome_mqtt.h
|
||||
aqhome_mqtt_p.h
|
||||
xmlread.h
|
||||
xmlwrite.h
|
||||
c_setdata.h
|
||||
</headers>
|
||||
|
||||
@@ -68,6 +69,7 @@
|
||||
loop_mqtt.c
|
||||
main.c
|
||||
xmlread.c
|
||||
xmlwrite.c
|
||||
c_setdata.c
|
||||
</sources>
|
||||
|
||||
|
||||
@@ -95,6 +95,23 @@ int AqHomeMqtt_GetTimeout(const AQHOME_MQTT *aqh)
|
||||
|
||||
|
||||
|
||||
const char *AqHomeMqtt_GetDeviceFile(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->deviceFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetDeviceFile(AQHOME_MQTT *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->deviceFile);
|
||||
aqh->deviceFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->availableDeviceList:NULL;
|
||||
@@ -112,16 +129,59 @@ void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetRegisteredDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl)
|
||||
{
|
||||
if (aqh) {
|
||||
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
|
||||
aqh->registeredDeviceList=dl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId)
|
||||
{
|
||||
if (aqh && aqh->registeredDeviceList)
|
||||
if (aqh && aqh->registeredDeviceList) {
|
||||
return AQHMQTT_Device_List_GetById(aqh->registeredDeviceList, wantedDeviceId);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No registered devices");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
if (aqh && aqh->registeredDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQHMQTT_Device_List_First(aqh->registeredDeviceList);
|
||||
if (device) {
|
||||
fprintf(stderr, "Registered Devices:\n");
|
||||
while(device) {
|
||||
const char *sDeviceName;
|
||||
const char *sDeviceId;
|
||||
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
fprintf(stderr, " %s (%s)\n", sDeviceId?sDeviceId:"<no id>", sDeviceName?sDeviceName:"<no name>");
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "No registered devices\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "No registered devices\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -35,11 +35,17 @@ void AqHomeMqtt_SetPidFile(AQHOME_MQTT *aqh, const char *s);
|
||||
|
||||
int AqHomeMqtt_GetTimeout(const AQHOME_MQTT *aqh);
|
||||
|
||||
const char *AqHomeMqtt_GetDeviceFile(const AQHOME_MQTT *aqh);
|
||||
void AqHomeMqtt_SetDeviceFile(AQHOME_MQTT *aqh, const char *s);
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh);
|
||||
void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
|
||||
|
||||
void AqHomeMqtt_SetRegisteredDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
|
||||
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId);
|
||||
|
||||
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#define AQHOME_MQTT_DEFAULT_PIDFILE "/var/run/aqhome-mqtt.pid"
|
||||
#define AQHOME_MQTT_DEFAULT_DATADIR "/var/lib/aqhome-mqtt"
|
||||
#define AQHOME_MQTT_DEFAULT_DEVICEFILE "mqttlog/registereddevices.xml"
|
||||
|
||||
#define AQHOME_MQTT_DEFAULT_BROKER_PORT 1899
|
||||
#define AQHOME_MQTT_DEFAULT_BROKER_CLIENTID "mqtt"
|
||||
@@ -35,6 +36,8 @@ struct AQHOME_MQTT {
|
||||
|
||||
AQHMQTT_DEVICE_LIST *availableDeviceList;
|
||||
AQHMQTT_DEVICE_LIST *registeredDeviceList;
|
||||
|
||||
char *deviceFile;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -40,30 +40,33 @@ void AqHomeMqttLog_HandleSetData(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_M
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
DBG_ERROR(NULL, "Received SETDATA request");
|
||||
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
|
||||
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
|
||||
if (recvdValue) {
|
||||
const char *valueName;
|
||||
const char *deviceName;
|
||||
|
||||
valueName=recvdValue?AQH_Value_GetNameForSystem(recvdValue):NULL;
|
||||
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
|
||||
deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
|
||||
if (deviceName) {
|
||||
if (valueName && deviceName) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AqHomeMqtt_FindRegisteredDevice(aqh, deviceName);
|
||||
if (device) {
|
||||
char *valueDataFreeable;
|
||||
|
||||
DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
|
||||
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
|
||||
_sendDataForDevice(aqh, device, valueName, valueDataFreeable);
|
||||
free(valueDataFreeable);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
|
||||
AqHomeMqtt_DumpRegisteredDevices(aqh);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Request does not contain a device name");
|
||||
DBG_ERROR(NULL, "Either value name or device name missing in request");
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
@@ -96,6 +99,7 @@ void _sendDataForDevice(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const ch
|
||||
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(aqh, deviceId, topic, valueData);
|
||||
}
|
||||
} /* if out */
|
||||
@@ -118,12 +122,12 @@ void _sendValueToMqtt(AQHOME_MQTT *aqh, const char *deviceId, const AQHMQTT_TOPI
|
||||
|
||||
ep=AqHomeMqtt_GetMqttEndpoint(aqh);
|
||||
buf=_createBufferForTopic(deviceId, topic);
|
||||
DBG_INFO(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:"<empty>");
|
||||
DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:"<empty>");
|
||||
msgOut=AQH_PublishMqttMsg_new(0, 0, GWEN_Buffer_GetStart(buf),
|
||||
(const uint8_t*) (valueData?valueData:NULL),
|
||||
valueData?strlen(valueData):0);
|
||||
if (msgOut) {
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
|
||||
//GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Error creating message");
|
||||
@@ -140,16 +144,12 @@ GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *to
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
s=AQHMQTT_Topic_GetBeforeId(topic);
|
||||
if (s && *s) {
|
||||
if (s && *s)
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
GWEN_Buffer_AppendByte(buf, '/');
|
||||
}
|
||||
GWEN_Buffer_AppendString(buf, deviceId);
|
||||
s=AQHMQTT_Topic_GetAfterId(topic);
|
||||
if (s && *s) {
|
||||
GWEN_Buffer_AppendByte(buf, '/');
|
||||
if (s && *s)
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "./init.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "./xmlread.h"
|
||||
#include "./xmlwrite.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
@@ -87,6 +88,24 @@ int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "devicefile", 0, NULL);
|
||||
if (s && *s) {
|
||||
AqHomeMqtt_SetDeviceFile(aqh, s);
|
||||
}
|
||||
else {
|
||||
GWEN_BUFFER *bufFilename;
|
||||
|
||||
bufFilename=AQH_GetRuntimeFilePath(AQHOME_MQTT_DEFAULT_DEVICEFILE);
|
||||
if (bufFilename) {
|
||||
AqHomeMqtt_SetDeviceFile(aqh, GWEN_Buffer_GetStart(bufFilename));
|
||||
GWEN_Buffer_free(bufFilename);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Could not setup filename for devices, please specify via command line argument");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
|
||||
|
||||
rv=_setupMqtt(aqh, dbArgs);
|
||||
@@ -101,6 +120,8 @@ int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv)
|
||||
return rv;
|
||||
}
|
||||
|
||||
AqHomeMqtt_LoadRuntimeDeviceFiles(aqh);
|
||||
|
||||
AqHomeMqtt_ReloadDeviceFiles(aqh);
|
||||
|
||||
return 0;
|
||||
@@ -112,6 +133,7 @@ void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
DBG_ERROR(NULL, "Loading devices description files");
|
||||
deviceList=AqHomeMqttLog_ReadDataDeviceFiles(aqh);
|
||||
if (deviceList)
|
||||
AqHomeMqtt_SetAvailableDeviceList(aqh, deviceList);
|
||||
@@ -119,6 +141,32 @@ void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh)
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
DBG_ERROR(NULL, "Loading registered devices from file \"%s\"", aqh->deviceFile);
|
||||
deviceList=AqHomeMqttLog_ReadDeviceFile(aqh, aqh->deviceFile);
|
||||
if (deviceList)
|
||||
AqHomeMqtt_SetRegisteredDeviceList(aqh, deviceList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=AqHomeMqttLog_WriteDevicesFile(aqh, aqh->registeredDeviceList, aqh->deviceFile);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing devices to \"%s\" (%d)", aqh->deviceFile, rv);
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createPidFile(const char *pidFilename)
|
||||
{
|
||||
FILE *f;
|
||||
@@ -364,6 +412,18 @@ int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
I18S("Specify timeout in second (default: no timeout)"),
|
||||
I18S("Specify timeout in second (default: no timeout)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"devicefile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"d", /* short option */
|
||||
"devicefile", /* long option */
|
||||
I18S("Specify the device file"),
|
||||
I18S("Specify the device file")
|
||||
},
|
||||
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv);
|
||||
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh);
|
||||
|
||||
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh);
|
||||
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -70,6 +70,9 @@ void _handleIpcMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if (protoId==0 && code==AQH_MSGTYPE_IPC_DATA_RESULT) {
|
||||
/* result received */
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#define I18S(msg) msg
|
||||
|
||||
#define AQHOME_MQTTLOG_PING_INTERVAL 120
|
||||
#define AQHOME_MQTTLOG_SAVE_INTERVAL 60
|
||||
|
||||
#define FULL_DEBUG
|
||||
|
||||
@@ -143,9 +144,11 @@ void _serve(AQHOME_MQTT *aqh)
|
||||
int timeout;
|
||||
time_t startTime;
|
||||
time_t lastPingSendTime;
|
||||
time_t lastSaveTime;
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
startTime=time(NULL);
|
||||
lastSaveTime=time(NULL);
|
||||
|
||||
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
|
||||
|
||||
@@ -184,7 +187,28 @@ void _serve(AQHOME_MQTT *aqh)
|
||||
lastPingSendTime=time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (1){
|
||||
time_t now;
|
||||
|
||||
now=time(NULL);
|
||||
if (now-lastSaveTime>AQHOME_MQTTLOG_SAVE_INTERVAL) {
|
||||
DBG_ERROR(NULL, "Writing device files");
|
||||
rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing runtime data");
|
||||
}
|
||||
lastSaveTime=time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
} /* while */
|
||||
|
||||
rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing runtime data");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -69,6 +69,13 @@
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="mask" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/xml.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
@@ -41,7 +42,8 @@
|
||||
*/
|
||||
|
||||
static AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *sl);
|
||||
static AQHMQTT_DEVICE *_readDeviceFile(AQHOME_MQTT *aqh, const char *sFilename);
|
||||
static int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList);
|
||||
static int _readXmlDevices(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList);
|
||||
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);
|
||||
@@ -58,27 +60,32 @@ static AQHMQTT_TRANSLATION *_readXmlTranslation(AQHOME_MQTT *aqh, GWEN_XMLNODE *
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadRuntimeDataDeviceFiles(AQHOME_MQTT *aqh)
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDeviceFile(AQHOME_MQTT *aqh, const char *sFilename)
|
||||
{
|
||||
GWEN_STRINGLIST *sl;
|
||||
int rv;
|
||||
|
||||
sl=AQH_GetListOfMatchingRuntimeDataFiles("aqhome/devices", "*.xml");
|
||||
if (sl) {
|
||||
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=_readDeviceFiles(aqh, sl);
|
||||
GWEN_StringList_free(sl);
|
||||
if (deviceList==NULL) {
|
||||
DBG_INFO(NULL, "Error reading sysconf device files");
|
||||
deviceList=AQHMQTT_Device_List_new();
|
||||
rv=_readDeviceFileToList(aqh, sFilename, deviceList);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" not found", sFilename);
|
||||
AQHMQTT_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (AQHMQTT_Device_List_GetCount(deviceList)<1) {
|
||||
AQHMQTT_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No sysconf device files");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,12 +126,12 @@ AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *s
|
||||
|
||||
s=GWEN_StringListEntry_Data(se);
|
||||
if (s && *s) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
int rv;
|
||||
|
||||
device=_readDeviceFile(aqh, s);
|
||||
if (device) {
|
||||
DBG_ERROR(NULL, "Adding device \"%s\" to list", AQHMQTT_Device_GetName(device));
|
||||
AQHMQTT_Device_List_Add(device, deviceList);
|
||||
DBG_INFO(NULL, "Reading device file \"%s\"", s);
|
||||
rv=_readDeviceFileToList(aqh, s, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_WARN(NULL, "Error reading device file \"%s\" (%d), ignoring", s, rv);
|
||||
}
|
||||
}
|
||||
se=GWEN_StringListEntry_Next(se);
|
||||
@@ -140,11 +147,10 @@ AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *s
|
||||
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE *_readDeviceFile(AQHOME_MQTT *aqh, const char *sFilename)
|
||||
int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *rootNode;
|
||||
GWEN_XMLNODE *deviceNode;
|
||||
GWEN_XMLNODE *deviceListNode;
|
||||
int rv;
|
||||
|
||||
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
|
||||
@@ -152,36 +158,72 @@ AQHMQTT_DEVICE *_readDeviceFile(AQHOME_MQTT *aqh, const char *sFilename)
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return NULL;
|
||||
return rv;
|
||||
}
|
||||
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;
|
||||
deviceListNode=GWEN_XMLNode_FindFirstTag(rootNode, "devices", NULL, NULL);
|
||||
if (deviceListNode==NULL)
|
||||
deviceListNode=rootNode;
|
||||
|
||||
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 <device> element", sFilename);
|
||||
rv=_readXmlDevices(aqh, deviceListNode, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading devices from file \"%s\" (%d)", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return NULL;
|
||||
return rv;
|
||||
}
|
||||
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _readXmlDevices(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *deviceNode;
|
||||
int rv;
|
||||
|
||||
deviceNode=GWEN_XMLNode_FindFirstTag(deviceListNode, "device", NULL, NULL);
|
||||
if (deviceNode) {
|
||||
while(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);
|
||||
if (device==NULL) {
|
||||
DBG_INFO(NULL, "Error reading device from XML (%d)", rv);
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
else {
|
||||
const char *sDeviceId;
|
||||
const char *sDeviceName;
|
||||
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
if (sDeviceId && *sDeviceId) {
|
||||
DBG_ERROR(NULL, "Adding device \"%s\" (%s) to list", sDeviceId, sDeviceName?sDeviceName:"<no type name>");
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Adding device type \"%s\" to list", sDeviceName?sDeviceName:"<no type name>");
|
||||
}
|
||||
AQHMQTT_Device_List_Add(device, deviceList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Device is not an MQTT device, ignoring");
|
||||
}
|
||||
deviceNode=GWEN_XMLNode_FindNextTag(deviceNode, "device", NULL, NULL);
|
||||
} /* while */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <device> element found");
|
||||
return GWEN_ERROR_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -274,6 +316,7 @@ AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode)
|
||||
}
|
||||
AQHMQTT_Topic_SetDirection(topic, i);
|
||||
|
||||
AQHMQTT_Topic_SetName(topic, GWEN_XMLNode_GetProperty(topicNode, "name", NULL));
|
||||
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));
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDataDeviceFiles(AQHOME_MQTT *aqh);
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadRuntimeDataDeviceFiles(AQHOME_MQTT *aqh);
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadDeviceFile(AQHOME_MQTT *aqh, const char *sFilename);
|
||||
|
||||
|
||||
|
||||
|
||||
249
apps/aqhome-mqttlog/xmlwrite.c
Normal file
249
apps/aqhome-mqttlog/xmlwrite.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/****************************************************************************
|
||||
* 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 <config.h>
|
||||
#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 <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/xml.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
24
apps/aqhome-mqttlog/xmlwrite.h
Normal file
24
apps/aqhome-mqttlog/xmlwrite.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_MQTTLOG_XMLWRITE_H
|
||||
#define AQHOME_MQTTLOG_XMLWRITE_H
|
||||
|
||||
|
||||
#include "aqhome-mqttlog/aqhome_mqtt.h"
|
||||
#include "aqhome-mqttlog/types/device.h"
|
||||
|
||||
|
||||
|
||||
int AqHomeMqttLog_WriteDevicesFile(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -4,5 +4,5 @@ export AQHOME_LOGLEVEL=info
|
||||
export LD_LIBRARY_PATH="0-build/aqhome/:$LD_LIBRARY_PATH"
|
||||
|
||||
# 0-build/apps/aqhome-mqttlog/aqhome-mqttlog -ma 192.168.117.192 -mp 1883 -W /tmp/aqhome/mqttlog -i apps/aqhome-mqttlog/mqttlog.conf --mqttclientid=AQHOMEMQTTLOGTEST $*
|
||||
0-build/apps/aqhome-mqttlog/aqhome-mqttlog --mqttclientid=AQHOMEMQTTLOGTEST -p ./aqhome-mqtt.pid "$@"
|
||||
0-build/apps/aqhome-mqttlog/aqhome-mqttlog --mqttclientid=AQHOMEMQTTLOGTEST -p ./aqhome-mqtt.pid -d ./aqhome-mqtt.devices "$@"
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <gwenhywfar/pathmanager.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/i18n.h>
|
||||
#include <gwenhywfar/stringlist.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -39,6 +40,7 @@ static void _finiPathManager(void);
|
||||
static void _initI18n(void);
|
||||
static void _definePath(const char *pathName, const char *pathValue);
|
||||
static GWEN_STRINGLIST *_getListOfMatchingFiles(const char *pathName, const char *subFolder, const char *mask);
|
||||
static GWEN_BUFFER *_getRuntimeFilePath(const char *pathName, const char *sFilename);
|
||||
|
||||
|
||||
|
||||
@@ -106,6 +108,13 @@ GWEN_STRINGLIST *AQH_GetListOfMatchingSysconfFiles(const char *subFolder, const
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *AQH_GetRuntimeFilePath(const char *sFilename)
|
||||
{
|
||||
return _getRuntimeFilePath(AQHOME_PM_RTDATADIR, sFilename);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AQH_LoadConfigFile(void)
|
||||
{
|
||||
@@ -263,3 +272,37 @@ GWEN_STRINGLIST *_getListOfMatchingFiles(const char *pathName, const char *subFo
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *_getRuntimeFilePath(const char *pathName, const char *sFilename)
|
||||
{
|
||||
GWEN_STRINGLIST *sl;
|
||||
|
||||
sl=GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, pathName);
|
||||
if (sl) {
|
||||
GWEN_STRINGLISTENTRY *se;
|
||||
|
||||
se=GWEN_StringList_FirstEntry(sl);
|
||||
if (se) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_StringListEntry_Data(se);
|
||||
if (s && *s) {
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
if (sFilename && *sFilename) {
|
||||
GWEN_Buffer_AppendByte(buf, GWEN_DIR_SEPARATOR);
|
||||
GWEN_Buffer_AppendString(buf, sFilename);
|
||||
}
|
||||
GWEN_StringList_free(sl);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
GWEN_StringList_free(sl);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <gwenhywfar/stringlist.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
#include <gwenhywfar/buffer.h>
|
||||
|
||||
|
||||
|
||||
@@ -27,6 +28,8 @@ AQHOME_API GWEN_STRINGLIST *AQH_GetListOfMatchingDataFiles(const char *subFolder
|
||||
AQHOME_API GWEN_STRINGLIST *AQH_GetListOfMatchingRuntimeDataFiles(const char *subFolder, const char *mask);
|
||||
AQHOME_API GWEN_STRINGLIST *AQH_GetListOfMatchingSysconfFiles(const char *subFolder, const char *mask);
|
||||
|
||||
AQHOME_API GWEN_BUFFER *AQH_GetRuntimeFilePath(const char *sFilename);
|
||||
|
||||
AQHOME_API GWEN_STRINGLIST *AQH_GetGlobalDataDirs(void);
|
||||
AQHOME_API GWEN_STRINGLIST *AQH_GetGlobalSysconfDirs(void);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<device name="tasmotaplug" driver="mqtt">
|
||||
|
||||
<mqtttopics>
|
||||
<mqtttopic type="json" direction="in" >
|
||||
<mqtttopic type="json" name="sensor" direction="in" >
|
||||
<mask>tele/tasmota/*/SENSOR</mask>
|
||||
<beforeId>tele/tasmota/</beforeId>
|
||||
<afterId>/SENSOR</afterId>
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
</mqtttopic>
|
||||
|
||||
<mqtttopic type="num" direction="out" >
|
||||
<mqtttopic type="num" name="power" direction="out" >
|
||||
<beforeId>cmnd/tasmota/</beforeId>
|
||||
<afterId>/Power</afterId>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user