Files
aqhomecontrol/aqhome/aqhome.c
Martin Preuss d0c8b3b284 let setData use double values instead of strings.
this allows for storing value set with setData which can then be used in
the cgi module to retrieve the last value set.
2025-10-07 23:50:50 +02:00

591 lines
14 KiB
C

/****************************************************************************
* 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 <config.h>
#endif
#include "aqhome/aqhome.h"
#include <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/logger.h>
#include <gwenhywfar/pathmanager.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/i18n.h>
#include <gwenhywfar/stringlist.h>
#include <gwenhywfar/directory.h>
#include <stdlib.h>
#define AQHOME_PM_LIBNAME "aqhome"
#define AQHOME_PM_SYSCONFDIR "sysconfdir"
#define AQHOME_PM_DATADIR "datadir"
#define AQHOME_PM_RTDATADIR "rtdatadir"
#define AQHOME_PM_LOCALEDIR "localedir"
#define AQHOME_SYSCONFIG_FILE "aqhome.conf"
static void _initLogging(void);
static void _finiLogging(void);
static void _initPathManager(void);
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);
static GWEN_BUFFER *_findFileinPath(const char *pathName, const char *sFilename);
static int _readUint8DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom);
static int _readUint16DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom);
static int _readUint32DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom);
static int _readUint8DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom);
static int _readUint16DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom);
static int _readUint32DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom);
int AQH_Init(void)
{
int rv;
rv=GWEN_Init();
if (rv) {
DBG_ERROR_ERR(AQH_LOGDOMAIN, rv);
return rv;
}
_initLogging();
_initPathManager();
_initI18n();
return 0;
}
void AQH_Fini(void)
{
_finiPathManager();
_finiLogging();
GWEN_Fini();
}
GWEN_STRINGLIST *AQH_GetGlobalDataDirs(void)
{
return GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, AQHOME_PM_DATADIR);
}
GWEN_STRINGLIST *AQH_GetGlobalSysconfDirs(void)
{
return GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, AQHOME_PM_SYSCONFDIR);
}
GWEN_STRINGLIST *AQH_GetListOfMatchingDataFiles(const char *subFolder, const char *mask)
{
return _getListOfMatchingFiles(AQHOME_PM_DATADIR, subFolder, mask);
}
GWEN_STRINGLIST *AQH_GetListOfMatchingRuntimeDataFiles(const char *subFolder, const char *mask)
{
return _getListOfMatchingFiles(AQHOME_PM_RTDATADIR, subFolder, mask);
}
GWEN_STRINGLIST *AQH_GetListOfMatchingSysconfFiles(const char *subFolder, const char *mask)
{
return _getListOfMatchingFiles(AQHOME_PM_SYSCONFDIR, subFolder, mask);
}
GWEN_BUFFER *AQH_GetRuntimeFilePath(const char *sFilename)
{
return _getRuntimeFilePath(AQHOME_PM_RTDATADIR, sFilename);
}
GWEN_BUFFER *AQH_FindPathOfRuntimeFile(const char *sFilename)
{
return _findFileinPath(AQHOME_PM_RTDATADIR, sFilename);
}
GWEN_BUFFER *AQH_FindPathOfSysconfFile(const char *sFilename)
{
return _findFileinPath(AQHOME_PM_SYSCONFDIR, sFilename);
}
GWEN_BUFFER *AQH_FindPathOfDataFile(const char *sFilename)
{
return _findFileinPath(AQHOME_PM_DATADIR, sFilename);
}
GWEN_DB_NODE *AQH_LoadConfigFile(void)
{
GWEN_BUFFER *fbuf;
int rv;
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
rv=GWEN_PathManager_FindFile(AQHOME_PM_LIBNAME, AQHOME_PM_SYSCONFDIR, AQHOME_SYSCONFIG_FILE, fbuf);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "Config file \"%s\" not found (%d)", AQHOME_SYSCONFIG_FILE, rv);
GWEN_Buffer_free(fbuf);
return NULL;
}
else {
GWEN_DB_NODE *db;
db=GWEN_DB_Group_new("aqhome-config");
rv=GWEN_DB_ReadFile(db, GWEN_Buffer_GetStart(fbuf), GWEN_DB_FLAGS_DEFAULT);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "Error reading config file \"%s\" (%d)", AQHOME_SYSCONFIG_FILE, rv);
GWEN_Buffer_free(fbuf);
GWEN_DB_Group_free(db);
return NULL;
}
GWEN_Buffer_free(fbuf);
return db;
}
}
void AQH_MergeConfigFileIntoConfig(GWEN_DB_NODE *dbArgs, const char *destDbGroupName)
{
GWEN_DB_NODE *dbConfig;
dbConfig=AQH_LoadConfigFile();
if (dbConfig) {
GWEN_DB_GroupRename(dbConfig, destDbGroupName);
GWEN_DB_AddGroup(dbArgs, dbConfig);
}
}
int AQH_ValueType_fromString(const char *s)
{
if (s) {
if (strcasecmp(s, "sensor")==0)
return AQH_ValueType_Sensor;
else if (strcasecmp(s, "actor")==0)
return AQH_ValueType_Actor;
}
return AQH_ValueType_Unknown;
}
const char *AQH_ValueType_toString(int i)
{
switch (i) {
case AQH_ValueType_Sensor: return "sensor";
case AQH_ValueType_Actor: return "actor";
case AQH_ValueType_Unknown:
default: return "unknown";
}
}
int AQH_ValueDataType_fromString(const char *s)
{
if (s) {
if (strcasecmp(s, "int")==0)
return AQH_ValueDataType_Int;
else if (strcasecmp(s, "dword")==0)
return AQH_ValueDataType_Uint32;
else if (strcasecmp(s, "rational")==0)
return AQH_ValueDataType_Rational;
else if (strcasecmp(s, "uint8")==0)
return AQH_ValueDataType_Uint8;
else if (strcasecmp(s, "uint16")==0)
return AQH_ValueDataType_Uint16;
else if (strcasecmp(s, "uint32")==0)
return AQH_ValueDataType_Uint32;
}
return AQH_ValueDataType_Unknown;
}
const char *AQH_ValueDataType_toString(int i)
{
switch(i) {
case AQH_ValueDataType_Int: return "int";
case AQH_ValueDataType_Rational: return "rational";
case AQH_ValueDataType_Uint8: return "uint8";
case AQH_ValueDataType_Uint16: return "uint16";
case AQH_ValueDataType_Uint32: return "uint32";
case AQH_ValueDataType_Unknown:
default: return "unknown";
}
}
int AQH_ValueModality_fromString(const char *s)
{
if (s) {
if (strcasecmp(s, "temperature")==0)
return AQH_ValueModality_Temperature;
else if (strcasecmp(s, "humidity")==0)
return AQH_ValueModality_Humidity;
else if (strcasecmp(s, "door")==0)
return AQH_ValueModality_Door;
else if (strcasecmp(s, "rgb")==0)
return AQH_ValueModality_RGB;
else if (strcasecmp(s, "rgbw")==0)
return AQH_ValueModality_RGBW;
else if (strcasecmp(s, "motion")==0)
return AQH_ValueModality_Motion;
else if (strcasecmp(s, "co2")==0)
return AQH_ValueModality_Co2;
else if (strcasecmp(s, "tvoc")==0)
return AQH_ValueModality_TVOC;
else if (strcasecmp(s, "stats")==0)
return AQH_ValueModality_Stats;
else if (strcasecmp(s, "light")==0)
return AQH_ValueModality_Light;
else if (strcasecmp(s, "onOff")==0)
return AQH_ValueModality_OnOff;
else if (strcasecmp(s, "onOffAuto")==0)
return AQH_ValueModality_OnOffAuto;
}
return AQH_ValueModality_Unknown;
}
const char *AQH_ValueModality_toString(int i)
{
switch(i) {
case AQH_ValueModality_Temperature: return "temperature";
case AQH_ValueModality_Humidity: return "humidity";
case AQH_ValueModality_Door: return "door";
case AQH_ValueModality_RGB: return "rgb";
case AQH_ValueModality_RGBW: return "rgbw";
case AQH_ValueModality_Motion: return "motion";
case AQH_ValueModality_Co2: return "co2";
case AQH_ValueModality_TVOC: return "tvoc";
case AQH_ValueModality_Stats: return "stats";
case AQH_ValueModality_Light: return "light";
case AQH_ValueModality_OnOff: return "onOff";
case AQH_ValueModality_OnOffAuto: return "onOffAuto";
case AQH_ValueModality_Unknown:
default: return "unknown";
}
}
void _initLogging(void)
{
const char *s;
if (!GWEN_Logger_IsOpen(AQH_LOGDOMAIN))
GWEN_Logger_Open(AQH_LOGDOMAIN, "aqhome", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
s=getenv("AQHOME_LOGLEVEL");
if (s && *s) {
GWEN_LOGGER_LEVEL ll;
ll=GWEN_Logger_Name2Level(s);
GWEN_Logger_SetLevel(AQH_LOGDOMAIN, ll);
}
else
GWEN_Logger_SetLevel(AQH_LOGDOMAIN, GWEN_LoggerLevel_Notice);
}
void _finiLogging(void)
{
GWEN_Logger_Close(AQH_LOGDOMAIN);
}
void _initPathManager(void)
{
_definePath(AQHOME_PM_SYSCONFDIR, AQHOME_SYSCONF_DIR);
_definePath(AQHOME_PM_LOCALEDIR, AQHOME_SYSCONF_DIR);
_definePath(AQHOME_PM_DATADIR, AQHOME_DATA_DIR);
_definePath(AQHOME_PM_RTDATADIR, AQHOME_RTDATA_DIR);
}
void _finiPathManager(void)
{
GWEN_PathManager_UndefinePath(AQHOME_PM_LIBNAME, AQHOME_PM_LOCALEDIR);
GWEN_PathManager_UndefinePath(AQHOME_PM_LIBNAME, AQHOME_PM_RTDATADIR);
GWEN_PathManager_UndefinePath(AQHOME_PM_LIBNAME, AQHOME_PM_DATADIR);
GWEN_PathManager_UndefinePath(AQHOME_PM_LIBNAME, AQHOME_PM_SYSCONFDIR);
GWEN_PathManager_RemovePaths(AQHOME_PM_LIBNAME);
}
void _initI18n(void)
{
GWEN_STRINGLIST *sl;
sl=GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, AQHOME_PM_LOCALEDIR);
if (sl) {
const char *localedir;
int rv;
localedir=GWEN_StringList_FirstString(sl);
rv=GWEN_I18N_BindTextDomain_Dir(PACKAGE, localedir);
if (rv) {
DBG_ERROR(AQH_LOGDOMAIN, "Could not bind textdomain (%d)", rv);
}
else {
rv=GWEN_I18N_BindTextDomain_Codeset(PACKAGE, "UTF-8");
if (rv) {
DBG_ERROR(AQH_LOGDOMAIN, "Could not set codeset (%d)", rv);
}
}
GWEN_StringList_free(sl);
}
}
void _definePath(const char *pathName, const char *pathValue)
{
/* define sysconf paths */
GWEN_PathManager_DefinePath(AQHOME_PM_LIBNAME, pathName);
#if defined(OS_WIN32) || defined(ENABLE_LOCAL_INSTALL)
/* add folder relative to EXE */
GWEN_PathManager_AddRelPath(AQHOME_PM_LIBNAME, AQHOME_PM_LIBNAME, pathName, pathValue, GWEN_PathManager_RelModeExe);
#else
/* add absolute folder */
GWEN_PathManager_AddPath(AQHOME_PM_LIBNAME, AQHOME_PM_LIBNAME, pathName, pathValue);
#endif
}
GWEN_STRINGLIST *_getListOfMatchingFiles(const char *pathName, const char *subFolder, const char *mask)
{
int rv;
GWEN_STRINGLIST *sl;
sl=GWEN_StringList_new();
rv=GWEN_PathManager_GetMatchingFilesRecursively(AQHOME_PM_LIBNAME, pathName, subFolder, sl, mask);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN,
"Error listing matching data files (folder=%s, mask=%s)",
subFolder?subFolder:"<empty>", mask?mask:"<empty>");
GWEN_StringList_free(sl);
return NULL;
}
return sl;
}
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;
}
GWEN_BUFFER *_findFileinPath(const char *pathName, const char *sFilename)
{
GWEN_STRINGLIST *sl;
sl=GWEN_PathManager_GetPaths(AQHOME_PM_LIBNAME, pathName);
if (sl) {
int rv;
GWEN_BUFFER *buf;
buf=GWEN_Buffer_new(0, 256, 0, 1);
rv=GWEN_Directory_FindFileInPaths(sl, sFilename, buf);
GWEN_StringList_free(sl);
if (rv==0)
return buf;
GWEN_Buffer_free(buf);
}
return NULL;
}
int AQH_ReadDataFromDouble(int dataType, double d, uint16_t *pDataVal, uint16_t *pDataDenom)
{
switch(dataType) {
case AQH_ValueDataType_Uint8: return _readUint8DataFromDouble(d, pDataVal, pDataDenom);
case AQH_ValueDataType_Int:
case AQH_ValueDataType_Uint16: return _readUint16DataFromDouble(d, pDataVal, pDataDenom);
case AQH_ValueDataType_Uint32: return _readUint32DataFromDouble(d, pDataVal, pDataDenom);
case AQH_ValueDataType_Rational: break;
default: break;
}
return GWEN_ERROR_INVALID;
}
int _readUint8DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom)
{
uint8_t v;
v=((uint8_t) (d)) & 0xff;
*pDataVal=v & 0xff;
*pDataDenom=1;
return 0;
}
int _readUint16DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom)
{
uint16_t v;
v=((uint16_t) d) & 0xffff;
*pDataVal=v;
*pDataDenom=1;
return 0;
}
int _readUint32DataFromDouble(double d, uint16_t *pDataVal, uint16_t *pDataDenom)
{
uint32_t v;
v=((uint32_t) d) & 0xffffffff;
*pDataVal=(v>>16) & 0xffff;
*pDataDenom=v & 0xffff;
return 0;
}
int AQH_ReadDataFromString(int dataType, const char *s, uint16_t *pDataVal, uint16_t *pDataDenom)
{
if (s && *s) {
//DBG_ERROR(NULL, "Reading \"%s\" as datatype %d (%s)", s?s:"<NULL>", dataType, AQH_ValueDataType_toString(dataType));
switch(dataType) {
case AQH_ValueDataType_Uint8: return _readUint8DataFromString(s, pDataVal, pDataDenom);
case AQH_ValueDataType_Int:
case AQH_ValueDataType_Uint16: return _readUint16DataFromString(s, pDataVal, pDataDenom);
case AQH_ValueDataType_Uint32: return _readUint32DataFromString(s, pDataVal, pDataDenom);
case AQH_ValueDataType_Rational: break;
default: break;
}
}
return GWEN_ERROR_INVALID;
}
int _readUint8DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom)
{
int v=0;
if (1==sscanf(s, "%i", &v)) {
*pDataVal=v & 0xff;
*pDataDenom=1;
return 0;
}
return GWEN_ERROR_INVALID;
}
int _readUint16DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom)
{
int v=0;
if (1==sscanf(s, "%i", &v)) {
*pDataVal=v & 0xffff;
*pDataDenom=1;
return 0;
}
return GWEN_ERROR_INVALID;
}
int _readUint32DataFromString(const char *s, uint16_t *pDataVal, uint16_t *pDataDenom)
{
long int v=0;
if (1==sscanf(s, "%li", &v)) {
*pDataVal=(v>>16) & 0xffff;
*pDataDenom=v & 0xffff;
return 0;
}
return GWEN_ERROR_INVALID;
}