Improved mqttlog daemaon: persistent registered devices.
This commit is contained in:
@@ -55,6 +55,7 @@
|
|||||||
aqhome_mqtt.h
|
aqhome_mqtt.h
|
||||||
aqhome_mqtt_p.h
|
aqhome_mqtt_p.h
|
||||||
xmlread.h
|
xmlread.h
|
||||||
|
xmlwrite.h
|
||||||
c_setdata.h
|
c_setdata.h
|
||||||
</headers>
|
</headers>
|
||||||
|
|
||||||
@@ -68,6 +69,7 @@
|
|||||||
loop_mqtt.c
|
loop_mqtt.c
|
||||||
main.c
|
main.c
|
||||||
xmlread.c
|
xmlread.c
|
||||||
|
xmlwrite.c
|
||||||
c_setdata.c
|
c_setdata.c
|
||||||
</sources>
|
</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)
|
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh)
|
||||||
{
|
{
|
||||||
return aqh?aqh->availableDeviceList:NULL;
|
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)
|
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);
|
return AQHMQTT_Device_List_GetById(aqh->registeredDeviceList, wantedDeviceId);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(NULL, "No registered devices");
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
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);
|
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);
|
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh);
|
||||||
void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
|
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);
|
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId);
|
||||||
|
|
||||||
|
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#define AQHOME_MQTT_DEFAULT_PIDFILE "/var/run/aqhome-mqtt.pid"
|
#define AQHOME_MQTT_DEFAULT_PIDFILE "/var/run/aqhome-mqtt.pid"
|
||||||
#define AQHOME_MQTT_DEFAULT_DATADIR "/var/lib/aqhome-mqtt"
|
#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_PORT 1899
|
||||||
#define AQHOME_MQTT_DEFAULT_BROKER_CLIENTID "mqtt"
|
#define AQHOME_MQTT_DEFAULT_BROKER_CLIENTID "mqtt"
|
||||||
@@ -35,6 +36,8 @@ struct AQHOME_MQTT {
|
|||||||
|
|
||||||
AQHMQTT_DEVICE_LIST *availableDeviceList;
|
AQHMQTT_DEVICE_LIST *availableDeviceList;
|
||||||
AQHMQTT_DEVICE_LIST *registeredDeviceList;
|
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;
|
AQH_VALUE *recvdValue;
|
||||||
|
|
||||||
DBG_ERROR(NULL, "Received SETDATA request");
|
DBG_ERROR(NULL, "Received SETDATA request");
|
||||||
|
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
|
||||||
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
|
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
|
||||||
if (recvdValue) {
|
if (recvdValue) {
|
||||||
const char *valueName;
|
const char *valueName;
|
||||||
const char *deviceName;
|
const char *deviceName;
|
||||||
|
|
||||||
valueName=recvdValue?AQH_Value_GetNameForSystem(recvdValue):NULL;
|
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
|
||||||
deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
|
deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
|
||||||
if (deviceName) {
|
if (valueName && deviceName) {
|
||||||
AQHMQTT_DEVICE *device;
|
AQHMQTT_DEVICE *device;
|
||||||
|
|
||||||
device=AqHomeMqtt_FindRegisteredDevice(aqh, deviceName);
|
device=AqHomeMqtt_FindRegisteredDevice(aqh, deviceName);
|
||||||
if (device) {
|
if (device) {
|
||||||
char *valueDataFreeable;
|
char *valueDataFreeable;
|
||||||
|
|
||||||
|
DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
|
||||||
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
|
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
|
||||||
_sendDataForDevice(aqh, device, valueName, valueDataFreeable);
|
_sendDataForDevice(aqh, device, valueName, valueDataFreeable);
|
||||||
free(valueDataFreeable);
|
free(valueDataFreeable);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
|
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
|
||||||
|
AqHomeMqtt_DumpRegisteredDevices(aqh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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);
|
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;
|
value=valueList?AQHMQTT_Value_List_GetByName(valueList, valueName):NULL;
|
||||||
if (value) {
|
if (value) {
|
||||||
/* found value, create publish msg, send */
|
/* found value, create publish msg, send */
|
||||||
|
DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName);
|
||||||
_sendValueToMqtt(aqh, deviceId, topic, valueData);
|
_sendValueToMqtt(aqh, deviceId, topic, valueData);
|
||||||
}
|
}
|
||||||
} /* if out */
|
} /* if out */
|
||||||
@@ -118,12 +122,12 @@ void _sendValueToMqtt(AQHOME_MQTT *aqh, const char *deviceId, const AQHMQTT_TOPI
|
|||||||
|
|
||||||
ep=AqHomeMqtt_GetMqttEndpoint(aqh);
|
ep=AqHomeMqtt_GetMqttEndpoint(aqh);
|
||||||
buf=_createBufferForTopic(deviceId, topic);
|
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),
|
msgOut=AQH_PublishMqttMsg_new(0, 0, GWEN_Buffer_GetStart(buf),
|
||||||
(const uint8_t*) (valueData?valueData:NULL),
|
(const uint8_t*) (valueData?valueData:NULL),
|
||||||
valueData?strlen(valueData):0);
|
valueData?strlen(valueData):0);
|
||||||
if (msgOut) {
|
if (msgOut) {
|
||||||
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
|
//GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DBG_ERROR(NULL, "Error creating message");
|
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);
|
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||||
s=AQHMQTT_Topic_GetBeforeId(topic);
|
s=AQHMQTT_Topic_GetBeforeId(topic);
|
||||||
if (s && *s) {
|
if (s && *s)
|
||||||
GWEN_Buffer_AppendString(buf, s);
|
GWEN_Buffer_AppendString(buf, s);
|
||||||
GWEN_Buffer_AppendByte(buf, '/');
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(buf, deviceId);
|
GWEN_Buffer_AppendString(buf, deviceId);
|
||||||
s=AQHMQTT_Topic_GetAfterId(topic);
|
s=AQHMQTT_Topic_GetAfterId(topic);
|
||||||
if (s && *s) {
|
if (s && *s)
|
||||||
GWEN_Buffer_AppendByte(buf, '/');
|
|
||||||
GWEN_Buffer_AppendString(buf, s);
|
GWEN_Buffer_AppendString(buf, s);
|
||||||
}
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "./init.h"
|
#include "./init.h"
|
||||||
#include "./aqhome_mqtt_p.h"
|
#include "./aqhome_mqtt_p.h"
|
||||||
#include "./xmlread.h"
|
#include "./xmlread.h"
|
||||||
|
#include "./xmlwrite.h"
|
||||||
|
|
||||||
#include "aqhome/aqhome.h"
|
#include "aqhome/aqhome.h"
|
||||||
#include "aqhome/ipc/endpoint_ipc.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);
|
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
|
||||||
|
|
||||||
rv=_setupMqtt(aqh, dbArgs);
|
rv=_setupMqtt(aqh, dbArgs);
|
||||||
@@ -101,6 +120,8 @@ int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AqHomeMqtt_LoadRuntimeDeviceFiles(aqh);
|
||||||
|
|
||||||
AqHomeMqtt_ReloadDeviceFiles(aqh);
|
AqHomeMqtt_ReloadDeviceFiles(aqh);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -112,6 +133,7 @@ void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh)
|
|||||||
{
|
{
|
||||||
AQHMQTT_DEVICE_LIST *deviceList;
|
AQHMQTT_DEVICE_LIST *deviceList;
|
||||||
|
|
||||||
|
DBG_ERROR(NULL, "Loading devices description files");
|
||||||
deviceList=AqHomeMqttLog_ReadDataDeviceFiles(aqh);
|
deviceList=AqHomeMqttLog_ReadDataDeviceFiles(aqh);
|
||||||
if (deviceList)
|
if (deviceList)
|
||||||
AqHomeMqtt_SetAvailableDeviceList(aqh, 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)
|
int _createPidFile(const char *pidFilename)
|
||||||
{
|
{
|
||||||
FILE *f;
|
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)"),
|
||||||
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_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||||
GWEN_ArgsType_Int, /* type */
|
GWEN_ArgsType_Int, /* type */
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv);
|
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv);
|
||||||
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh);
|
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh);
|
||||||
|
|
||||||
|
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh);
|
||||||
|
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ void _handleIpcMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (protoId==0 && code==AQH_MSGTYPE_IPC_DATA_RESULT) {
|
||||||
|
/* result received */
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
#define I18S(msg) msg
|
#define I18S(msg) msg
|
||||||
|
|
||||||
#define AQHOME_MQTTLOG_PING_INTERVAL 120
|
#define AQHOME_MQTTLOG_PING_INTERVAL 120
|
||||||
|
#define AQHOME_MQTTLOG_SAVE_INTERVAL 60
|
||||||
|
|
||||||
#define FULL_DEBUG
|
#define FULL_DEBUG
|
||||||
|
|
||||||
@@ -143,9 +144,11 @@ void _serve(AQHOME_MQTT *aqh)
|
|||||||
int timeout;
|
int timeout;
|
||||||
time_t startTime;
|
time_t startTime;
|
||||||
time_t lastPingSendTime;
|
time_t lastPingSendTime;
|
||||||
|
time_t lastSaveTime;
|
||||||
GWEN_DB_NODE *dbArgs;
|
GWEN_DB_NODE *dbArgs;
|
||||||
|
|
||||||
startTime=time(NULL);
|
startTime=time(NULL);
|
||||||
|
lastSaveTime=time(NULL);
|
||||||
|
|
||||||
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
|
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
|
||||||
|
|
||||||
@@ -184,7 +187,28 @@ void _serve(AQHOME_MQTT *aqh)
|
|||||||
lastPingSendTime=time(NULL);
|
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>
|
<flags></flags>
|
||||||
</member>
|
</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">
|
<member name="mask" type="char_ptr" maxlen="128">
|
||||||
<default>NULL</default>
|
<default>NULL</default>
|
||||||
<preset>NULL</preset>
|
<preset>NULL</preset>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <gwenhywfar/endpoint_multilayer.h>
|
#include <gwenhywfar/endpoint_multilayer.h>
|
||||||
#include <gwenhywfar/text.h>
|
#include <gwenhywfar/text.h>
|
||||||
#include <gwenhywfar/xml.h>
|
#include <gwenhywfar/xml.h>
|
||||||
|
#include <gwenhywfar/directory.h>
|
||||||
#include <gwenhywfar/debug.h>
|
#include <gwenhywfar/debug.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -41,7 +42,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *sl);
|
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_DEVICE *_readXmlDevice(AQHOME_MQTT *aqh, GWEN_XMLNODE *deviceNode);
|
||||||
static AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode);
|
static AQHMQTT_TOPIC_LIST *_readXmlTopicList(AQHOME_MQTT *aqh, GWEN_XMLNODE *parentNode);
|
||||||
static AQHMQTT_TOPIC *_readXmlTopic(AQHOME_MQTT *aqh, GWEN_XMLNODE *topicNode);
|
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_ReadDeviceFile(AQHOME_MQTT *aqh, const char *sFilename)
|
||||||
AQHMQTT_DEVICE_LIST *AqHomeMqttLog_ReadRuntimeDataDeviceFiles(AQHOME_MQTT *aqh)
|
|
||||||
{
|
{
|
||||||
GWEN_STRINGLIST *sl;
|
int rv;
|
||||||
|
|
||||||
sl=AQH_GetListOfMatchingRuntimeDataFiles("aqhome/devices", "*.xml");
|
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE);
|
||||||
if (sl) {
|
if (rv<0) {
|
||||||
|
DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
AQHMQTT_DEVICE_LIST *deviceList;
|
AQHMQTT_DEVICE_LIST *deviceList;
|
||||||
|
|
||||||
deviceList=_readDeviceFiles(aqh, sl);
|
deviceList=AQHMQTT_Device_List_new();
|
||||||
GWEN_StringList_free(sl);
|
rv=_readDeviceFileToList(aqh, sFilename, deviceList);
|
||||||
if (deviceList==NULL) {
|
if (rv<0) {
|
||||||
DBG_INFO(NULL, "Error reading sysconf device files");
|
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 NULL;
|
||||||
}
|
}
|
||||||
return deviceList;
|
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);
|
s=GWEN_StringListEntry_Data(se);
|
||||||
if (s && *s) {
|
if (s && *s) {
|
||||||
AQHMQTT_DEVICE *device;
|
int rv;
|
||||||
|
|
||||||
device=_readDeviceFile(aqh, s);
|
DBG_INFO(NULL, "Reading device file \"%s\"", s);
|
||||||
if (device) {
|
rv=_readDeviceFileToList(aqh, s, deviceList);
|
||||||
DBG_ERROR(NULL, "Adding device \"%s\" to list", AQHMQTT_Device_GetName(device));
|
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||||
AQHMQTT_Device_List_Add(device, deviceList);
|
DBG_WARN(NULL, "Error reading device file \"%s\" (%d), ignoring", s, rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
se=GWEN_StringListEntry_Next(se);
|
se=GWEN_StringListEntry_Next(se);
|
||||||
@@ -140,11 +147,10 @@ AQHMQTT_DEVICE_LIST *_readDeviceFiles(AQHOME_MQTT *aqh, const GWEN_STRINGLIST *s
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _readDeviceFileToList(AQHOME_MQTT *aqh, const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList)
|
||||||
AQHMQTT_DEVICE *_readDeviceFile(AQHOME_MQTT *aqh, const char *sFilename)
|
|
||||||
{
|
{
|
||||||
GWEN_XMLNODE *rootNode;
|
GWEN_XMLNODE *rootNode;
|
||||||
GWEN_XMLNODE *deviceNode;
|
GWEN_XMLNODE *deviceListNode;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
|
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
|
||||||
@@ -152,36 +158,72 @@ AQHMQTT_DEVICE *_readDeviceFile(AQHOME_MQTT *aqh, const char *sFilename)
|
|||||||
if (rv<0) {
|
if (rv<0) {
|
||||||
DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv);
|
DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv);
|
||||||
GWEN_XMLNode_free(rootNode);
|
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);
|
deviceListNode=GWEN_XMLNode_FindFirstTag(rootNode, "devices", NULL, NULL);
|
||||||
if (driverName && *driverName && strcasecmp(driverName, "mqtt")==0) {
|
if (deviceListNode==NULL)
|
||||||
AQHMQTT_DEVICE *device;
|
deviceListNode=rootNode;
|
||||||
|
|
||||||
device=_readXmlDevice(aqh, deviceNode);
|
rv=_readXmlDevices(aqh, deviceListNode, deviceList);
|
||||||
GWEN_XMLNode_free(rootNode);
|
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||||
if (device==NULL) {
|
DBG_ERROR(AQH_LOGDOMAIN, "Error reading devices from file \"%s\" (%d)", sFilename, rv);
|
||||||
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);
|
|
||||||
GWEN_XMLNode_free(rootNode);
|
GWEN_XMLNode_free(rootNode);
|
||||||
return NULL;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
GWEN_XMLNode_free(rootNode);
|
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_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_SetTopic(topic, GWEN_XMLNode_GetCharValue(topicNode, "topic", NULL));
|
||||||
AQHMQTT_Topic_SetMask(topic, GWEN_XMLNode_GetCharValue(topicNode, "mask", NULL));
|
AQHMQTT_Topic_SetMask(topic, GWEN_XMLNode_GetCharValue(topicNode, "mask", NULL));
|
||||||
AQHMQTT_Topic_SetBeforeId(topic, GWEN_XMLNode_GetCharValue(topicNode, "beforeId", 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_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"
|
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 -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/pathmanager.h>
|
||||||
#include <gwenhywfar/debug.h>
|
#include <gwenhywfar/debug.h>
|
||||||
#include <gwenhywfar/i18n.h>
|
#include <gwenhywfar/i18n.h>
|
||||||
|
#include <gwenhywfar/stringlist.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ static void _finiPathManager(void);
|
|||||||
static void _initI18n(void);
|
static void _initI18n(void);
|
||||||
static void _definePath(const char *pathName, const char *pathValue);
|
static void _definePath(const char *pathName, const char *pathValue);
|
||||||
static GWEN_STRINGLIST *_getListOfMatchingFiles(const char *pathName, const char *subFolder, const char *mask);
|
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)
|
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/stringlist.h>
|
||||||
#include <gwenhywfar/db.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_GetListOfMatchingRuntimeDataFiles(const char *subFolder, const char *mask);
|
||||||
AQHOME_API GWEN_STRINGLIST *AQH_GetListOfMatchingSysconfFiles(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_GetGlobalDataDirs(void);
|
||||||
AQHOME_API GWEN_STRINGLIST *AQH_GetGlobalSysconfDirs(void);
|
AQHOME_API GWEN_STRINGLIST *AQH_GetGlobalSysconfDirs(void);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<device name="tasmotaplug" driver="mqtt">
|
<device name="tasmotaplug" driver="mqtt">
|
||||||
|
|
||||||
<mqtttopics>
|
<mqtttopics>
|
||||||
<mqtttopic type="json" direction="in" >
|
<mqtttopic type="json" name="sensor" direction="in" >
|
||||||
<mask>tele/tasmota/*/SENSOR</mask>
|
<mask>tele/tasmota/*/SENSOR</mask>
|
||||||
<beforeId>tele/tasmota/</beforeId>
|
<beforeId>tele/tasmota/</beforeId>
|
||||||
<afterId>/SENSOR</afterId>
|
<afterId>/SENSOR</afterId>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
</mqtttopic>
|
</mqtttopic>
|
||||||
|
|
||||||
<mqtttopic type="num" direction="out" >
|
<mqtttopic type="num" name="power" direction="out" >
|
||||||
<beforeId>cmnd/tasmota/</beforeId>
|
<beforeId>cmnd/tasmota/</beforeId>
|
||||||
<afterId>/Power</afterId>
|
<afterId>/Power</afterId>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user