diff --git a/apps/aqhome-react/aqhome_react.c b/apps/aqhome-react/aqhome_react.c index f615349..f5ebf0b 100644 --- a/apps/aqhome-react/aqhome_react.c +++ b/apps/aqhome-react/aqhome_react.c @@ -11,6 +11,10 @@ #endif #include "./aqhome_react_p.h" +#include "aqhome-react/units/u_or.h" +#include "aqhome-react/units/u_valuefilter.h" +#include "aqhome-react/units/u_hold.h" + #include #include @@ -22,6 +26,8 @@ AQHOME_REACT *AqHomeReact_new() AQHOME_REACT *aqh; GWEN_NEW_OBJECT(AQHOME_REACT, aqh); + aqh->unitNetList=AQHREACT_UnitNet_List_new(); + aqh->unitList=AQHREACT_Unit_List_new(); return aqh; } @@ -31,6 +37,8 @@ AQHOME_REACT *AqHomeReact_new() void AqHomeReact_free(AQHOME_REACT *aqh) { if (aqh) { + AQHREACT_UnitNet_List_free(aqh->unitNetList); + AQHREACT_Unit_List_free(aqh->unitList); GWEN_MsgEndpoint_free(aqh->brokerEndpoint); GWEN_DB_Group_free(aqh->dbArgs); free(aqh->pidFile); @@ -80,6 +88,103 @@ int AqHomeReact_GetTimeout(const AQHOME_REACT *aqh) +AQHREACT_UNIT *AqHomeReact_GetTimerUnit(const AQHOME_REACT *aqh) +{ + return aqh?aqh->timerUnit:NULL; +} + + + +AQHREACT_UNIT *AqHomeReact_GetVarChangeUnit(const AQHOME_REACT *aqh) +{ + return aqh?aqh->varChangeUnit:NULL; +} + + + +AQHREACT_UNIT_NET_LIST *AqHomeReact_GetUnitNetList(const AQHOME_REACT *aqh) +{ + return aqh?aqh->unitNetList:NULL; +} + + + +void AqHomeReact_AddUnitNet(AQHOME_REACT *aqh, AQHREACT_UNIT_NET *unitNet) +{ + if (aqh) + AQHREACT_UnitNet_List_Add(unitNet, aqh->unitNetList); +} + + + +AQHREACT_UNIT_NET *AqHomeReact_GetUnitNetByName(const AQHOME_REACT *aqh, const char *s) +{ + return (aqh && s && *s)?AQHREACT_UnitNet_List_GetByName(aqh->unitNetList, s):NULL; +} + + + +AQHREACT_UNIT *AqHomeReact_FindUnitByNetNameAndUnitId(const AQHOME_REACT *aqh, const char *netName, const char *unitId) +{ + if (aqh && unitId && *unitId) { + AQHREACT_UNIT_LIST *unitList=NULL; + + if (netName && *netName) { + AQHREACT_UNIT_NET *unitNet; + + unitNet=AQHREACT_UnitNet_List_GetByName(aqh->unitNetList, netName); + if (unitNet) + unitList=AQHREACT_UnitNet_GetUnitList(unitNet); + else { + DBG_ERROR(NULL, "Unit net \"%s\" not found", netName); + return NULL; + } + } + else + unitList=aqh->unitList; + + if (unitList) { + AQHREACT_UNIT *unit; + + unit=AQHREACT_Unit_List_GetById(unitList, unitId); + if (unit==NULL) { + DBG_ERROR(NULL, "Unit \"%s/%s\" not found", netName, unitId); + return NULL; + } + return unit; + } + } + + return NULL; +} + + + +AQHREACT_UNIT *AqHomeReact_CreateUnitByName(AQHOME_REACT *aqh, const char *unitType) +{ + /* this does not include u_timer and u_varchanges, because those are only created once globally in init.c */ + if (aqh && unitType && *unitType) { + if (strcasecmp(unitType, "or")==0) + return AqHomeReact_UnitOr_new(); + else if (strcasecmp(unitType, "valueFilter")==0) + return AqHomeReact_UnitValueFilter_new(); + else if (strcasecmp(unitType, "hold")==0) + return AqHomeReact_UnitHold_new(); + else { + DBG_ERROR(NULL, "Unknown unit type \"%s\"", unitType); + return NULL; + } + } + + return NULL; +} + + + + + + + diff --git a/apps/aqhome-react/aqhome_react.h b/apps/aqhome-react/aqhome_react.h index 8e6863a..39b1db5 100644 --- a/apps/aqhome-react/aqhome_react.h +++ b/apps/aqhome-react/aqhome_react.h @@ -9,12 +9,14 @@ #ifndef AQHOME_REACT_H #define AQHOME_REACT_H - #include typedef struct AQHOME_REACT AQHOME_REACT; +#include "aqhome-react/types/unit.h" +#include "aqhome-react/types/unitnet.h" + AQHOME_REACT *AqHomeReact_new(); void AqHomeReact_free(AQHOME_REACT *aqh); @@ -28,7 +30,16 @@ void AqHomeReact_SetPidFile(AQHOME_REACT *aqh, const char *s); int AqHomeReact_GetTimeout(const AQHOME_REACT *aqh); +AQHREACT_UNIT *AqHomeReact_GetTimerUnit(const AQHOME_REACT *aqh); +AQHREACT_UNIT *AqHomeReact_GetVarChangeUnit(const AQHOME_REACT *aqh); +AQHREACT_UNIT_NET_LIST *AqHomeReact_GetUnitNetList(const AQHOME_REACT *aqh); +void AqHomeReact_AddUnitNet(AQHOME_REACT *aqh, AQHREACT_UNIT_NET *unitNet); +AQHREACT_UNIT_NET *AqHomeReact_GetUnitNetById(const AQHOME_REACT *aqh); + +AQHREACT_UNIT *AqHomeReact_FindUnitByNetNameAndUnitId(const AQHOME_REACT *aqh, const char *netName, const char *unitId); + +AQHREACT_UNIT *AqHomeReact_CreateUnitByName(AQHOME_REACT *aqh, const char *unitType); #endif diff --git a/apps/aqhome-react/aqhome_react_p.h b/apps/aqhome-react/aqhome_react_p.h index 7db0113..d5b7d0b 100644 --- a/apps/aqhome-react/aqhome_react_p.h +++ b/apps/aqhome-react/aqhome_react_p.h @@ -29,6 +29,10 @@ struct AQHOME_REACT { char *pidFile; int timeout; /* timeout for run e.g. inside valgrind */ + AQHREACT_UNIT *timerUnit; + AQHREACT_UNIT *varChangeUnit; + AQHREACT_UNIT_LIST *unitList; + AQHREACT_UNIT_NET_LIST *unitNetList; }; diff --git a/apps/aqhome-react/fini.c b/apps/aqhome-react/fini.c index 79e9378..4947aa1 100644 --- a/apps/aqhome-react/fini.c +++ b/apps/aqhome-react/fini.c @@ -43,13 +43,19 @@ int AqHomeReact_Fini(AQHOME_REACT *aqh) { + if (aqh) { + GWEN_MsgEndpoint_Disconnect(aqh->brokerEndpoint); + GWEN_MsgEndpoint_free(aqh->brokerEndpoint); + aqh->brokerEndpoint=NULL; - GWEN_MsgEndpoint_Disconnect(aqh->brokerEndpoint); - GWEN_MsgEndpoint_free(aqh->brokerEndpoint); - aqh->brokerEndpoint=NULL; + AQHREACT_UnitNet_List_Clear(aqh->unitNetList); + AQHREACT_Unit_List_Clear(aqh->unitList); + aqh->timerUnit=NULL; + aqh->varChangeUnit=NULL; - if (aqh->pidFile) - remove(aqh->pidFile); + if (aqh->pidFile) + remove(aqh->pidFile); + } return 0; } diff --git a/apps/aqhome-react/init.c b/apps/aqhome-react/init.c index e6add70..c3d2c1b 100644 --- a/apps/aqhome-react/init.c +++ b/apps/aqhome-react/init.c @@ -12,6 +12,8 @@ #include "./init.h" #include "./aqhome_react_p.h" +#include "aqhome-react/units/u_timer.h" +#include "aqhome-react/units/u_varchanges.h" #include "aqhome/aqhome.h" #include "aqhome/ipc/endpoint_ipc.h" @@ -48,6 +50,7 @@ static int _createPidFile(const char *pidFilename); static int _setupBroker(AQHOME_REACT *aqh, GWEN_DB_NODE *dbArgs); +static void _setupBuiltinUnits(AQHOME_REACT *aqh); static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs); @@ -84,7 +87,7 @@ int AqHomeReact_Init(AQHOME_REACT *aqh, int argc, char **argv) } } - /* TODO: setup react units */ + _setupBuiltinUnits(aqh); rv=_setupBroker(aqh, dbArgs); if (rv<0) { @@ -155,6 +158,7 @@ int _setupBroker(AQHOME_REACT *aqh, GWEN_DB_NODE *dbArgs) int rv; ep=AQH_ClientIpcEndpoint_new("brokerIpcClient", 0); + GWEN_MsgEndpoint_AddFlags(ep, AQH_IPCENDPOINT_FLAGS_WANTUPDATES); ipcBaseEndpoint=AQH_IpcEndpoint_CreateIpcTcpClient(brokerAddress, brokerPort, "brokerPhysEndpoint", 0); AQH_IpcEndpoint_SetServiceName(ipcBaseEndpoint, brokerClientId); GWEN_MsgEndpoint_Tree2_AddChild(ep, ipcBaseEndpoint); @@ -173,6 +177,23 @@ int _setupBroker(AQHOME_REACT *aqh, GWEN_DB_NODE *dbArgs) +void _setupBuiltinUnits(AQHOME_REACT *aqh) +{ + AQHREACT_UNIT *unit; + + unit=AqHomeReact_UnitTimer_new(); + AQHREACT_Unit_SetId(unit, ".timer"); + AQHREACT_Unit_List_Add(unit, aqh->unitList); + aqh->timerUnit=unit; + + unit=AqHomeReact_UnitVarChanges_new(); + AQHREACT_Unit_SetId(unit, ".updatedValue"); + AQHREACT_Unit_List_Add(unit, aqh->unitList); + aqh->varChangeUnit=unit; +} + + + int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs) { int rv; diff --git a/apps/aqhome-react/loop.c b/apps/aqhome-react/loop.c index 726d832..327a7a7 100644 --- a/apps/aqhome-react/loop.c +++ b/apps/aqhome-react/loop.c @@ -12,6 +12,7 @@ #include "./loop.h" #include "./aqhome_react_p.h" +#include "aqhome-react/units/u_varchanges.h" #include "aqhome/ipc/data/ipc_data.h" #include "aqhome/ipc/data/msg_data_multidata.h" @@ -35,7 +36,9 @@ * ------------------------------------------------------------------------------------------------ */ -static void _handleDataResponse(GWEN_MSG *msg); +static void _handleDataResponse(AQHREACT_UNIT *varChangeUnit, GWEN_MSG *msg); +static int _processAllNets(AQHOME_REACT *aqh); +static int _processNet(AQHREACT_UNIT_NET *unitNet); @@ -44,19 +47,19 @@ static void _handleDataResponse(GWEN_MSG *msg); * ------------------------------------------------------------------------------------------------ */ -void AqHomeReact_Loop(AQHOME_REACT *aqh, int timeoutInMilliSecs) +void AqHomeReact_IoLoop(AQHOME_REACT *aqh, int timeoutInMilliSecs) { GWEN_MSG *msg; GWEN_MsgEndpoint_IoLoop(aqh->brokerEndpoint, timeoutInMilliSecs); - msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(aqh->brokerEndpoint); - if (msg) { + + while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(aqh->brokerEndpoint)) ) { uint16_t code; code=GWEN_IpcMsg_GetCode(msg); if (code==AQH_MSGTYPE_IPC_DATA_DATACHANGED) { DBG_INFO(NULL, "Received expected IPC message"); - _handleDataResponse(msg); + _handleDataResponse(aqh->varChangeUnit, msg); } else if (code==AQH_MSGTYPE_IPC_DATA_RESULT) { DBG_INFO(NULL, "Received IPC result message, ignoring"); @@ -65,12 +68,80 @@ void AqHomeReact_Loop(AQHOME_REACT *aqh, int timeoutInMilliSecs) DBG_INFO(NULL, "Received unexpected message %d (%x)", code, code); } GWEN_Msg_free(msg); - } + } /* while */ } -void _handleDataResponse(GWEN_MSG *msg) +void AqHomeReact_ProcessAllUnits(AQHOME_REACT *aqh) +{ + int rv; + + do { + rv=_processAllNets(aqh); + } while (rv==1); +} + + + +int _processAllNets(AQHOME_REACT *aqh) +{ + int result=0; + int rv; + AQHREACT_UNIT_NET *unitNet; + + rv=AQHREACT_Unit_Process(aqh->varChangeUnit); + if (rv>0) + result=1; + + rv=AQHREACT_Unit_Process(aqh->timerUnit); + if (rv>0) + result=1; + + unitNet=AQHREACT_UnitNet_List_First(aqh->unitNetList); + while(unitNet) { + rv=_processNet(unitNet); + if (rv>0) + result=1; + + unitNet=AQHREACT_UnitNet_List_Next(unitNet); + } + + return result; +} + + + +int _processNet(AQHREACT_UNIT_NET *unitNet) +{ + AQHREACT_UNIT_LIST *unitList; + const char *netName; + + netName=AQHREACT_UnitNet_GetName(unitNet); + DBG_INFO(NULL, "Processing net \"%s\"", netName?netName:""); + unitList=AQHREACT_UnitNet_GetUnitList(unitNet); + if (unitList) { + int result=0; + AQHREACT_UNIT *unit; + + unit=AQHREACT_Unit_List_First(unitList); + while(unit) { + int rv; + + rv=AQHREACT_Unit_Process(unit); + if (rv>0) + result=1; + unit=AQHREACT_Unit_List_Next(unit); + } + return result; + } + + return 0; +} + + + +void _handleDataResponse(AQHREACT_UNIT *varChangeUnit, GWEN_MSG *msg) { AQH_VALUE *value; const GWEN_TAG16 *tag; @@ -92,7 +163,7 @@ void _handleDataResponse(GWEN_MSG *msg) timestamp=*(dataPoints++); u.i=*(dataPoints++); -// Utils_PrintFormattedSingleDataPoint(value, timestamp, u.f, tmpl); + AqHomeReact_UnitVarChanges_ValueUpdated(varChangeUnit, value, timestamp, u.f); } } AQH_Value_free(value); diff --git a/apps/aqhome-react/loop.h b/apps/aqhome-react/loop.h index 9f95918..8d74d83 100644 --- a/apps/aqhome-react/loop.h +++ b/apps/aqhome-react/loop.h @@ -13,7 +13,8 @@ #include "./aqhome_react.h" -void AqHomeReact_Loop(AQHOME_REACT *aqh, int timeoutInMilliSecs); +void AqHomeReact_IoLoop(AQHOME_REACT *aqh, int timeoutInMilliSecs); +void AqHomeReact_ProcessAllUnits(AQHOME_REACT *aqh); #endif diff --git a/apps/aqhome-react/main.c b/apps/aqhome-react/main.c index 28fe2e5..6180be8 100644 --- a/apps/aqhome-react/main.c +++ b/apps/aqhome-react/main.c @@ -13,6 +13,7 @@ #include "./init.h" #include "./fini.h" #include "./loop.h" +#include "aqhome-react/units/u_timer.h" #include "aqhome/aqhome.h" @@ -95,8 +96,8 @@ int main(int argc, char **argv) } GWEN_Logger_Open(0, "aqhome-react", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User); - GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning); - //GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info); + //GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning); + GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info); rv=AQH_Init(); if (rv<0) { @@ -141,11 +142,13 @@ void _serve(AQHOME_REACT *aqh) time_t startTime; time_t lastTimerTime; GWEN_DB_NODE *dbArgs; + AQHREACT_UNIT *timerUnit; startTime=time(NULL); lastTimerTime=startTime; dbArgs=AqHomeReact_GetDbArgs(aqh); + timerUnit=AqHomeReact_GetTimerUnit(aqh); rv=_setSignalHandlers(); if (rv<0) { @@ -159,14 +162,17 @@ void _serve(AQHOME_REACT *aqh) time_t now; DBG_DEBUG(NULL, "Next loop"); - AqHomeReact_Loop(aqh, 500); + + AqHomeReact_IoLoop(aqh, 500); now=time(NULL); if (now!=lastTimerTime) { lastTimerTime=now; - /* TODO: fire timer */ + AqHomeReact_UnitTimer_GenerateTick(timerUnit); } + AqHomeReact_ProcessAllUnits(aqh); + if (timeout) { if ((now-startTime)>timeout) { DBG_ERROR(NULL, "Timeout, stopping service"); diff --git a/apps/aqhome-react/types/0BUILD b/apps/aqhome-react/types/0BUILD index a4e2451..5c445bd 100644 --- a/apps/aqhome-react/types/0BUILD +++ b/apps/aqhome-react/types/0BUILD @@ -49,6 +49,7 @@ param_p.h unit.h unit_p.h + unitnet.h @@ -59,6 +60,7 @@ link.c param.c unit.c + unitnet.c diff --git a/apps/aqhome-react/types/dataobject.h b/apps/aqhome-react/types/dataobject.h index ce7b2c7..f4b8d63 100644 --- a/apps/aqhome-react/types/dataobject.h +++ b/apps/aqhome-react/types/dataobject.h @@ -10,8 +10,6 @@ #define AQHOME_REACT_DATAOBJECT_H -#include "aqhome-react/aqhome_react.h" - #include @@ -26,6 +24,9 @@ enum { }; +#include "aqhome-react/aqhome_react.h" + + AQHREACT_DATAOBJECT *AQHREACT_DataObject_new(); void AQHREACT_DataObject_free(AQHREACT_DATAOBJECT *dataObject); diff --git a/apps/aqhome-react/types/inputslot.h b/apps/aqhome-react/types/inputslot.h index 065f465..cd2f5f4 100644 --- a/apps/aqhome-react/types/inputslot.h +++ b/apps/aqhome-react/types/inputslot.h @@ -10,8 +10,6 @@ #define AQHOME_REACT_INPUTSLOT_H -#include "aqhome-react/aqhome_react.h" - #include @@ -19,6 +17,7 @@ typedef struct AQHREACT_INPUT_SLOT AQHREACT_INPUT_SLOT; GWEN_LIST_FUNCTION_DEFS(AQHREACT_INPUT_SLOT, AQHREACT_InputSlot) +#include "aqhome-react/aqhome_react.h" #include "aqhome-react/types/dataobject.h" diff --git a/apps/aqhome-react/types/outputslot.h b/apps/aqhome-react/types/outputslot.h index 08790e0..585da6e 100644 --- a/apps/aqhome-react/types/outputslot.h +++ b/apps/aqhome-react/types/outputslot.h @@ -9,8 +9,6 @@ #ifndef AQHOME_REACT_OUTPUTSLOT_H #define AQHOME_REACT_OUTPUTSLOT_H -#include "aqhome-react/aqhome_react.h" - #include @@ -18,6 +16,7 @@ typedef struct AQHREACT_OUTPUT_SLOT AQHREACT_OUTPUT_SLOT; GWEN_LIST_FUNCTION_DEFS(AQHREACT_OUTPUT_SLOT, AQHREACT_OutputSlot) +#include "aqhome-react/aqhome_react.h" #include "aqhome-react/types/link.h" diff --git a/apps/aqhome-react/types/param.h b/apps/aqhome-react/types/param.h index b3c9470..a0dc30a 100644 --- a/apps/aqhome-react/types/param.h +++ b/apps/aqhome-react/types/param.h @@ -9,15 +9,15 @@ #ifndef AQHOME_REACT_PARAM_H #define AQHOME_REACT_PARAM_H -#include "aqhome-react/aqhome_react.h" - - #include typedef struct AQHREACT_PARAM AQHREACT_PARAM; GWEN_LIST_FUNCTION_DEFS(AQHREACT_PARAM, AQHREACT_Param) +#include "aqhome-react/aqhome_react.h" + + AQHREACT_PARAM *AQHREACT_Param_new(); void AQHREACT_Param_free(AQHREACT_PARAM *param); diff --git a/apps/aqhome-react/types/unit.c b/apps/aqhome-react/types/unit.c index 70f1f65..a95a915 100644 --- a/apps/aqhome-react/types/unit.c +++ b/apps/aqhome-react/types/unit.c @@ -21,7 +21,7 @@ GWEN_INHERIT_FUNCTIONS(AQHREACT_UNIT) -AQHREACT_UNIT *AQHREACT_Unit_new() +AQHREACT_UNIT *AQHREACT_Unit_new(void) { AQHREACT_UNIT *unit; @@ -151,6 +151,21 @@ void AQHREACT_Unit_SubFlags(AQHREACT_UNIT *unit, uint32_t i) +uint64_t AQHREACT_Unit_GetGpTimestamp(const AQHREACT_UNIT *unit) +{ + return unit?unit->gpTimestamp:0; +} + + + +void AQHREACT_Unit_SetGpTimestamp(AQHREACT_UNIT *unit, uint64_t t) +{ + if (unit) + unit->gpTimestamp=t; +} + + + AQHREACT_INPUT_SLOT_LIST *AQHREACT_Unit_GetInputSlots(const AQHREACT_UNIT *unit) { return unit?unit->inputSlotList:NULL; @@ -566,5 +581,27 @@ int AQHREACT_Unit_InputHasChanged(const AQHREACT_UNIT *unit) +AQHREACT_UNIT *AQHREACT_Unit_List_GetById(const AQHREACT_UNIT_LIST *unitList, const char *id) +{ + if (unitList && id && *id) { + AQHREACT_UNIT *unit; + + unit=AQHREACT_Unit_List_First(unitList); + while(unit) { + const char *s; + + s=AQHREACT_Unit_GetId(unit); + if (s && *s && strcasecmp(s, id)==0) + return unit; + unit=AQHREACT_Unit_List_Next(unit); + } + } + + return NULL; +} + + + + diff --git a/apps/aqhome-react/types/unit.h b/apps/aqhome-react/types/unit.h index db20906..0225d69 100644 --- a/apps/aqhome-react/types/unit.h +++ b/apps/aqhome-react/types/unit.h @@ -10,8 +10,6 @@ #define AQHOME_REACT_UNIT_H -#include "aqhome-react/aqhome_react.h" - #include #include @@ -26,9 +24,11 @@ GWEN_INHERIT_FUNCTION_DEFS(AQHREACT_UNIT) #define AQHREACT_UNIT_FLAGS_MULTI 0x20000000 +#include "aqhome-react/aqhome_react.h" #include "aqhome-react/types/inputslot.h" #include "aqhome-react/types/outputslot.h" #include "aqhome-react/types/param.h" +#include "aqhome-react/types/dataobject.h" typedef void (*AQHREACT_UNIT_INPUTDATA_FN)(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject); @@ -36,7 +36,7 @@ typedef int (*AQHREACT_UNIT_PROCESS_FN)(AQHREACT_UNIT *unit); -AQHREACT_UNIT *AQHREACT_Unit_new(); +AQHREACT_UNIT *AQHREACT_Unit_new(void); void AQHREACT_Unit_free(AQHREACT_UNIT *unit); const char *AQHREACT_Unit_GetName(const AQHREACT_UNIT *unit); @@ -56,6 +56,11 @@ void AQHREACT_Unit_SetFlags(AQHREACT_UNIT *unit, uint32_t i); void AQHREACT_Unit_AddFlags(AQHREACT_UNIT *unit, uint32_t i); void AQHREACT_Unit_SubFlags(AQHREACT_UNIT *unit, uint32_t i); +/** general purpose timestamp, unit is free to use it */ +uint64_t AQHREACT_Unit_GetGpTimestamp(const AQHREACT_UNIT *unit); +void AQHREACT_Unit_SetGpTimestamp(AQHREACT_UNIT *unit, uint64_t t); + + AQHREACT_INPUT_SLOT_LIST *AQHREACT_Unit_GetInputSlots(const AQHREACT_UNIT *unit); void AQHREACT_Unit_AddInputSlot(AQHREACT_UNIT *unit, AQHREACT_INPUT_SLOT *inSlot); AQHREACT_INPUT_SLOT *AQHREACT_Unit_GetInputSlotByIdForUnit(const AQHREACT_UNIT *unit, int id); @@ -86,6 +91,12 @@ void AQHREACT_Unit_OutputStringData(AQHREACT_UNIT *unit, int slotIndex, const ch void AQHREACT_Unit_InputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject); +/** + * Process inputs and generate output. + * + * @return >0 if something done, 0 if nothing done (response of internal implementation), <0 on error + * @param unit unit object + */ int AQHREACT_Unit_Process(AQHREACT_UNIT *unit); @@ -93,6 +104,8 @@ AQHREACT_UNIT_INPUTDATA_FN AQHREACT_Unit_SetInputDataFn(AQHREACT_UNIT *unit, AQH AQHREACT_UNIT_PROCESS_FN AQHREACT_Unit_SetProcessFn(AQHREACT_UNIT *unit, AQHREACT_UNIT_PROCESS_FN f); +AQHREACT_UNIT *AQHREACT_Unit_List_GetById(const AQHREACT_UNIT_LIST *unitList, const char *id); + #endif diff --git a/apps/aqhome-react/types/unit_p.h b/apps/aqhome-react/types/unit_p.h index 0b03e3e..a61581e 100644 --- a/apps/aqhome-react/types/unit_p.h +++ b/apps/aqhome-react/types/unit_p.h @@ -22,6 +22,7 @@ struct AQHREACT_UNIT { char *id; uint32_t flags; + uint64_t gpTimestamp; int nextInputSlotId; diff --git a/apps/aqhome-react/types/unitnet.c b/apps/aqhome-react/types/unitnet.c new file mode 100644 index 0000000..5abfc6c --- /dev/null +++ b/apps/aqhome-react/types/unitnet.c @@ -0,0 +1,111 @@ +/**************************************************************************** + * 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 "./unitnet_p.h" + +#include + + +GWEN_LIST_FUNCTIONS(AQHREACT_UNIT_NET, AQHREACT_UnitNet) + + + +AQHREACT_UNIT_NET *AQHREACT_UnitNet_new(void) +{ + AQHREACT_UNIT_NET *unitNet; + + GWEN_NEW_OBJECT(AQHREACT_UNIT_NET, unitNet); + GWEN_LIST_INIT(AQHREACT_UNIT_NET, unitNet); + + unitNet->unitList=AQHREACT_UnitNet_List_new(); + + return unitNet; +} + + + +void AQHREACT_UnitNet_free(AQHREACT_UNIT_NET *unitNet) +{ + if (unitNet) { + GWEN_LIST_FINI(AQHREACT_UNIT_NET, unitNet); + AQHREACT_UnitNet_List_free(unitNet->unitList); + GWEN_FREE_OBJECT(unitNet); + } +} + + + +const char *AQHREACT_UnitNet_GetName(const AQHREACT_UNIT_NET *unitNet) +{ + return unitNet?unitNet->name:NULL; +} + + + +void AQHREACT_UnitNet_SetName(AQHREACT_UNIT_NET *unitNet, const char *s) +{ + if (unitNet) { + free(unitNet->name); + unitNet->name=s?strdup(s):NULL; + } +} + + + +AQHREACT_UNIT_LIST *AQHREACT_UnitNet_GetUnitList(const AQHREACT_UNIT_NET *unitNet) +{ + return unitNet?unitNet->unitList:NULL; +} + + + +AQHREACT_UNIT *AQHREACT_UnitNet_GetUnitById(const AQHREACT_UNIT_NET *unitNet, const char *s) +{ + return (unitNet && s && *s)?AQHREACT_Unit_List_GetById(unitNet->unitList, s):NULL; +} + + + +void AQHREACT_UnitNet_AddUnit(AQHREACT_UNIT_NET *unitNet, AQHREACT_UNIT *unit) +{ + if (unitNet && unit) + AQHREACT_Unit_List_Add(unit, unitNet->unitList); +} + + + +AQHREACT_UNIT_NET *AQHREACT_UnitNet_List_GetByName(const AQHREACT_UNIT_NET_LIST *unitNetList, const char *name) +{ + if (unitNetList && name && *name) { + AQHREACT_UNIT_NET *unitNet; + + unitNet=AQHREACT_UnitNet_List_First(unitNetList); + while(unitNet) { + const char *s; + + s=AQHREACT_UnitNet_GetName(unitNet); + if (s && *s && strcasecmp(s, name)==0) + return unitNet; + unitNet=AQHREACT_UnitNet_List_Next(unitNet); + } + } + + return NULL; +} + + + + + + + diff --git a/apps/aqhome-react/types/unitnet.h b/apps/aqhome-react/types/unitnet.h new file mode 100644 index 0000000..8657912 --- /dev/null +++ b/apps/aqhome-react/types/unitnet.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * 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_REACT_UNIT_NET_H +#define AQHOME_REACT_UNIT_NET_H + + +#include + + +typedef struct AQHREACT_UNIT_NET AQHREACT_UNIT_NET; +GWEN_LIST_FUNCTION_DEFS(AQHREACT_UNIT_NET, AQHREACT_UnitNet) + + +#include "aqhome-react/aqhome_react.h" + + +AQHREACT_UNIT_NET *AQHREACT_UnitNet_new(void); +void AQHREACT_UnitNet_free(AQHREACT_UNIT_NET *unitNet); + +const char *AQHREACT_UnitNet_GetName(const AQHREACT_UNIT_NET *unitNet); +void AQHREACT_UnitNet_SetName(AQHREACT_UNIT_NET *unitNet, const char *s); + +AQHREACT_UNIT_LIST *AQHREACT_UnitNet_GetUnitList(const AQHREACT_UNIT_NET *unitNet); +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_UNIT_NET *AQHREACT_UnitNet_List_GetByName(const AQHREACT_UNIT_NET_LIST *unitNetList, const char *name); + + + + +#endif + diff --git a/apps/aqhome-react/types/unitnet_p.h b/apps/aqhome-react/types/unitnet_p.h new file mode 100644 index 0000000..57d7d8b --- /dev/null +++ b/apps/aqhome-react/types/unitnet_p.h @@ -0,0 +1,25 @@ +/**************************************************************************** + * 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_REACT_UNIT_NET_P_H +#define AQHOME_REACT_UNIT_NET_P_H + + +#include "aqhome-react/types/unitnet.h" + + +struct AQHREACT_UNIT_NET { + GWEN_LIST_ELEMENT(AQHREACT_UNIT_NET) + + char *name; + AQHREACT_UNIT_LIST *unitList; +}; + + +#endif + diff --git a/apps/aqhome-react/units/0BUILD b/apps/aqhome-react/units/0BUILD index 1dbf4ef..15029af 100644 --- a/apps/aqhome-react/units/0BUILD +++ b/apps/aqhome-react/units/0BUILD @@ -38,15 +38,25 @@ u_or.h + u_passthrough.h u_varchanges.h u_valuefilter.h + u_timer.h + u_hold.h + u_lowpass.h + u_highpass.h $(local/typefiles) u_or.c + u_passthrough.c u_varchanges.c u_valuefilter.c + u_timer.c + u_hold.c + u_lowpass.c + u_highpass.c diff --git a/apps/aqhome-react/units/README b/apps/aqhome-react/units/README new file mode 100644 index 0000000..cba59d9 --- /dev/null +++ b/apps/aqhome-react/units/README @@ -0,0 +1,4 @@ + +This folder contains units. + +Please add code to function AqHomeReact_CreateUnitByName() in ../aqhome_react.c for new unit types. diff --git a/apps/aqhome-react/units/u_highpass.c b/apps/aqhome-react/units/u_highpass.c new file mode 100644 index 0000000..a2efe2e --- /dev/null +++ b/apps/aqhome-react/units/u_highpass.c @@ -0,0 +1,98 @@ +/**************************************************************************** + * 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_highpass.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define AQHOMEREACT_UNIT_HIGHPASS_INSLOT_INPUT 0 +#define AQHOMEREACT_UNIT_HIGHPASS_OUTSLOT_OUTPUT 0 + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQHREACT_UNIT *AqHomeReact_UnitHighPass_new(void) +{ + AQHREACT_UNIT *unit; + AQHREACT_OUTPUT_SLOT *outputSlot; + AQHREACT_INPUT_SLOT *inputSlot; + AQHREACT_PARAM *param; + + unit=AQHREACT_Unit_new(); + AQHREACT_Unit_SetName(unit, "highpass"); + AQHREACT_Unit_SetDescription(unit, "Highpass filter for data"); + AQHREACT_Unit_SetInputDataFn(unit, _cbInputData); + + outputSlot=AQHREACT_OutputSlot_new(); + AQHREACT_OutputSlot_SetName(outputSlot, "output"); + AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_HIGHPASS_OUTSLOT_OUTPUT); + AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddOutputSlot(unit, outputSlot); + + inputSlot=AQHREACT_InputSlot_new(); + AQHREACT_InputSlot_SetName(inputSlot, "input"); + AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_HIGHPASS_INSLOT_INPUT); + AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddInputSlot(unit, inputSlot); + + param=AQHREACT_Param_new(); + AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_HIGHPASS_PARAM_LIMIT); + AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddParam(unit, param); + + param=AQHREACT_Param_new(); + AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_HIGHPASS_PARAM_NEWVALUE); + AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddParam(unit, param); + + return unit; +} + + + +void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject) +{ + if (unit && dataObject && slotIdForUnit==AQHOMEREACT_UNIT_HIGHPASS_INSLOT_INPUT) { + double data; + double limit; + double newValue; + + data=AQHREACT_DataObject_GetDoubleData(dataObject); + limit=AQHREACT_Unit_GetParamValueDouble(unit, AQHOMEREACT_UNIT_HIGHPASS_PARAM_LIMIT, data); + newValue=AQHREACT_Unit_GetParamValueDouble(unit, AQHOMEREACT_UNIT_HIGHPASS_PARAM_NEWVALUE, data); + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_HIGHPASS_OUTSLOT_OUTPUT, (data>=limit)?data:newValue); + } +} + + + + diff --git a/apps/aqhome-react/units/u_highpass.h b/apps/aqhome-react/units/u_highpass.h new file mode 100644 index 0000000..1e75bfc --- /dev/null +++ b/apps/aqhome-react/units/u_highpass.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * 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_HIGHPASS_H +#define AQHOMEREACT_U_HIGHPASS_H + + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" + + +#define AQHOMEREACT_UNIT_HIGHPASS_PARAM_LIMIT "threshold" +#define AQHOMEREACT_UNIT_HIGHPASS_PARAM_NEWVALUE "newValue" + + +AQHREACT_UNIT *AqHomeReact_UnitHighPass_new(void); + + + +#endif + + diff --git a/apps/aqhome-react/units/u_hold.c b/apps/aqhome-react/units/u_hold.c new file mode 100644 index 0000000..b1ac7ae --- /dev/null +++ b/apps/aqhome-react/units/u_hold.c @@ -0,0 +1,185 @@ +/**************************************************************************** + * 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_hold.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define AQHOMEREACT_UNIT_HOLD_INSLOT_INPUT 0 +#define AQHOMEREACT_UNIT_HOLD_INSLOT_TIMER 1 + +#define AQHOMEREACT_UNIT_HOLD_OUTSLOT_OUTPUT 0 + + + +/* ------------------------------------------------------------------------------------------------ + * type declarations + * ------------------------------------------------------------------------------------------------ + */ + +typedef struct AQHREACT_UNIT_HOLD AQHREACT_UNIT_HOLD; +struct AQHREACT_UNIT_HOLD { + uint64_t tsHoldUntil; + int lastProcessedState; + int currentOutState; +}; +GWEN_INHERIT(AQHREACT_UNIT, AQHREACT_UNIT_HOLD) + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); +static int _cbProcessFn(AQHREACT_UNIT *unit); +static int _checkState(AQHREACT_UNIT *unit); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQHREACT_UNIT *AqHomeReact_UnitHold_new(void) +{ + AQHREACT_UNIT_HOLD *xunit; + AQHREACT_UNIT *unit; + AQHREACT_OUTPUT_SLOT *outputSlot; + AQHREACT_INPUT_SLOT *inputSlot; + + unit=AQHREACT_Unit_new(); + GWEN_NEW_OBJECT(AQHREACT_UNIT_HOLD, xunit); + GWEN_INHERIT_SETDATA(AQHREACT_UNIT, AQHREACT_UNIT_HOLD, unit, xunit, _freeData); + + AQHREACT_Unit_SetName(unit, "hold"); + AQHREACT_Unit_SetDescription(unit, "Hold incoming signal for a given time"); + AQHREACT_Unit_SetProcessFn(unit, _cbProcessFn); + + outputSlot=AQHREACT_OutputSlot_new(); + AQHREACT_OutputSlot_SetName(outputSlot, "output"); + AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_HOLD_OUTSLOT_OUTPUT); + AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddOutputSlot(unit, outputSlot); + + inputSlot=AQHREACT_InputSlot_new(); + AQHREACT_InputSlot_SetName(inputSlot, "input"); + AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_HOLD_INSLOT_INPUT); + AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddInputSlot(unit, inputSlot); + + inputSlot=AQHREACT_InputSlot_new(); + AQHREACT_InputSlot_SetName(inputSlot, "timer"); + AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_HOLD_INSLOT_TIMER); + AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddInputSlot(unit, inputSlot); + + return unit; +} + + + +void _freeData(void *bp, void *p) +{ + AQHREACT_UNIT_HOLD *xunit; + + xunit=(AQHREACT_UNIT_HOLD*) p; + GWEN_FREE_OBJECT(xunit); +} + + + +int _cbProcessFn(AQHREACT_UNIT *unit) +{ + if (unit && AQHREACT_Unit_InputHasChanged(unit)) { + int rv; + + rv=_checkState(unit); + AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit); + return rv; + } + + return 0; +} + + + +int _checkState(AQHREACT_UNIT *unit) +{ + AQHREACT_UNIT_HOLD *xunit; + int result=0; + + xunit=GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_HOLD, unit); + if (xunit) { + AQHREACT_INPUT_SLOT *dataSlot; + + dataSlot=AQHREACT_Unit_GetInputSlotByIdForUnit(unit, AQHOMEREACT_UNIT_HOLD_INSLOT_INPUT); + if (dataSlot) { + AQHREACT_DATAOBJECT *dataObject; + + dataObject=AQHREACT_InputSlot_GetCurrentDataObject(dataSlot); + if (dataObject) { + double data; + + data=AQHREACT_DataObject_GetDoubleData(dataObject); + if (data>0.0) { + if (xunit->lastProcessedState==0) { /* was off, is on, turn output ON */ + DBG_INFO(NULL, "Turning output ON"); + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_HOLD_OUTSLOT_OUTPUT, 1.0); + xunit->currentOutState=1; + result=1; + } + xunit->lastProcessedState=1; + } /* if new value is ON */ + else { + uint64_t now; + + now=(uint64_t) time(NULL); + if (xunit->lastProcessedState) { /* was 1, is now 0, start hold timer */ + int holdTime; + + DBG_INFO(NULL, "Starting timeout counter"); + holdTime=AQHREACT_Unit_GetParamValueDouble(unit, AQHOMEREACT_UNIT_HOLD_PARAM_HOLDTIME, 30.0); + xunit->tsHoldUntil=now+holdTime; + result=1; + } + else { /* was 0, is 0, check timeout */ + if (xunit->currentOutState>0) { /* output is still ON, check hold time */ + if (now>xunit->tsHoldUntil) { + /* timeout, turn output OFF */ + DBG_INFO(NULL, "Turning output OFF"); + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_HOLD_OUTSLOT_OUTPUT, 0.0); + xunit->currentOutState=0; + xunit->tsHoldUntil=0; + result=1; + } + } + } + xunit->lastProcessedState=0; + } + } + } + } + return result; +} + + + diff --git a/apps/aqhome-react/units/u_hold.h b/apps/aqhome-react/units/u_hold.h new file mode 100644 index 0000000..7519544 --- /dev/null +++ b/apps/aqhome-react/units/u_hold.h @@ -0,0 +1,25 @@ +/**************************************************************************** + * 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_HOLD_H +#define AQHOMEREACT_U_HOLD_H + + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" + +#define AQHOMEREACT_UNIT_HOLD_PARAM_HOLDTIME "holdTime" + + +AQHREACT_UNIT *AqHomeReact_UnitHold_new(void); + + + +#endif + + diff --git a/apps/aqhome-react/units/u_lowpass.c b/apps/aqhome-react/units/u_lowpass.c new file mode 100644 index 0000000..70cc058 --- /dev/null +++ b/apps/aqhome-react/units/u_lowpass.c @@ -0,0 +1,98 @@ +/**************************************************************************** + * 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_lowpass.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define AQHOMEREACT_UNIT_LOWPASS_INSLOT_INPUT 0 +#define AQHOMEREACT_UNIT_LOWPASS_OUTSLOT_OUTPUT 0 + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQHREACT_UNIT *AqHomeReact_UnitLowPass_new(void) +{ + AQHREACT_UNIT *unit; + AQHREACT_OUTPUT_SLOT *outputSlot; + AQHREACT_INPUT_SLOT *inputSlot; + AQHREACT_PARAM *param; + + unit=AQHREACT_Unit_new(); + AQHREACT_Unit_SetName(unit, "lowpass"); + AQHREACT_Unit_SetDescription(unit, "Lowpass filter for data"); + AQHREACT_Unit_SetInputDataFn(unit, _cbInputData); + + outputSlot=AQHREACT_OutputSlot_new(); + AQHREACT_OutputSlot_SetName(outputSlot, "output"); + AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_LOWPASS_OUTSLOT_OUTPUT); + AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddOutputSlot(unit, outputSlot); + + inputSlot=AQHREACT_InputSlot_new(); + AQHREACT_InputSlot_SetName(inputSlot, "input"); + AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_LOWPASS_INSLOT_INPUT); + AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddInputSlot(unit, inputSlot); + + param=AQHREACT_Param_new(); + AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_LOWPASS_PARAM_LIMIT); + AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddParam(unit, param); + + param=AQHREACT_Param_new(); + AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_LOWPASS_PARAM_NEWVALUE); + AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddParam(unit, param); + + return unit; +} + + + +void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject) +{ + if (unit && dataObject && slotIdForUnit==AQHOMEREACT_UNIT_LOWPASS_INSLOT_INPUT) { + double data; + double limit; + double newValue; + + data=AQHREACT_DataObject_GetDoubleData(dataObject); + limit=AQHREACT_Unit_GetParamValueDouble(unit, AQHOMEREACT_UNIT_LOWPASS_PARAM_LIMIT, data); + newValue=AQHREACT_Unit_GetParamValueDouble(unit, AQHOMEREACT_UNIT_LOWPASS_PARAM_NEWVALUE, data); + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_LOWPASS_OUTSLOT_OUTPUT, (data<=limit)?data:newValue); + } +} + + + + diff --git a/apps/aqhome-react/units/u_lowpass.h b/apps/aqhome-react/units/u_lowpass.h new file mode 100644 index 0000000..c13ec85 --- /dev/null +++ b/apps/aqhome-react/units/u_lowpass.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * 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_LOWPASS_H +#define AQHOMEREACT_U_LOWPASS_H + + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" + + +#define AQHOMEREACT_UNIT_LOWPASS_PARAM_LIMIT "threshold" +#define AQHOMEREACT_UNIT_LOWPASS_PARAM_NEWVALUE "newValue" + + +AQHREACT_UNIT *AqHomeReact_UnitLowPass_new(void); + + + +#endif + + diff --git a/apps/aqhome-react/units/u_or.c b/apps/aqhome-react/units/u_or.c index a868f1d..5e2f74f 100644 --- a/apps/aqhome-react/units/u_or.c +++ b/apps/aqhome-react/units/u_or.c @@ -86,6 +86,7 @@ int _cbProcessFn(AQHREACT_UNIT *unit) result=_sampleInputSlots(inputSlotList); AQHREACT_Unit_ClearChangeFlagsInUnitAndInputSlots(unit); AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_OR_OUTSLOT_RESULT, result?1.0:0.0); + return 1; } } diff --git a/apps/aqhome-react/units/u_passthrough.c b/apps/aqhome-react/units/u_passthrough.c new file mode 100644 index 0000000..c09452d --- /dev/null +++ b/apps/aqhome-react/units/u_passthrough.c @@ -0,0 +1,77 @@ +/**************************************************************************** + * 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_passthrough.h" + +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +AQHREACT_UNIT *AqHomeReact_UnitPassthrough_new(void) +{ + AQHREACT_UNIT *unit; + AQHREACT_OUTPUT_SLOT *outputSlot; + AQHREACT_INPUT_SLOT *inputSlot; + + unit=AQHREACT_Unit_new(); + AQHREACT_Unit_SetName(unit, "passthrough"); + AQHREACT_Unit_SetDescription(unit, "Generic passthrough unit"); + AQHREACT_Unit_SetInputDataFn(unit, _cbInputData); + + outputSlot=AQHREACT_OutputSlot_new(); + AQHREACT_OutputSlot_SetName(outputSlot, "output"); + AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_PASSTHROUGH_OUTSLOT_OUTPUT); + AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddOutputSlot(unit, outputSlot); + + inputSlot=AQHREACT_InputSlot_new(); + AQHREACT_InputSlot_SetName(inputSlot, "input"); + AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_PASSTHROUGH_OUTSLOT_OUTPUT); + AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddInputSlot(unit, inputSlot); + + return unit; +} + + + + +void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject) +{ + if (unit && dataObject && slotIdForUnit==AQHOMEREACT_UNIT_PASSTHROUGH_INSLOT_INPUT) + AQHREACT_Unit_OutputData(unit, AQHOMEREACT_UNIT_PASSTHROUGH_OUTSLOT_OUTPUT, dataObject); +} + + + + diff --git a/apps/aqhome-react/units/u_passthrough.h b/apps/aqhome-react/units/u_passthrough.h new file mode 100644 index 0000000..9148d90 --- /dev/null +++ b/apps/aqhome-react/units/u_passthrough.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_PASSTHROUGH_H +#define AQHOMEREACT_U_PASSTHROUGH_H + + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" + + +#define AQHOMEREACT_UNIT_PASSTHROUGH_INSLOT_INPUT 0 +#define AQHOMEREACT_UNIT_PASSTHROUGH_OUTSLOT_OUTPUT 0 + + + +AQHREACT_UNIT *AqHomeReact_UnitPassthrough_new(void); + + + +#endif + + diff --git a/apps/aqhome-react/units/u_timer.c b/apps/aqhome-react/units/u_timer.c new file mode 100644 index 0000000..a96a411 --- /dev/null +++ b/apps/aqhome-react/units/u_timer.c @@ -0,0 +1,42 @@ +/**************************************************************************** + * 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_timer.h" +#include "./u_passthrough.h" + +#include + + + +AQHREACT_UNIT *AqHomeReact_UnitTimer_new(void) +{ + AQHREACT_UNIT *unit; + + unit=AqHomeReact_UnitPassthrough_new(); + AQHREACT_Unit_SetName(unit, "timer"); + AQHREACT_Unit_SetDescription(unit, "Periodically generate a timer signal"); + + return unit; +} + + + +void AqHomeReact_UnitTimer_GenerateTick(AQHREACT_UNIT *unit) +{ + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_PASSTHROUGH_OUTSLOT_OUTPUT, 1.0); +} + + + + + + diff --git a/apps/aqhome-react/units/u_timer.h b/apps/aqhome-react/units/u_timer.h new file mode 100644 index 0000000..92cfd2c --- /dev/null +++ b/apps/aqhome-react/units/u_timer.h @@ -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 AQHOMEREACT_U_TIMER_H +#define AQHOMEREACT_U_TIMER_H + + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" + + +AQHREACT_UNIT *AqHomeReact_UnitTimer_new(void); + +void AqHomeReact_UnitTimer_GenerateTick(AQHREACT_UNIT *unit); + + +#endif + + diff --git a/apps/aqhome-react/units/u_varchanges.c b/apps/aqhome-react/units/u_varchanges.c index 497276e..39d1e4e 100644 --- a/apps/aqhome-react/units/u_varchanges.c +++ b/apps/aqhome-react/units/u_varchanges.c @@ -11,71 +11,42 @@ #endif #include "./u_varchanges.h" +#include "./u_passthrough.h" #include -/* ------------------------------------------------------------------------------------------------ - * defines - * ------------------------------------------------------------------------------------------------ - */ - -#define AQHOMEREACT_UNIT_VARCHANGES_INSLOT_CHANGE 0 - -#define AQHOMEREACT_UNIT_VARCHANGES_OUTSLOT_RESULT 0 - - - -/* ------------------------------------------------------------------------------------------------ - * forward declarations - * ------------------------------------------------------------------------------------------------ - */ - -static void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject); - - - -/* ------------------------------------------------------------------------------------------------ - * implementations - * ------------------------------------------------------------------------------------------------ - */ - -AQHREACT_UNIT *AqHomeReact_UnitVarChanges_new(AQHOME_REACT *aqh) +AQHREACT_UNIT *AqHomeReact_UnitVarChanges_new(void) { AQHREACT_UNIT *unit; - AQHREACT_OUTPUT_SLOT *outputSlot; - AQHREACT_INPUT_SLOT *inputSlot; - unit=AQHREACT_Unit_new(); + unit=AqHomeReact_UnitPassthrough_new(); AQHREACT_Unit_SetName(unit, "varchanges"); AQHREACT_Unit_SetDescription(unit, "Propagates changes of values on the data server"); - AQHREACT_Unit_SetInputDataFn(unit, _cbInputData); - - outputSlot=AQHREACT_OutputSlot_new(); - AQHREACT_OutputSlot_SetName(outputSlot, "output"); - AQHREACT_OutputSlot_SetIdForUnit(outputSlot, AQHOMEREACT_UNIT_VARCHANGES_OUTSLOT_RESULT); - AQHREACT_OutputSlot_SetEmittedDataType(outputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); - AQHREACT_Unit_AddOutputSlot(unit, outputSlot); - - inputSlot=AQHREACT_InputSlot_new(); - AQHREACT_InputSlot_SetName(inputSlot, "input"); - AQHREACT_InputSlot_SetIdForUnit(inputSlot, AQHOMEREACT_UNIT_VARCHANGES_INSLOT_CHANGE); - AQHREACT_InputSlot_SetAcceptedDataType(inputSlot, AQHREACT_DATAOBJECTTYPE_DOUBLE); - AQHREACT_Unit_AddInputSlot(unit, inputSlot); return unit; } - -void _cbInputData(AQHREACT_UNIT *unit, int slotIdForUnit, const AQHREACT_DATAOBJECT *dataObject) +void AqHomeReact_UnitVarChanges_ValueUpdated(AQHREACT_UNIT *unit, const AQH_VALUE *value, uint64_t timestamp, double data) { - if (unit && dataObject && slotIdForUnit==0) - AQHREACT_Unit_OutputData(unit, AQHOMEREACT_UNIT_VARCHANGES_OUTSLOT_RESULT, dataObject); + AQHREACT_DATAOBJECT *dataObject; + + DBG_INFO(NULL, "Value \"%s\" changed", AQH_Value_GetNameForSystem(value)); + dataObject=AQHREACT_DataObject_new(); + AQHREACT_DataObject_SetDataType(dataObject, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_DataObject_SetTimestamp(dataObject, timestamp); + AQHREACT_DataObject_SetDoubleData(dataObject, data); + AQHREACT_DataObject_SetSystemValueId(dataObject, AQH_Value_GetNameForSystem(value)); + AQHREACT_DataObject_SetValueId(dataObject, AQH_Value_GetId(value)); + AQHREACT_Unit_OutputData(unit, AQHOMEREACT_UNIT_PASSTHROUGH_OUTSLOT_OUTPUT, dataObject); + AQHREACT_DataObject_free(dataObject); } + + diff --git a/apps/aqhome-react/units/u_varchanges.h b/apps/aqhome-react/units/u_varchanges.h index 3897593..9f75df4 100644 --- a/apps/aqhome-react/units/u_varchanges.h +++ b/apps/aqhome-react/units/u_varchanges.h @@ -13,9 +13,12 @@ #include "aqhome-react/aqhome_react.h" #include "aqhome-react/types/unit.h" +#include "aqhome/data/value.h" -AQHREACT_UNIT *AqHomeReact_UnitVarChanges_new(AQHOME_REACT *aqh); +AQHREACT_UNIT *AqHomeReact_UnitVarChanges_new(void); + +void AqHomeReact_UnitVarChanges_ValueUpdated(AQHREACT_UNIT *unit, const AQH_VALUE *value, uint64_t timestamp, double data); #endif diff --git a/aqhome-react.sh b/aqhome-react.sh new file mode 100755 index 0000000..8006a9c --- /dev/null +++ b/aqhome-react.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +export AQHOME_LOGLEVEL=info +export LD_LIBRARY_PATH="0-build/aqhome/:$LD_LIBRARY_PATH" + +0-build/apps/aqhome-react/aqhome-react -p ./aqhome-react.pid "$@" +