/**************************************************************************** * 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; }