diff --git a/apps/aqhome-react/types/prgrule.c b/apps/aqhome-react/types/prgrule.c index fdc24cf..7c1016b 100644 --- a/apps/aqhome-react/types/prgrule.c +++ b/apps/aqhome-react/types/prgrule.c @@ -68,6 +68,13 @@ void AQHREACT_PrgRule_free(AQHREACT_PRGRULE *prgRule) +double AQHREACT_PrgRule_GetValue(const AQHREACT_PRGRULE *prgRule) +{ + return prgRule?prgRule->value:0.0; +} + + + int AQHREACT_PrgRule_Matches(const AQHREACT_PRGRULE *prgRule, int min, int hour, int dayOfMonth, int month, int dayOfWeek) { if ((prgRule->bitfieldMonth & (1L< @@ -67,6 +69,7 @@ u_zeroposnegstring.c u_module.c u_suntime.c + u_timeprogram.c diff --git a/apps/aqhome-react/units/u_timeprogram.c b/apps/aqhome-react/units/u_timeprogram.c new file mode 100644 index 0000000..81b34b2 --- /dev/null +++ b/apps/aqhome-react/units/u_timeprogram.c @@ -0,0 +1,325 @@ +/**************************************************************************** + * 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_timeprogram_p.h" + +#include +#include +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * defines + * ------------------------------------------------------------------------------------------------ + */ + +#define AQHOMEREACT_UNIT_TIMEPROGRAM_OUTSLOT_OUTPUT 0 + + +GWEN_INHERIT(AQHREACT_UNIT, AQHREACT_UNIT_TIMEPROGRAM); + + + +/* ------------------------------------------------------------------------------------------------ + * forward declarations + * ------------------------------------------------------------------------------------------------ + */ + +static MODULE_TIMER_ACTION *ModuleTimerAction_new(int hourTime, double value); +static void ModuleTimerAction_free(MODULE_TIMER_ACTION *act); + +static void GWENHYWFAR_CB _freeData(void *bp, void *p); +static int _cbProcess(AQHREACT_UNIT *unit); +static int _readRules(AQHREACT_UNIT *unit); + +static int _handleActionsForGivenTime(AQHREACT_UNIT *unit, int hourMins); +static int _checkAndAddActions(AQHREACT_UNIT *unit); +static int _addActionsForGivenTime(const GWEN_TIME *ti, + int hour, + const AQHREACT_PRGRULE_LIST *ruleList, + MODULE_TIMER_ACTION_LIST *actionList); + + + +/* ------------------------------------------------------------------------------------------------ + * implementations + * ------------------------------------------------------------------------------------------------ + */ + +GWEN_LIST_FUNCTIONS(MODULE_TIMER_ACTION, ModuleTimerAction); + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * ModuleTimerAction + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + */ + +MODULE_TIMER_ACTION *ModuleTimerAction_new(int hourTime, double value) +{ + MODULE_TIMER_ACTION *act; + + GWEN_NEW_OBJECT(MODULE_TIMER_ACTION, act); + GWEN_LIST_INIT(MODULE_TIMER_ACTION, act); + + act->hourMinutes=hourTime; + act->value=value; + + return act; +} + + + +void ModuleTimerAction_free(MODULE_TIMER_ACTION *act) +{ + if (act) { + GWEN_LIST_FINI(MODULE_TIMER_ACTION, act); + GWEN_FREE_OBJECT(act); + } +} + + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * AqHomeReact_UnitTimeProgram + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + */ + +AQHREACT_UNIT *AqHomeReact_UnitTimeProgram_new(AQHOME_REACT *aqh) +{ + AQHREACT_UNIT *unit; + AQHREACT_UNIT_TIMEPROGRAM *xunit; + AQHREACT_PORT *port; + AQHREACT_PARAM *param; + + unit=AQHREACT_Unit_new(aqh); + GWEN_NEW_OBJECT(AQHREACT_UNIT_TIMEPROGRAM, xunit); + GWEN_INHERIT_SETDATA(AQHREACT_UNIT, AQHREACT_UNIT_TIMEPROGRAM, unit, xunit, _freeData); + + xunit->actionList=ModuleTimerAction_List_new(); + AQHREACT_Unit_SetProcessFn(unit, _cbProcess); + + port=AQHREACT_Port_new(); + AQHREACT_Port_SetName(port, "output"); + AQHREACT_Port_SetIdForUnit(port, AQHOMEREACT_UNIT_TIMEPROGRAM_OUTSLOT_OUTPUT); + AQHREACT_Port_SetDataType(port, AQHREACT_DATAOBJECTTYPE_DOUBLE); + AQHREACT_Unit_AddOutputPort(unit, port); + + param=AQHREACT_Param_new(); + AQHREACT_Param_SetName(param, AQHOMEREACT_UNIT_TIMEPROGRAM_PARAM_RULES); + AQHREACT_Param_SetDataType(param, AQHREACT_DATAOBJECTTYPE_STRING); + AQHREACT_Unit_AddParam(unit, param); + + return unit; +} + + + +void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p) +{ + AQHREACT_UNIT_TIMEPROGRAM *xunit; + + xunit=(AQHREACT_UNIT_TIMEPROGRAM*) p; + + ModuleTimerAction_List_free(xunit->actionList); + AQHREACT_PrgRule_List_free(xunit->ruleList); + GWEN_FREE_OBJECT(xunit); +} + + + +int _cbProcess(AQHREACT_UNIT *unit) +{ + int didSomething=0; + + if (unit) { + AQHREACT_UNIT_TIMEPROGRAM *xunit; + + xunit=GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_TIMEPROGRAM, unit); + if (xunit) { + int rv; + + if (xunit->ruleList==NULL) { + rv=_readRules(unit); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + didSomething=1; + } + + rv=_checkAndAddActions(unit); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + if (rv>0) + didSomething=1; + } + } + return didSomething?1:0; +} + + + +int _checkAndAddActions(AQHREACT_UNIT *unit) +{ + AQHREACT_UNIT_TIMEPROGRAM *xunit; + GWEN_TIME *ti; + int didSomething=0; + + xunit=GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_TIMEPROGRAM, unit); + ti=GWEN_CurrentTime(); + if (ti) { + int hours; + int mins; + int secs; + int hourMins; + int rv; + + /* translate current time */ + rv=GWEN_Time_GetBrokenDownTime(ti, &hours, &mins, &secs); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + GWEN_Time_free(ti); + return rv; + } + hourMins=(hours*60)+mins; + + rv=GWEN_Time_AddSeconds(ti, 60*60); /* next hour */ + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + GWEN_Time_free(ti); + return rv; + } + + rv=GWEN_Time_GetBrokenDownTime(ti, &hours, &mins, &secs); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + GWEN_Time_free(ti); + return rv; + } + if (hours!=xunit->lastActionHour) { + DBG_INFO(NULL, "Adding actions for next hour %02d", hours); + _addActionsForGivenTime(ti, hours, xunit->ruleList, xunit->actionList); + xunit->lastActionHour=hours; + didSomething=1; + } + GWEN_Time_free(ti); + + rv=_handleActionsForGivenTime(unit, hourMins); + if (rv<0) { + DBG_INFO(NULL, "here (%d)", rv); + return rv; + } + if (rv>0) + didSomething=1; + } + + return didSomething?1:0; +} + + + +int _handleActionsForGivenTime(AQHREACT_UNIT *unit, int hourMins) +{ + AQHREACT_UNIT_TIMEPROGRAM *xunit; + MODULE_TIMER_ACTION *action; + int valueSent=0; + + xunit=GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_TIMEPROGRAM, unit); + action=ModuleTimerAction_List_First(xunit->actionList); + while(action) { + MODULE_TIMER_ACTION *nextAction; + + nextAction=ModuleTimerAction_List_Next(action); + if ((hourMins>action->hourMinutes) || (hourMins+(23*60))hourMinutes) { + ModuleTimerAction_List_Del(action); + DBG_INFO(NULL, "Sending output value %.2f", action->value); + AQHREACT_Unit_OutputDoubleData(unit, AQHOMEREACT_UNIT_TIMEPROGRAM_OUTSLOT_OUTPUT, action->value); + ModuleTimerAction_free(action); + valueSent=1; + } + + action=nextAction; + } + + return valueSent?1:0; +} + + + +int _addActionsForGivenTime(const GWEN_TIME *ti, int hour, const AQHREACT_PRGRULE_LIST *ruleList, MODULE_TIMER_ACTION_LIST *actionList) +{ + int actionsAdded=0; + GWEN_DATE *dt; + int dayOfMonth; + int month; + int dayOfWeek; + int mins; + + dt=GWEN_Date_fromTime(ti); + month=GWEN_Date_GetMonth(dt); + dayOfMonth=GWEN_Date_GetDay(dt); + dayOfWeek=GWEN_Date_WeekDay(dt); + GWEN_Date_free(dt); + + for (mins=0; mins<60; mins++) { + const AQHREACT_PRGRULE *rule; + + rule=AQHREACT_PrgRule_List_First(ruleList); + while(rule) { + if (AQHREACT_PrgRule_Matches(rule, mins, hour, dayOfMonth, month, dayOfWeek)>0) { + MODULE_TIMER_ACTION *act; + + act=ModuleTimerAction_new((hour*60)+mins, AQHREACT_PrgRule_GetValue(rule)); + ModuleTimerAction_List_Add(act, actionList); + actionsAdded=1; + } + rule=AQHREACT_PrgRule_List_Next(rule); + } + } + return actionsAdded?1:0; +} + + + +int _readRules(AQHREACT_UNIT *unit) +{ + AQHREACT_UNIT_TIMEPROGRAM *xunit; + const char *s; + + xunit=GWEN_INHERIT_GETDATA(AQHREACT_UNIT, AQHREACT_UNIT_TIMEPROGRAM, unit); + AQHREACT_PrgRule_List_free(xunit->ruleList); + xunit->ruleList=NULL; + + s=AQHREACT_Unit_GetParamValueString(unit, AQHOMEREACT_UNIT_TIMEPROGRAM_PARAM_RULES, NULL); + if (s) { + xunit->ruleList=AQHREACT_PrgRule_ReadRules(s); + if (xunit->ruleList==NULL) { + DBG_INFO(NULL, "Error reading rules from [%s]", s); + return GWEN_ERROR_BAD_DATA; + } + return 0; + } + else { + DBG_INFO(NULL, "No rules"); + return GWEN_ERROR_NO_DATA; + } +} + + + + + diff --git a/apps/aqhome-react/units/u_timeprogram.h b/apps/aqhome-react/units/u_timeprogram.h new file mode 100644 index 0000000..31a5b3f --- /dev/null +++ b/apps/aqhome-react/units/u_timeprogram.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_TIMEPROGRAM_H +#define AQHOMEREACT_U_TIMEPROGRAM_H + + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" + + +#define AQHOMEREACT_UNIT_TIMEPROGRAM_PARAM_RULES "rules" + + + +AQHREACT_UNIT *AqHomeReact_UnitTimeProgram_new(AQHOME_REACT *aqh); + + +#endif + + diff --git a/apps/aqhome-react/units/u_timeprogram_p.h b/apps/aqhome-react/units/u_timeprogram_p.h new file mode 100644 index 0000000..f01463a --- /dev/null +++ b/apps/aqhome-react/units/u_timeprogram_p.h @@ -0,0 +1,49 @@ +/**************************************************************************** + * 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_TIMEPROGRAM_P_H +#define AQHOMEREACT_U_TIMEPROGRAM_P_H + + +#include "./u_timeprogram.h" + +#include "aqhome-react/aqhome_react.h" +#include "aqhome-react/types/unit.h" +#include "aqhome-react/types/prgrule.h" + +#include + + + +typedef struct MODULE_TIMER_ACTION MODULE_TIMER_ACTION; +typedef struct AQHREACT_UNIT_TIMEPROGRAM AQHREACT_UNIT_TIMEPROGRAM; + +GWEN_LIST_FUNCTION_DEFS(MODULE_TIMER_ACTION, ModuleTimerAction) + + + +struct MODULE_TIMER_ACTION { + GWEN_LIST_ELEMENT(MODULE_TIMER_ACTION) + + int hourMinutes; + double value; +}; + + + +struct AQHREACT_UNIT_TIMEPROGRAM { + AQHREACT_PRGRULE_LIST *ruleList; + MODULE_TIMER_ACTION_LIST *actionList; + + int lastActionHour; +}; + + +#endif + +