diff --git a/apps/aqhome-react/0BUILD b/apps/aqhome-react/0BUILD
index 0d3de92..4946776 100644
--- a/apps/aqhome-react/0BUILD
+++ b/apps/aqhome-react/0BUILD
@@ -68,6 +68,7 @@
types
units
+ networks
diff --git a/apps/aqhome-react/net_read.c b/apps/aqhome-react/net_read.c
index a5f201b..dadd6f7 100644
--- a/apps/aqhome-react/net_read.c
+++ b/apps/aqhome-react/net_read.c
@@ -32,12 +32,20 @@
* ------------------------------------------------------------------------------------------------
*/
-AQHREACT_UNIT_NET_LIST *_readUnitNetFiles(AQHOME_REACT *aqh, const GWEN_STRINGLIST *sl);
-static int _readUnitNetFileToList(AQHOME_REACT *aqh, const char *sFilename, AQHREACT_UNIT_NET_LIST *unitNetList);
+static AQHREACT_UNIT_NET_LIST *_readUnitNetFiles(AQHOME_REACT *aqh, const GWEN_STRINGLIST *sl);
+static int _readAllNetworksFromFileIntoList(AQHOME_REACT *aqh, const char *sFilename, AQHREACT_UNIT_NET_LIST *unitNetList);
+static GWEN_XMLNODE *_readNetworkFromSysconfIntoXml(AQHOME_REACT *aqh, const char *networkName);
static AQHREACT_UNIT_NET *_readUnitNetFromXml(AQHOME_REACT *aqh, GWEN_XMLNODE *unitNetNode);
+static GWEN_XMLNODE *_readUnitNetFileToXml(AQHOME_REACT *aqh, const char *sFilename);
+static void _readNetParamDefsWithList(AQHREACT_PARAM_LIST *paramList, GWEN_XMLNODE *unitNetNode);
+static int _readUnits(AQHOME_REACT *aqh, AQHREACT_UNIT_NET *unitNet, GWEN_XMLNODE *unitNetNode);
+static int _readLinks(AQHOME_REACT *aqh, AQHREACT_UNIT_NET *unitNet, GWEN_XMLNODE *unitNetNode);
static AQHREACT_UNIT *_readUnit(AQHOME_REACT *aqh, GWEN_XMLNODE *unitNode);
-static int _readParam(AQHREACT_UNIT *unit, GWEN_XMLNODE *n);
+static int _readParamValuesForList(const AQHREACT_PARAM_LIST *paramList, GWEN_XMLNODE *parentNode);
+static int _readParamValueForList(const AQHREACT_PARAM_LIST *paramList, GWEN_XMLNODE *paramNode);
+static AQHREACT_PARAM *_readNetParamDef(GWEN_XMLNODE *paramNode);
static int _readLink(AQHOME_REACT *aqh, AQHREACT_UNIT_NET *unitNet, GWEN_XMLNODE *linkNode);
+static int _setParamDoubleValueFromString(AQHREACT_PARAM *param, const char *s);
@@ -111,6 +119,37 @@ AQHREACT_UNIT_NET_LIST *AQHREACT_ReadUnitNetFiles(AQHOME_REACT *aqh)
+GWEN_XMLNODE *_readNetworkFromSysconfIntoXml(AQHOME_REACT *aqh, const char *networkName)
+{
+ GWEN_XMLNODE *n;
+ GWEN_BUFFER *bufFilename;
+ GWEN_BUFFER *bufPath;
+
+ bufFilename=GWEN_Buffer_new(0, 256, 0, 1);
+ GWEN_Buffer_AppendString(bufFilename, "aqhome/react/networks/");
+ GWEN_Buffer_AppendString(bufFilename, networkName);
+ GWEN_Buffer_AppendString(bufFilename, ".xml");
+
+ bufPath=AQH_FindPathOfSysconfFile(GWEN_Buffer_GetStart(bufFilename));
+ if (bufPath==NULL) {
+ DBG_ERROR(NULL, "Network file \"%s\" not found in sysconf folders", GWEN_Buffer_GetStart(bufFilename));
+ GWEN_Buffer_free(bufFilename);
+ return NULL;
+ }
+ GWEN_Buffer_free(bufFilename);
+
+ n=_readUnitNetFileToXml(aqh, GWEN_Buffer_GetStart(bufPath));
+ if (n==NULL) {
+ DBG_ERROR(NULL, "Error reading network file \"%s\" from sysconf dir", GWEN_Buffer_GetStart(bufPath));
+ GWEN_Buffer_free(bufPath);
+ return NULL;
+ }
+ GWEN_Buffer_free(bufPath);
+ return n;
+}
+
+
+
AQHREACT_UNIT_NET_LIST *_readUnitNetFiles(AQHOME_REACT *aqh, const GWEN_STRINGLIST *sl)
{
GWEN_STRINGLISTENTRY *se;
@@ -126,7 +165,7 @@ AQHREACT_UNIT_NET_LIST *_readUnitNetFiles(AQHOME_REACT *aqh, const GWEN_STRINGLI
int rv;
DBG_INFO(NULL, "Reading unit network file \"%s\"", s);
- rv=_readUnitNetFileToList(aqh, s, unitNetList);
+ rv=_readAllNetworksFromFileIntoList(aqh, s, unitNetList);
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
DBG_WARN(NULL, "Error reading unit network file \"%s\" (%d), ignoring", s, rv);
}
@@ -144,7 +183,7 @@ AQHREACT_UNIT_NET_LIST *_readUnitNetFiles(AQHOME_REACT *aqh, const GWEN_STRINGLI
-int _readUnitNetFileToList(AQHOME_REACT *aqh, const char *sFilename, AQHREACT_UNIT_NET_LIST *unitNetList)
+int _readAllNetworksFromFileIntoList(AQHOME_REACT *aqh, const char *sFilename, AQHREACT_UNIT_NET_LIST *unitNetList)
{
GWEN_XMLNODE *rootNode;
GWEN_XMLNODE *netListNode;
@@ -185,12 +224,108 @@ AQHREACT_UNIT_NET *_readUnitNetFromXml(AQHOME_REACT *aqh, GWEN_XMLNODE *unitNetN
{
AQHREACT_UNIT_NET *unitNet;
const char *s;
- GWEN_XMLNODE *nGroup;
+ int rv;
unitNet=AQHREACT_UnitNet_new();
s=GWEN_XMLNode_GetProperty(unitNetNode, "id", NULL);
AQHREACT_UnitNet_SetName(unitNet, s);
+ s=GWEN_XMLNode_GetProperty(unitNetNode, "type", NULL);
+ if (s && *s) {
+ GWEN_XMLNODE *baseNetXml;
+
+ /* uses a template file, load that and only set params from non-template file */
+ DBG_INFO(NULL, "Loading base network \"%s\"", s);
+ baseNetXml=_readNetworkFromSysconfIntoXml(aqh, s);
+ if (baseNetXml==NULL) {
+ DBG_ERROR(NULL, "Base network \"%s\" not available (error or missing)", s);
+ AQHREACT_UnitNet_free(unitNet);
+ return NULL;
+ }
+ _readNetParamDefsWithList(AQHREACT_UnitNet_GetParamList(unitNet), baseNetXml);
+
+ /* also read netParams from this file (after reading from template) */
+ rv=_readParamValuesForList(AQHREACT_UnitNet_GetParamList(unitNet), unitNetNode);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ AQHREACT_UnitNet_free(unitNet);
+ GWEN_XMLNode_free(baseNetXml);
+ return NULL;
+ }
+
+ rv=_readUnits(aqh, unitNet, baseNetXml);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ AQHREACT_UnitNet_free(unitNet);
+ GWEN_XMLNode_free(baseNetXml);
+ return NULL;
+ }
+
+ rv=_readLinks(aqh, unitNet, baseNetXml);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ AQHREACT_UnitNet_free(unitNet);
+ GWEN_XMLNode_free(baseNetXml);
+ return NULL;
+ }
+ GWEN_XMLNode_free(baseNetXml);
+ }
+ else {
+ /* just directly read network from given XML node (no need to load a template file) */
+ _readNetParamDefsWithList(AQHREACT_UnitNet_GetParamList(unitNet), unitNetNode);
+
+ rv=_readUnits(aqh, unitNet, unitNetNode);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ AQHREACT_UnitNet_free(unitNet);
+ return NULL;
+ }
+
+ rv=_readLinks(aqh, unitNet, unitNetNode);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ AQHREACT_UnitNet_free(unitNet);
+ return NULL;
+ }
+ }
+
+ return unitNet;
+}
+
+
+
+GWEN_XMLNODE *_readUnitNetFileToXml(AQHOME_REACT *aqh, const char *sFilename)
+{
+ GWEN_XMLNODE *rootNode;
+ GWEN_XMLNODE *netNode;
+ int rv;
+
+ rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
+ rv=GWEN_XML_ReadFile(rootNode, sFilename, GWEN_XML_FLAGS_DEFAULT);
+ if (rv<0) {
+ DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv);
+ GWEN_XMLNode_free(rootNode);
+ return NULL;
+ }
+
+ netNode=GWEN_XMLNode_FindFirstTag(rootNode, "network", NULL, NULL);
+ if (netNode) {
+ GWEN_XMLNode_UnlinkChild(rootNode, netNode);
+ GWEN_XMLNode_free(rootNode);
+ return netNode;
+ }
+ else {
+ DBG_ERROR(NULL, "No \"network\" element in network file \"%s\"", sFilename);
+ return NULL;
+ }
+}
+
+
+
+int _readUnits(AQHOME_REACT *aqh, AQHREACT_UNIT_NET *unitNet, GWEN_XMLNODE *unitNetNode)
+{
+ GWEN_XMLNODE *nGroup;
+
nGroup=GWEN_XMLNode_FindFirstTag(unitNetNode, "units", NULL, NULL);
if (nGroup) {
GWEN_XMLNODE *n;
@@ -204,13 +339,21 @@ AQHREACT_UNIT_NET *_readUnitNetFromXml(AQHOME_REACT *aqh, GWEN_XMLNODE *unitNetN
AQHREACT_UnitNet_AddUnit(unitNet, unit);
else {
DBG_ERROR(NULL, "Error reading unit in net \"%s\"", AQHREACT_UnitNet_GetName(unitNet));
- AQHREACT_UnitNet_free(unitNet);
- return NULL;
+ return GWEN_ERROR_BAD_DATA;
}
n=GWEN_XMLNode_FindNextTag(n, "unit", NULL, NULL);
}
}
+ return 0;
+}
+
+
+
+int _readLinks(AQHOME_REACT *aqh, AQHREACT_UNIT_NET *unitNet, GWEN_XMLNODE *unitNetNode)
+{
+ GWEN_XMLNODE *nGroup;
+
nGroup=GWEN_XMLNode_FindFirstTag(unitNetNode, "links", NULL, NULL);
if (nGroup) {
GWEN_XMLNODE *n;
@@ -222,25 +365,22 @@ AQHREACT_UNIT_NET *_readUnitNetFromXml(AQHOME_REACT *aqh, GWEN_XMLNODE *unitNetN
rv=_readLink(aqh, unitNet, n);
if (rv<0) {
DBG_ERROR(NULL, "Error reading link in net \"%s\" (%d)", AQHREACT_UnitNet_GetName(unitNet), rv);
- AQHREACT_UnitNet_free(unitNet);
- return NULL;
+ return GWEN_ERROR_BAD_DATA;
}
n=GWEN_XMLNode_FindNextTag(n, "link", NULL, NULL);
}
}
-
- return unitNet;
+ return 0;
}
-
AQHREACT_UNIT *_readUnit(AQHOME_REACT *aqh, GWEN_XMLNODE *unitNode)
{
AQHREACT_UNIT *unit;
const char *unitType;
const char *unitId;
- GWEN_XMLNODE *nGroup;
+ int rv;
unitType=GWEN_XMLNode_GetProperty(unitNode, "type", NULL);
if (!(unitType && *unitType)) {
@@ -252,22 +392,11 @@ AQHREACT_UNIT *_readUnit(AQHOME_REACT *aqh, GWEN_XMLNODE *unitNode)
unitId=GWEN_XMLNode_GetProperty(unitNode, "id", NULL);
AQHREACT_Unit_SetId(unit, unitId);
- nGroup=GWEN_XMLNode_FindFirstTag(unitNode, "params", NULL, NULL);
- if (nGroup) {
- GWEN_XMLNODE *n;
-
- n=GWEN_XMLNode_FindFirstTag(nGroup, "param", NULL, NULL);
- while(n) {
- int rv;
-
- rv=_readParam(unit, n);
- if (rv<0) {
- DBG_INFO(NULL, "here (%d)", rv);
- AQHREACT_Unit_free(unit);
- return NULL;
- }
- n=GWEN_XMLNode_FindNextTag(n, "param", NULL, NULL);
- }
+ rv=_readParamValuesForList(AQHREACT_Unit_GetParamList(unit), unitNode);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ AQHREACT_Unit_free(unit);
+ return NULL;
}
return unit;
@@ -275,7 +404,32 @@ AQHREACT_UNIT *_readUnit(AQHOME_REACT *aqh, GWEN_XMLNODE *unitNode)
-int _readParam(AQHREACT_UNIT *unit, GWEN_XMLNODE *paramNode)
+int _readParamValuesForList(const AQHREACT_PARAM_LIST *paramList, GWEN_XMLNODE *parentNode)
+{
+ GWEN_XMLNODE *nGroup;
+
+ nGroup=GWEN_XMLNode_FindFirstTag(parentNode, "params", NULL, NULL);
+ if (nGroup) {
+ GWEN_XMLNODE *n;
+
+ n=GWEN_XMLNode_FindFirstTag(nGroup, "param", NULL, NULL);
+ while(n) {
+ int rv;
+
+ rv=_readParamValueForList(paramList, n);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ return rv;
+ }
+ n=GWEN_XMLNode_FindNextTag(n, "param", NULL, NULL);
+ }
+ }
+ return 0;
+}
+
+
+
+int _readParamValueForList(const AQHREACT_PARAM_LIST *paramList, GWEN_XMLNODE *paramNode)
{
const char *paramName;
@@ -283,7 +437,7 @@ int _readParam(AQHREACT_UNIT *unit, GWEN_XMLNODE *paramNode)
if (paramName && *paramName) {
AQHREACT_PARAM *param;
- param=AQHREACT_Unit_GetParamByName(unit, paramName);
+ param=AQHREACT_Param_List_GetParamByName(paramList, paramName);
if (param) {
const char *value;
@@ -300,7 +454,7 @@ int _readParam(AQHREACT_UNIT *unit, GWEN_XMLNODE *paramNode)
rv=GWEN_Text_StringToDouble(value, &valueAsDouble);
if (rv<0) {
- DBG_ERROR(NULL, "Not a DOUBLE value for param %s in unit %s [%s]", paramName, AQHREACT_Unit_GetId(unit), value);
+ DBG_ERROR(NULL, "Not a DOUBLE value for param %s in list [%s]", paramName, value);
return rv;
}
AQHREACT_Param_SetDoubleValue(param, valueAsDouble);
@@ -314,7 +468,7 @@ int _readParam(AQHREACT_UNIT *unit, GWEN_XMLNODE *paramNode)
}
}
else {
- DBG_ERROR(NULL, "No param name \"%s\" in unit %s", paramName, AQHREACT_Unit_GetId(unit));
+ DBG_ERROR(NULL, "No param name \"%s\" in list", paramName);
return GWEN_ERROR_BAD_DATA;
}
}
@@ -324,6 +478,100 @@ int _readParam(AQHREACT_UNIT *unit, GWEN_XMLNODE *paramNode)
+void _readNetParamDefsWithList(AQHREACT_PARAM_LIST *paramList, GWEN_XMLNODE *unitNetNode)
+{
+ GWEN_XMLNODE *nGroup;
+
+ nGroup=GWEN_XMLNode_FindFirstTag(unitNetNode, "params", NULL, NULL);
+ if (nGroup) {
+ GWEN_XMLNODE *n;
+
+ n=GWEN_XMLNode_FindFirstTag(nGroup, "param", NULL, NULL);
+ while(n) {
+ AQHREACT_PARAM *param;
+
+ param=_readNetParamDef(n);
+ if (param)
+ AQHREACT_Param_List_Add(param, paramList);
+ n=GWEN_XMLNode_FindNextTag(n, "param", NULL, NULL);
+ }
+ }
+}
+
+
+
+AQHREACT_PARAM *_readNetParamDef(GWEN_XMLNODE *paramNode)
+{
+ const char *paramName;
+ const char *paramType;
+ const char *paramValue;
+
+ paramName=GWEN_XMLNode_GetProperty(paramNode, "name", NULL);
+ paramType=GWEN_XMLNode_GetProperty(paramNode, "type", "string");
+ paramValue=GWEN_XMLNode_GetCharValue(paramNode, NULL, NULL);
+
+ if (paramName && *paramName) {
+ int t=AQHREACT_DATAOBJECTTYPE_STRING;
+ AQHREACT_PARAM *param;
+
+ if (paramType) {
+ if (strcasecmp(paramType, "string")==0)
+ t=AQHREACT_DATAOBJECTTYPE_STRING;
+ else if (strcasecmp(paramType, "double")==0)
+ t=AQHREACT_DATAOBJECTTYPE_DOUBLE;
+ else {
+ DBG_ERROR(NULL, "Invalid data type in parameter (%s), assuming string", paramType);
+ t=AQHREACT_DATAOBJECTTYPE_STRING;
+ }
+ }
+
+ param=AQHREACT_Param_new();
+ AQHREACT_Param_SetName(param, paramName);
+ AQHREACT_Param_SetDataType(param, t);
+ if (paramValue && *paramValue) {
+ int rv;
+
+ switch(t) {
+ case AQHREACT_DATAOBJECTTYPE_STRING:
+ AQHREACT_Param_SetStringValue(param, paramValue);
+ break;
+ case AQHREACT_DATAOBJECTTYPE_DOUBLE:
+ rv=_setParamDoubleValueFromString(param, paramValue);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ AQHREACT_Param_free(param);
+ return NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return param;
+ }
+
+ return NULL;
+}
+
+
+
+int _setParamDoubleValueFromString(AQHREACT_PARAM *param, const char *s)
+{
+ int rv;
+ double value;
+
+ rv=GWEN_Text_StringToDouble(s, &value);
+ if (rv<0) {
+ DBG_INFO(NULL, "here (%d)", rv);
+ return rv;
+ }
+ AQHREACT_Param_SetDoubleValue(param, value);
+ return 0;
+}
+
+
+
int _readLink(AQHOME_REACT *aqh, AQHREACT_UNIT_NET *unitNet, GWEN_XMLNODE *linkNode)
{
const char *sourceUnitName;
diff --git a/apps/aqhome-react/networks/0BUILD b/apps/aqhome-react/networks/0BUILD
new file mode 100644
index 0000000..f5f1467
--- /dev/null
+++ b/apps/aqhome-react/networks/0BUILD
@@ -0,0 +1,8 @@
+
+
+
+
+ tvlight.xml
+
+
+
diff --git a/apps/aqhome-react/networks/tvlight.xml b/apps/aqhome-react/networks/tvlight.xml
new file mode 100644
index 0000000..05522aa
--- /dev/null
+++ b/apps/aqhome-react/networks/tvlight.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+ 30
+ 70
+
+
+
+
+
+
+ $(inPlugValue)
+
+
+
+
+
+
+ $(threshold)
+
+
+
+
+
+
+ $(outPlugValue)
+
+
+
+
+
+
+ OFF
+ OFF
+ ON
+
+
+
+
+
+
+ $(delayTime)
+ 0.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/aqhome-react/types/param.c b/apps/aqhome-react/types/param.c
index e9e2815..2b7f84a 100644
--- a/apps/aqhome-react/types/param.c
+++ b/apps/aqhome-react/types/param.c
@@ -157,6 +157,26 @@ void AQHREACT_Param_SubFlags(AQHREACT_PARAM *param, uint32_t f)
+AQHREACT_PARAM *AQHREACT_Param_List_GetParamByName(const AQHREACT_PARAM_LIST *paramList, const char *paramName)
+{
+ if (paramList && paramName && *paramName) {
+ AQHREACT_PARAM *param;
+
+ param=AQHREACT_Param_List_First(paramList);
+ while(param) {
+ const char *s;
+
+ s=AQHREACT_Param_GetName(param);
+ if (s && *s && strcasecmp(paramName, s)==0)
+ return param;
+ param=AQHREACT_Param_List_Next(param);
+ }
+ }
+ return NULL;
+}
+
+
+
diff --git a/apps/aqhome-react/types/param.h b/apps/aqhome-react/types/param.h
index a0dc30a..0a04714 100644
--- a/apps/aqhome-react/types/param.h
+++ b/apps/aqhome-react/types/param.h
@@ -42,6 +42,7 @@ void AQHREACT_Param_SetFlags(AQHREACT_PARAM *param, uint32_t f);
void AQHREACT_Param_AddFlags(AQHREACT_PARAM *param, uint32_t f);
void AQHREACT_Param_SubFlags(AQHREACT_PARAM *param, uint32_t f);
+AQHREACT_PARAM *AQHREACT_Param_List_GetParamByName(const AQHREACT_PARAM_LIST *paramList, const char *paramName);
#endif
diff --git a/apps/aqhome-react/types/unitnet.c b/apps/aqhome-react/types/unitnet.c
index 4e5c0ca..40131d9 100644
--- a/apps/aqhome-react/types/unitnet.c
+++ b/apps/aqhome-react/types/unitnet.c
@@ -28,6 +28,7 @@ AQHREACT_UNIT_NET *AQHREACT_UnitNet_new(void)
GWEN_LIST_INIT(AQHREACT_UNIT_NET, unitNet);
unitNet->unitList=AQHREACT_Unit_List_new();
+ unitNet->paramList=AQHREACT_Param_List_new();
return unitNet;
}
@@ -38,6 +39,7 @@ void AQHREACT_UnitNet_free(AQHREACT_UNIT_NET *unitNet)
{
if (unitNet) {
GWEN_LIST_FINI(AQHREACT_UNIT_NET, unitNet);
+ AQHREACT_Param_List_free(unitNet->paramList);
AQHREACT_Unit_List_free(unitNet->unitList);
GWEN_FREE_OBJECT(unitNet);
}
@@ -84,6 +86,41 @@ void AQHREACT_UnitNet_AddUnit(AQHREACT_UNIT_NET *unitNet, AQHREACT_UNIT *unit)
+AQHREACT_PARAM_LIST *AQHREACT_UnitNet_GetParamList(const AQHREACT_UNIT_NET *unitNet)
+{
+ return unitNet?unitNet->paramList:NULL;
+}
+
+
+
+void AQHREACT_UnitNet_AddParam(AQHREACT_UNIT_NET *unitNet, AQHREACT_PARAM *param)
+{
+ if (unitNet)
+ AQHREACT_Param_List_Add(param, unitNet->paramList);
+}
+
+
+
+AQHREACT_PARAM *AQHREACT_UnitNet_GetParamByName(const AQHREACT_UNIT_NET *unitNet, const char *paramName)
+{
+ if (unitNet && unitNet->paramList && paramName && *paramName) {
+ AQHREACT_PARAM *param;
+
+ param=AQHREACT_Param_List_First(unitNet->paramList);
+ while(param) {
+ const char *s;
+
+ s=AQHREACT_Param_GetName(param);
+ if (s && *s && strcasecmp(paramName, s)==0)
+ return param;
+ param=AQHREACT_Param_List_Next(param);
+ }
+ }
+ return NULL;
+}
+
+
+
AQHREACT_UNIT_NET *AQHREACT_UnitNet_List_GetByName(const AQHREACT_UNIT_NET_LIST *unitNetList, const char *name)
{
if (unitNetList && name && *name) {
diff --git a/apps/aqhome-react/types/unitnet.h b/apps/aqhome-react/types/unitnet.h
index 8657912..13d8105 100644
--- a/apps/aqhome-react/types/unitnet.h
+++ b/apps/aqhome-react/types/unitnet.h
@@ -18,6 +18,7 @@ GWEN_LIST_FUNCTION_DEFS(AQHREACT_UNIT_NET, AQHREACT_UnitNet)
#include "aqhome-react/aqhome_react.h"
+#include "aqhome-react/types/param.h"
AQHREACT_UNIT_NET *AQHREACT_UnitNet_new(void);
@@ -30,6 +31,11 @@ AQHREACT_UNIT_LIST *AQHREACT_UnitNet_GetUnitList(const AQHREACT_UNIT_NET *unitNe
AQHREACT_UNIT *AQHREACT_UnitNet_GetUnitById(const AQHREACT_UNIT_NET *unitNet, const char *s);
void AQHREACT_UnitNet_AddUnit(AQHREACT_UNIT_NET *unitNet, AQHREACT_UNIT *unit);
+AQHREACT_PARAM_LIST *AQHREACT_UnitNet_GetParamList(const AQHREACT_UNIT_NET *unitNet);
+void AQHREACT_UnitNet_AddParam(AQHREACT_UNIT_NET *unitNet, AQHREACT_PARAM *param);
+AQHREACT_PARAM *AQHREACT_UnitNet_GetParamByName(const AQHREACT_UNIT_NET *unitNet, const char *paramName);
+
+
AQHREACT_UNIT_NET *AQHREACT_UnitNet_List_GetByName(const AQHREACT_UNIT_NET_LIST *unitNetList, const char *name);
diff --git a/apps/aqhome-react/types/unitnet_p.h b/apps/aqhome-react/types/unitnet_p.h
index 57d7d8b..5cfe3cd 100644
--- a/apps/aqhome-react/types/unitnet_p.h
+++ b/apps/aqhome-react/types/unitnet_p.h
@@ -18,6 +18,7 @@ struct AQHREACT_UNIT_NET {
char *name;
AQHREACT_UNIT_LIST *unitList;
+ AQHREACT_PARAM_LIST *paramList;
};
diff --git a/apps/aqhome-react/units/0BUILD b/apps/aqhome-react/units/0BUILD
index a5e3813..5c9148c 100644
--- a/apps/aqhome-react/units/0BUILD
+++ b/apps/aqhome-react/units/0BUILD
@@ -45,6 +45,8 @@
u_lowpass.h
u_highpass.h
u_stabilize.h
+ u_valueset.h
+ u_zeroposnegstring.h
@@ -57,6 +59,8 @@
u_lowpass.c
u_highpass.c
u_stabilize.c
+ u_valueset.c
+ u_zeroposnegstring.c
diff --git a/apps/aqhome-react/units/u_valueset.c b/apps/aqhome-react/units/u_valueset.c
new file mode 100644
index 0000000..0d7169f
--- /dev/null
+++ b/apps/aqhome-react/units/u_valueset.c
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * 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
+#endif
+
+#include "./u_valueset.h"
+
+#include
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * defines
+ * ------------------------------------------------------------------------------------------------
+ */
+
+#define AQHOMEREACT_UNIT_VALUESET_INSLOT_VALUE 0
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * forward declarations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject);
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * implementations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+AQHREACT_UNIT *AqHomeReact_UnitValueSet_new(AQHOME_REACT *aqh)
+{
+ AQHREACT_UNIT *unit;
+ AQHREACT_INPUT_SLOT *inputSlot;
+ AQHREACT_PARAM *param;
+
+ unit=AQHREACT_Unit_new(aqh);
+ AQHREACT_Unit_SetName(unit, "valueset");
+ AQHREACT_Unit_SetDescription(unit, "Set value by value path");
+ AQHREACT_Unit_SetInputDataFn(unit, _cbInputData);
+
+ inputSlot=AQHREACT_InputSlot_new();
+ AQHREACT_InputSlot_SetName(inputSlot, "input");
+ AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_VALUESET_INSLOT_VALUE);
+ AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_STRING);
+ AQHREACT_Unit_AddInputSlot(unit, inputSlot);
+
+ param=AQHREACT_Param_new();
+ AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUENAME);
+ AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_STRING);
+ AQHREACT_Unit_AddParam(unit, param);
+
+ return unit;
+}
+
+
+
+void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject)
+{
+ if (unit && dataObject && slotIdForUnit==AQHOMEREACT_UNIT_VALUESET_INSLOT_VALUE) {
+ const char *sSystemValueId;
+
+ sSystemValueId=AQHREACT_DataObject_GetSystemValueId(dataObject);
+ if (sSystemValueId && *sSystemValueId) {
+ const char *sValueName;
+
+ sValueName=AQHREACT_Unit_GetParamValueString(unit, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUENAME, NULL);
+ if (sValueName && *sValueName) {
+ // TODO: set value
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/apps/aqhome-react/units/u_valueset.h b/apps/aqhome-react/units/u_valueset.h
new file mode 100644
index 0000000..3cef416
--- /dev/null
+++ b/apps/aqhome-react/units/u_valueset.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+ * 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 AQHOMEREACT_U_VALUESET_H
+#define AQHOMEREACT_U_VALUESET_H
+
+
+#include "aqhome-react/aqhome_react.h"
+#include "aqhome-react/types/unit.h"
+
+
+#define AQHOMEREACT_UNIT_VALUESET_PARAM_VALUENAME "valueName"
+
+
+AQHREACT_UNIT *AqHomeReact_UnitValueSet_new(AQHOME_REACT *aqh);
+
+
+
+#endif
+
+
diff --git a/apps/aqhome-react/units/u_zeroposnegstring.c b/apps/aqhome-react/units/u_zeroposnegstring.c
new file mode 100644
index 0000000..f41dd6c
--- /dev/null
+++ b/apps/aqhome-react/units/u_zeroposnegstring.c
@@ -0,0 +1,119 @@
+/****************************************************************************
+ * 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
+#endif
+
+#include "./u_zeroposnegstring.h"
+
+#include
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * defines
+ * ------------------------------------------------------------------------------------------------
+ */
+
+#define AQHOMEREACT_UNIT_ZEROPOSNEGSTRING_INSLOT_VALUE 0
+
+#define AQHOMEREACT_UNIT_ZEROPOSNEGSTRING_OUTSLOT_RESULT 0
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * forward declarations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject);
+
+
+
+/* ------------------------------------------------------------------------------------------------
+ * implementations
+ * ------------------------------------------------------------------------------------------------
+ */
+
+AQHREACT_UNIT *AqHomeReact_UnitZeroPosNegString_new(AQHOME_REACT *aqh)
+{
+ AQHREACT_UNIT *unit;
+ AQHREACT_OUTPUT_SLOT *outputSlot;
+ AQHREACT_INPUT_SLOT *inputSlot;
+ AQHREACT_PARAM *param;
+
+ unit=AQHREACT_Unit_new(aqh);
+ AQHREACT_Unit_SetName(unit, "zeroPosNegString");
+ AQHREACT_Unit_SetDescription(unit, "Translate double value into strings for zero, positive, negative values");
+ AQHREACT_Unit_SetInputDataFn(unit, _cbInputData);
+
+ outputSlot=AQHREACT_OutputSlot_new();
+ AQHREACT_OutputSlot_SetName(outputSlot, "output");
+ AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_ZEROPOSNEGSTRING_OUTSLOT_RESULT);
+ AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_STRING);
+ AQHREACT_Unit_AddOutputSlot(unit, outputSlot);
+
+ inputSlot=AQHREACT_InputSlot_new();
+ AQHREACT_InputSlot_SetName(inputSlot, "input");
+ AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_ZEROPOSNEGSTRING_INSLOT_VALUE);
+ AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE);
+ AQHREACT_Unit_AddInputSlot(unit, inputSlot);
+
+ param=AQHREACT_Param_new();
+ AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_NEG);
+ AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_STRING);
+ AQHREACT_Unit_AddParam(unit, param);
+
+ param=AQHREACT_Param_new();
+ AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_POS);
+ AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_STRING);
+ AQHREACT_Unit_AddParam(unit, param);
+
+ param=AQHREACT_Param_new();
+ AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_ZERO);
+ AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_STRING);
+ AQHREACT_Unit_AddParam(unit, param);
+
+ return unit;
+}
+
+
+
+void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject)
+{
+ if (unit && dataObject) {
+ const char *result=NULL;
+ const AQHREACT_INPUT_SLOT *inputSlot;
+
+ inputSlot=AQHREACT_Unit_GetInputSlotByIdForUnit(unit, slotIdForUnit);
+ if (inputSlot) {
+ AQHREACT_DATAOBJECT *dataObject;
+
+ dataObject=AQHREACT_InputSlot_GetCurrentDataObject(inputSlot);
+ if (dataObject) {
+ double data;
+
+ data=AQHREACT_DataObject_GetDoubleData(dataObject);
+ if (data>0.0)
+ result=AQHREACT_Unit_GetParamValueString(unit, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_POS, NULL);
+ else if (data<0.0)
+ result=AQHREACT_Unit_GetParamValueString(unit, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_NEG, NULL);
+ else
+ result=AQHREACT_Unit_GetParamValueString(unit, AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_ZERO, NULL);
+ }
+ }
+
+ if (result && *result)
+ AQHREACT_Unit_OutputStringData(unit, AQHOMEREACT_UNIT_ZEROPOSNEGSTRING_OUTSLOT_RESULT, result);
+ }
+}
+
+
+
+
diff --git a/apps/aqhome-react/units/u_zeroposnegstring.h b/apps/aqhome-react/units/u_zeroposnegstring.h
new file mode 100644
index 0000000..d635cfa
--- /dev/null
+++ b/apps/aqhome-react/units/u_zeroposnegstring.h
@@ -0,0 +1,28 @@
+/****************************************************************************
+ * 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 AQHOMEREACT_U_ZEROPOSNEGSTRING_H
+#define AQHOMEREACT_U_ZEROPOSNEGSTRING_H
+
+
+#include "aqhome-react/aqhome_react.h"
+#include "aqhome-react/types/unit.h"
+
+
+#define AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_NEG "valueIfNegative"
+#define AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_POS "valueIfPositive"
+#define AQHOMEREACT_UNIT_VALUESET_PARAM_VALUE_ZERO "valueIfZero"
+
+
+AQHREACT_UNIT *AqHomeReact_UnitZeroPosNegString_new(AQHOME_REACT *aqh);
+
+
+
+#endif
+
+
diff --git a/aqhome/aqhome.c b/aqhome/aqhome.c
index bba13cd..ff1814f 100644
--- a/aqhome/aqhome.c
+++ b/aqhome/aqhome.c
@@ -18,6 +18,7 @@
#include
#include
#include
+#include
#include
@@ -41,6 +42,7 @@ 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);
@@ -115,6 +117,20 @@ GWEN_BUFFER *AQH_GetRuntimeFilePath(const char *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_DB_NODE *AQH_LoadConfigFile(void)
{
@@ -306,3 +322,24 @@ GWEN_BUFFER *_getRuntimeFilePath(const char *pathName, const char *sFilename)
+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;
+}
+
+
+
diff --git a/aqhome/aqhome.h b/aqhome/aqhome.h
index 99f9c60..dbeb4b1 100644
--- a/aqhome/aqhome.h
+++ b/aqhome/aqhome.h
@@ -30,6 +30,10 @@ AQHOME_API GWEN_STRINGLIST *AQH_GetListOfMatchingSysconfFiles(const char *subFol
AQHOME_API GWEN_BUFFER *AQH_GetRuntimeFilePath(const char *sFilename);
+AQHOME_API GWEN_BUFFER *AQH_FindPathOfRuntimeFile(const char *sFilename);
+AQHOME_API GWEN_BUFFER *AQH_FindPathOfSysconfFile(const char *sFilename);
+
+
AQHOME_API GWEN_STRINGLIST *AQH_GetGlobalDataDirs(void);
AQHOME_API GWEN_STRINGLIST *AQH_GetGlobalSysconfDirs(void);