diff --git a/apps/aqhome-data/0BUILD b/apps/aqhome-data/0BUILD index 1eeccd4..b3d33c0 100644 --- a/apps/aqhome-data/0BUILD +++ b/apps/aqhome-data/0BUILD @@ -48,6 +48,7 @@ c_getlastdatapoint.h c_setdata.h c_addvalue.h + c_moddevice.h @@ -65,6 +66,7 @@ c_getlastdatapoint.c c_setdata.c c_addvalue.c + c_moddevice.c main.c diff --git a/apps/aqhome-data/c_moddevice.c b/apps/aqhome-data/c_moddevice.c new file mode 100644 index 0000000..9a46d04 --- /dev/null +++ b/apps/aqhome-data/c_moddevice.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * 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 "./c_getlastdatapoint.h" +#include "./aqhome_data_p.h" +#include "aqhome/ipc/data/ipc_data.h" +#include "aqhome/ipc/data/msg_data_devices.h" +#include "aqhome/ipc/endpoint_ipc.h" +#include "aqhome/ipc/msg_ipc_result.h" +#include "aqhome/ipc/msg_ipc_tag16.h" + +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + + +void AqHomeData_HandleModDevice(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg) +{ + GWEN_MSG *outMsg; + int resultCode=AQH_MSG_IPC_SUCCESS; + + if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_MODDEVICE) { + AQH_DEVICE *device; + + AQH_DevicesDataIpcMsg_Parse(recvdMsg, 0); + device=AQH_DevicesDataIpcMsg_ReadFirstDevice(recvdMsg); + if (device) { + const char *deviceNameForSystem; + + deviceNameForSystem=AQH_Device_GetNameForSystem(device); + if (deviceNameForSystem && *deviceNameForSystem) { + AQH_DEVICE *storedDevice; + + storedDevice=AQH_Storage_GetDeviceByNameForSystem(aqh->storage, deviceNameForSystem); + if (storedDevice) { + const char *s; + + s=AQH_Device_GetNameForGui(device); + if (s && *s) + AQH_Device_SetNameForGui(storedDevice, s); + + s=AQH_Device_GetRoomName(device); + if (s && *s) + AQH_Device_SetRoomName(storedDevice, s); + + s=AQH_Device_GetLocation(device); + if (s && *s) + AQH_Device_SetLocation(storedDevice, s); + + s=AQH_Device_GetDescription(device); + if (s && *s) + AQH_Device_SetDescription(storedDevice, s); + + AQH_Storage_AddRuntimeFlags(aqh->storage, AQH_STORAGE_RTFLAGS_MODIFIED); + resultCode=AQH_MSG_IPC_SUCCESS; + } + else { + DBG_INFO(NULL, "Device \"%s\" not found", deviceNameForSystem); + resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; + } + } + else { + DBG_INFO(NULL, "No name for value"); + resultCode=AQH_MSG_IPC_ERROR_NOTFOUND; + } + } + else { + DBG_INFO(NULL, "No device info in message"); + resultCode=AQH_MSG_IPC_ERROR_INVALID; + } + } + else { + DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data"); + resultCode=AQH_MSG_IPC_ERROR_PERMS; + } + + outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT, resultCode); + GWEN_MsgEndpoint_AddSendMessage(ep, outMsg); +} + + + diff --git a/apps/aqhome-data/c_moddevice.h b/apps/aqhome-data/c_moddevice.h new file mode 100644 index 0000000..e3cea44 --- /dev/null +++ b/apps/aqhome-data/c_moddevice.h @@ -0,0 +1,25 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQHOME_DATA_C_MODDEVICE_H +#define AQHOME_DATA_C_MODDEVICE_H + + +#include "./aqhome_data.h" + + +void AqHomeData_HandleModDevice(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg); + + + +#endif + + + + + diff --git a/apps/aqhome-data/loop.c b/apps/aqhome-data/loop.c index a8d0f4c..6518589 100644 --- a/apps/aqhome-data/loop.c +++ b/apps/aqhome-data/loop.c @@ -20,6 +20,7 @@ #include "./c_getdevices.h" #include "./c_setdata.h" #include "./c_addvalue.h" +#include "./c_moddevice.h" #include "./aqhome_data_p.h" #include "aqhome/ipc/data/ipc_data.h" #include "aqhome/ipc/data/msg_data_values.h" @@ -268,6 +269,7 @@ void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg) case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeData_HandleSetData(aqh, ep, msg); break; case AQH_MSGTYPE_IPC_DATA_ADDVALUE: AqHomeData_HandleAddValue(aqh, ep, msg); break; case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: AqHomeData_HandleGetDevices(aqh, ep, msg); break; + case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: AqHomeData_HandleModDevice(aqh, ep, msg); break; default: break; } } diff --git a/apps/aqhome-tool/data/0BUILD b/apps/aqhome-tool/data/0BUILD index e03ccb4..8c35042 100644 --- a/apps/aqhome-tool/data/0BUILD +++ b/apps/aqhome-tool/data/0BUILD @@ -39,6 +39,7 @@ getdatapoints.h getlastdatapoint.h setdata.h + moddevice.h @@ -50,6 +51,7 @@ getdatapoints.c getlastdatapoint.c setdata.c + moddevice.c diff --git a/apps/aqhome-tool/data/getdevices.c b/apps/aqhome-tool/data/getdevices.c index 945133d..7f7e3cd 100644 --- a/apps/aqhome-tool/data/getdevices.c +++ b/apps/aqhome-tool/data/getdevices.c @@ -108,6 +108,17 @@ int AQH_Tool_GetDevices(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) I18S("Specify service password"), I18S("Specify service password") }, + { + 0, /* flags */ + GWEN_ArgsType_Int, /* type */ + "printHeader", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "H", /* short option */ + "printheader", /* long option */ + I18S("Print header if given"), + I18S("Print header if given") + }, { GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ GWEN_ArgsType_Int, /* type */ @@ -153,8 +164,10 @@ int _doGetDevices(GWEN_DB_NODE *dbArgs) GWEN_MSG_ENDPOINT *epTcp; int timeoutInSeconds; GWEN_MSG *msg; + int printHeader; timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); + printHeader=GWEN_DB_GetIntValue(dbArgs, "printHeader", 0, 0); epTcp=Utils_OpenConnection(dbArgs, 0, timeoutInSeconds); if (epTcp==NULL) { @@ -185,7 +198,8 @@ int _doGetDevices(GWEN_DB_NODE *dbArgs) device=AQH_Device_List_First(deviceList); while(device) { - Utils_PrintDevice(device); + Utils_PrintDevice(device, printHeader); + printHeader=0; device=AQH_Device_List_Next(device); } AQH_Device_List_free(deviceList); diff --git a/apps/aqhome-tool/data/moddevice.c b/apps/aqhome-tool/data/moddevice.c new file mode 100644 index 0000000..6192688 --- /dev/null +++ b/apps/aqhome-tool/data/moddevice.c @@ -0,0 +1,271 @@ +/**************************************************************************** + * 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 "./moddevice.h" +#include "../utils.h" + +#include "aqhome/msg/msg_node.h" +#include "aqhome/ipc/msg_ipc_result.h" +#include "aqhome/ipc/data/msg_data_devices.h" +#include "aqhome/ipc/data/ipc_data.h" + +#include +#include +#include +#include + +#include +#include + + +#define I18S(msg) msg +#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg) + + +static int _doModDevice(GWEN_DB_NODE *dbArgs); +static void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const AQH_DEVICE *device); + + + + +int AQH_Tool_ModDevice(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv) +{ + GWEN_DB_NODE *dbLocalArgs; + int rv; + const GWEN_ARGS args[]= { + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "tcpAddress", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "t", /* short option */ + "tcpaddress", /* long option */ + I18S("Specify TCP address to connect to (defaults to 127.0.0.1)"), + I18S("Specify TCP address to connect to (defaults to 127.0.0.1)") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "tcpPort", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "P", /* short option */ + "tcpport", /* long option */ + I18S("Specify the TCP port to listen on"), + I18S("Specify the TCP port to listen on") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Int, /* type */ + "timeout", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "T", /* short option */ + NULL, /* long option */ + I18S("Specify timeout in seconds for response"), + I18S("Specify timeout in seconds for response") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "clientId", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "c", /* short option */ + "clientid", /* long option */ + I18S("Specify CLIENTID"), + I18S("Specify CLIENTID") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "userId", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "u", /* short option */ + "userid", /* long option */ + I18S("Specify user id"), + I18S("Specify user id") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "password", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "p", /* short option */ + "password", /* long option */ + I18S("Specify service password"), + I18S("Specify service password") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "device", /* name */ + 1, /* minnum */ + 1, /* maxnum */ + "d", /* short option */ + "device", /* long option */ + I18S("Specify name of the device to modify"), + I18S("Specify name of the device to modify") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "roomName", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "R", /* short option */ + "room", /* long option */ + I18S("Specify room for a device"), + I18S("Specify room for a device") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "nameForGui", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "G", /* short option */ + "guiname", /* long option */ + I18S("Specify GUI name of the device"), + I18S("Specify GUI name of the device") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "location", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + "L", /* short option */ + "location", /* long option */ + I18S("Specify location of the device"), + I18S("Specify location of the device") + }, + { + GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */ + GWEN_ArgsType_Char, /* type */ + "description", /* name */ + 0, /* minnum */ + 1, /* maxnum */ + NULL, /* short option */ + "description", /* long option */ + I18S("Specify description for the device"), + I18S("Specify description for the device") + }, + { + GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */ + GWEN_ArgsType_Int, /* type */ + "help", /* name */ + 0, /* minnum */ + 0, /* maxnum */ + "h", /* short option */ + "help", /* long option */ + "Show this help screen", /* short description */ + "Show this help screen" /* long description */ + } + }; + + dbLocalArgs=GWEN_DB_GetGroup(dbGlobalArgs, GWEN_DB_FLAGS_DEFAULT, "local"); + rv=GWEN_Args_Check(argc, argv, 1, + GWEN_ARGS_MODE_ALLOW_FREEPARAM, + args, + dbLocalArgs); + if (rv==GWEN_ARGS_RESULT_ERROR) { + fprintf(stderr, "ERROR: Could not parse arguments\n"); + return 1; + } + else if (rv==GWEN_ARGS_RESULT_HELP) { + GWEN_BUFFER *ubuf; + + ubuf=GWEN_Buffer_new(0, 1024, 0, 1); + if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) { + fprintf(stderr, "ERROR: Could not create help string\n"); + return 1; + } + fprintf(stderr, "%s\n", GWEN_Buffer_GetStart(ubuf)); + GWEN_Buffer_free(ubuf); + return 0; + } + + return _doModDevice(dbLocalArgs); +} + + + +int _doModDevice(GWEN_DB_NODE *dbArgs) +{ + GWEN_MSG_ENDPOINT *epTcp; + int timeoutInSeconds; + GWEN_MSG *msg; + AQH_DEVICE *device; + + timeoutInSeconds=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 5); + device=Utils_DeviceFromArgs(dbArgs); + + epTcp=Utils_OpenConnection(dbArgs, 0, timeoutInSeconds); + if (epTcp==NULL) { + DBG_ERROR(NULL, "ERROR creating TCP connection"); + return 2; + } + + /*fprintf(stdout, "Sending GetValues request\n");*/ + + _sendCommand(epTcp, device); + + for (;;) { + uint16_t code; + + msg=Utils_WaitForSpecificIpcMessage(epTcp, AQH_MSGTYPE_IPC_DATA_RESULT, timeoutInSeconds); + if (msg==NULL) { + DBG_ERROR(NULL, "No response received"); + return 2; + } + code=GWEN_IpcMsg_GetCode(msg); + if (code==AQH_MSGTYPE_IPC_DATA_RESULT) { + uint32_t resultCode; + + resultCode=AQH_ResultIpcMsg_GetResultCode(msg); + if (resultCode!=AQH_MSG_IPC_SUCCESS) { + fprintf(stderr, "ERROR: %d\n", resultCode); + GWEN_MsgEndpoint_free(epTcp); + return 3; + } + break; + } + else { + DBG_INFO(NULL, "Unexpected message \"%d\"", code); + GWEN_MsgEndpoint_free(epTcp); + return 3; + } + } /* for */ + + GWEN_MsgEndpoint_free(epTcp); + return 0; +} + + + +void _sendCommand(GWEN_MSG_ENDPOINT *epTcp, const AQH_DEVICE *device) +{ + GWEN_MSG *msgOut; + + msgOut=AQH_DevicesDataIpcMsg_newForOneDevice(AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, device); + GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut); +} + + + + + + diff --git a/apps/aqhome-tool/data/moddevice.h b/apps/aqhome-tool/data/moddevice.h new file mode 100644 index 0000000..53d8301 --- /dev/null +++ b/apps/aqhome-tool/data/moddevice.h @@ -0,0 +1,21 @@ +/**************************************************************************** + * 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. + ****************************************************************************/ + +#ifndef AQHOME_TOOL_MODDEVICE_H +#define AQHOME_TOOL_MODDEVICE_H + + +#include + + + +int AQH_Tool_ModDevice(GWEN_DB_NODE *dbGlobalArgs, int argc, char **argv); + + +#endif + diff --git a/apps/aqhome-tool/main.c b/apps/aqhome-tool/main.c index 6a40b95..6d39c28 100644 --- a/apps/aqhome-tool/main.c +++ b/apps/aqhome-tool/main.c @@ -19,6 +19,7 @@ #include "./data/getdatapoints.h" #include "./data/getlastdatapoint.h" #include "./data/setdata.h" +#include "./data/moddevice.h" #include #include @@ -81,6 +82,7 @@ int main(int argc, char **argv) GWEN_FE_DAH("getdata", AQH_Tool_GetDataPoints, I18N("Request list of datapoints for a value on the data server")), GWEN_FE_DAH("getlastdata", AQH_Tool_GetLastDataPoint, I18N("Request last datapoint for a value on the data server")), GWEN_FE_DAH("setdata", AQH_Tool_SetData, I18N("Set data for a value on the data server (e.g. a switch or thermostat)")), + GWEN_FE_DAH("moddevice", AQH_Tool_ModDevice, I18N("Modify a device on the data server")), GWEN_FE_END(), }; const GWEN_FUNCS *func; diff --git a/apps/aqhome-tool/utils.c b/apps/aqhome-tool/utils.c index 1edf0e5..081b9df 100644 --- a/apps/aqhome-tool/utils.c +++ b/apps/aqhome-tool/utils.c @@ -298,31 +298,70 @@ void Utils_PrintMeanData(const uint64_t *dataPoints, uint32_t numValues, const c -void Utils_PrintDevice(const AQH_DEVICE *device) +void Utils_PrintDevice(const AQH_DEVICE *device, int printHeader) { GWEN_TIMESTAMP *ts; uint64_t deviceId; - const char *deviceName; + const char *deviceNameForSystem; + const char *deviceNameForGui; + const char *roomName; + const char *location; + const char *description; uint64_t timestamp; deviceId=AQH_Device_GetId(device); - deviceName=AQH_Device_GetNameForSystem(device); + deviceNameForSystem=AQH_Device_GetNameForSystem(device); + deviceNameForGui=AQH_Device_GetNameForGui(device); + roomName=AQH_Device_GetRoomName(device); + location=AQH_Device_GetLocation(device); + description=AQH_Device_GetDescription(device); timestamp=AQH_Device_GetTimestampCreation(device); ts=timestamp?GWEN_Timestamp_fromLocalTime((time_t) timestamp):NULL; + + if (printHeader) + fprintf(stdout, "ID\tName\tCreation Date\tGUI Name\tRoom\tLocation\tDescription\n"); + + if (ts) - fprintf(stdout, "%lu\t%s\t%04d/%02d/%02d-%02d:%02d:%02d\n", + fprintf(stdout, "%lu\t%s\t%04d/%02d/%02d-%02d:%02d:%02d\t%s\t%s\t%s\t%s\n", deviceId, - deviceName, + deviceNameForSystem, GWEN_Timestamp_GetYear(ts), GWEN_Timestamp_GetMonth(ts), GWEN_Timestamp_GetDay(ts), GWEN_Timestamp_GetHour(ts), GWEN_Timestamp_GetMinute(ts), - GWEN_Timestamp_GetSecond(ts)); + GWEN_Timestamp_GetSecond(ts), + deviceNameForGui?deviceNameForGui:"", + roomName?roomName:"", + location?location:"", + description?description:""); else - fprintf(stdout, "%lu\t%s\t\n", + fprintf(stdout, "%lu\t%s\t\t%s\t%s\t%s\t%s\n", deviceId, - deviceName); + deviceNameForSystem, + deviceNameForGui?deviceNameForGui:"", + roomName?roomName:"", + location?location:"", + description?description:""); } + +AQH_DEVICE *Utils_DeviceFromArgs(GWEN_DB_NODE *dbArgs) +{ + AQH_DEVICE *device; + + device=AQH_Device_new(); + AQH_Device_SetNameForSystem(device, GWEN_DB_GetCharValue(dbArgs, "device", 0, NULL)); + AQH_Device_SetNameForGui(device, GWEN_DB_GetCharValue(dbArgs, "nameForGui", 0, NULL)); + AQH_Device_SetRoomName(device, GWEN_DB_GetCharValue(dbArgs, "roomName", 0, NULL)); + AQH_Device_SetLocation(device, GWEN_DB_GetCharValue(dbArgs, "location", 0, NULL)); + AQH_Device_SetDescription(device, GWEN_DB_GetCharValue(dbArgs, "description", 0, NULL)); + + return device; +} + + + + diff --git a/apps/aqhome-tool/utils.h b/apps/aqhome-tool/utils.h index 3a1e0cb..0332056 100644 --- a/apps/aqhome-tool/utils.h +++ b/apps/aqhome-tool/utils.h @@ -34,7 +34,10 @@ void Utils_PrintDataPoints(const uint64_t *dataPoints, uint32_t numValues, const void Utils_PrintSingleDataPoint(uint64_t timestamp, double data, const char *valueUnits); void Utils_PrintMeanData(const uint64_t *dataPoints, uint32_t numValues, const char *valueUnits); -void Utils_PrintDevice(const AQH_DEVICE *device); +void Utils_PrintDevice(const AQH_DEVICE *device, int printHeader); + + +AQH_DEVICE *Utils_DeviceFromArgs(GWEN_DB_NODE *dbArgs); #endif diff --git a/aqhome/ipc/data/ipc_data.h b/aqhome/ipc/data/ipc_data.h index 997cb2b..a886384 100644 --- a/aqhome/ipc/data/ipc_data.h +++ b/aqhome/ipc/data/ipc_data.h @@ -47,7 +47,7 @@ #define AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ 0xb00 /* GWEN_IpcMsg */ #define AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP 0xc00 /* AQH_DevicesDataIpcMsg */ -#define AQH_MSGTYPE_IPC_DATA_MODDEVICES_REQ 0xd00 /* AQH_DevicesDataIpcMsg */ +#define AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ 0xd00 /* AQH_DevicesDataIpcMsg */