--    ======================
--    Description
--    ======================
--
--    Podwójne GWC bliźniacze. Każde GWC (oznaczone jako GWC1 i GWC2) jest sterowane przy pomocy siłownika z możliwością proporcjonalnego ustawienia. I odpowiednio oznacza:
--
--    0% - przepustnica sterująca całkowicie zamknięta
--    100% - przepustnica sterująca całkowicie otwarta
--
--    Definicje:
--
--    "Z czerpni" - oznacza przestawienie dwóch przepustnic do pozycji całkowicie otwartej (100%) i oznacza przepływ powietrza z czerpni wprost do budynku
--
--    "Z GWC" - oznacza przestawienie dwóch przepustnic do pozycji całkowicie zamkniętej (0%) i oznacza przepływ powietrza z czerpni przez GWC do budynku
--
--    "Regeneracja złoża" - oznacza cykliczne przestawienie przepustnic w/g zdefiniowanych pozycji. Do ustawienia powiązane następujące parametry:
--
--     - "pozycja 1" - wartość siłownika przepustnicy wyrażona w procentach. Zakres nastawy od 0% do 100% (np. 30%)
--     - "pozycja 2" - wartość siłownika przepustnicy wyrażona w procentach. Zakres nastawy od 0% do 100% (np. 0%)
--     - "pozycja 3" - wartość siłownika przepustnicy wyrażona w procentach. Zakres nastawy od 0% do 100% (np. 0%)
--     - "czas zmiany 1" - wyrażony w sekundach
--     - "czas zmiany 2" - wyrażony w sekundach
--
--    Jeżeli logika zdecyduje, że aktualnym trybem pracy ma być "regeneracja złoża" to oznacza to:
--
--    Faza 1:
--      - Ustawienie siłownika GWC1 w "pozycji 1" (zgodnie z przykładem 30%)
--      - Ustawienie siłownika GWC2 w "pozycji 2" (zgodnie z przykładem 0%)
--      - Po upłynięciu "czasu zmiany 1" następuje przejście do fazy 2
--    Faza 2:
--      - Ustawienie siłownika GWC1 w "pozycji 3" (zgodnie z przykładem 0%)
--      - Ustawienie siłownika GWC2 w "pozycji 3" (zgodnie z przykładem 0%)
--      - Po upłynięciu "czasu zmiany 2" następuje przejście do fazy 3
--    Faza 3:
--      - Ustawienie siłownika GWC1 w "pozycji 2" (zgodnie z przykładem 0%)
--      - Ustawienie siłownika GWC2 w "pozycji 1" (zgodnie z przykładem 30%)
--      - Po upłynięciu "czasu zmiany 1" następuje przejście do fazy 4
--    Faza 4:
--      - Ustawienie siłownika GWC1 w "pozycji 3" (zgodnie z przykładem 0%)
--      - Ustawienie siłownika GWC2 w "pozycji 3" (zgodnie z przykładem 0%)
--      - Po upłynięciu "czasu zmiany 2" następuje przejście do fazy 1
--
--    Właściwa logika działania:
--
--    W okresie letnim:
--
--    1. Jeżeli temperatura zewnętrzna jest równa lub niższa od setting.summer.t.1.value (np. 20*C) z uwzględnieniem histerezy setting.t.1.hyst (np. 1*C) to następuje pobór powietrza "z czerpni".
--    2. Jeżeli temperatura zewnętrzna jest równa lub większa od setting.summer.t.2.value (np. 30*C) z uwzględnieniem histerezy setting.t.2.hyst (np. 1*C) to następuje pobór powietrza "z GWC".
--    3. Jeżeli temperatura zewnętrzna jest w zakresie pomiędzy setting.summer.t.1.value (np. 20*C) i setting.summer.t.2.value (np. 30*C) z uwzględnieniem histerezy to następuje "regeneracja złoża".
--
--    W okresie zimowym:
--
--    1. Jeżeli temperatura zewnętrzna jest równa lub niższa od setting.winter.t.1.value (np. 0*C) z uwzględnieniem histerezy setting.t.1.hyst (np. 1*C) to następuje pobór powietrza "z GWC".
--    2. Jeżeli temperatura zewnętrzna jest równa lub większa od setting.winter.t.2.value (np. 20*C) z uwzględnieniem histerezy setting.t.2.hyst (np. 1*C) to następuje pobór powietrza "z czerpni".
--    3. Jeżeli temperatura zewnętrzna jest w zakresie pomiędzy setting.winter.t.1.value (np. 0*C) i setting.winter.t.2.value (np. 20*C) z uwzględnieniem histerezy to następuje "regeneracja złoża".
--
--    ======================
--    Parameters
--    ======================
--
--    SubLogic supports following variables:
--
--    input.outdoor.value
--    input.outdoor.err                       - temperatura zewnętrzna
--
--    input.season                            - 0 - zima, 1 - lato [0..1]
--
--    output.ghe.1                            - wyjście określające stan przepustnicy dla GWC1
--
--    output.ghe.2                            - wyjście określające stan przepustnicy dla GWC2
--
--    setting.reg.pos.1                       - wartość siłownika przepustnicy wyrażona w procentach. "Pozycja 1" z definicji dla regeneracji złoża.
--
--    setting.reg.pos.2                       - wartość siłownika przepustnicy wyrażona w procentach. "Pozycja 2" z definicji dla regeneracji złoża.
--
--    setting.reg.pos.3                       - wartość siłownika przepustnicy wyrażona w procentach. "Pozycja 3" z definicji dla regeneracji złoża.
--
--    setting.reg.time.1                      - "Czas zmiany 1" z definicji dla regeneracji złoża wyrażony w sekundach.
--
--    setting.reg.time.2                      - "Czas zmiany 2" z definicji dla regeneracji złoża wyrażony w sekundach.
--
--    setting.alert.t.output.ghe.1            - wartość output.ghe.1 w przypadku błędu temperatury
--
--    setting.alert.t.output.ghe.2            - wartość output.ghe.2 w przypadku błędu temperatury
--
--    setting.summer.t.1.value                - wartość temperatury t1 dla okresu letniego
--                                              Wartość musi być mniejsza od setting.summer.t.2.value minimum o setting.t.1.hyst / 2 + setting.t.2.hyst /2).
--                                              Jeżeli nie będzie zachowany ten warunek to wartość zostanie automatycznie skorygowana
--
--    setting.summer.t.2.value                - wartość temperatury t2 dla okresu letniego.
--                                              Wartość musi być większa od setting.summer.t.1.value minimum o setting.t.1.hyst / 2 + setting.t.2.hyst /2).
--                                              Jeżeli nie będzie zachowany ten warunek to wartość zostanie automatycznie skorygowana
--
--    setting.winter.t.1.value                - wartość temperatury t1 dla okresu zimowego
--                                              Wartość musi być mniejsza od setting.winter.t.2.value minimum o setting.t.1.hyst / 2 + setting.t.2.hyst /2).
--                                              Jeżeli nie będzie zachowany ten warunek to wartość zostanie automatycznie skorygowana
--
--    setting.winter.t.2.value                - wartość temperatury t2 dla okresu zimowego
--                                              Wartość musi być większa od setting.winter.t.1.value minimum o setting.t.1.hyst / 2 + setting.t.2.hyst /2	).
--                                              Jeżeli nie będzie zachowany ten warunek to wartość zostanie automatycznie skorygowana
--
--    setting.t.1.hyst                        - histereza powiązana z temperaturą t1
--
--    setting.t.2.hyst                        - histereza powiązana z temperaturą t2
--
--    counter.alert.t.state                   - jeżeli któryś z czujników jest uszkodzony to ta flaga jest ustawiana na 1.
--
--    counter.reg.phase.current               - aktualna faza dla regeneracji złoża. 0 - nie jest realizowana funkcja regeneracji złoża.
--
--    counter.reg.phase.downcounter           - pozostały czas do zmiany fazy regeneracji złoża
--
--    counter.t.1.value                       - aktualna wartość progu t1
--
--    counter.t.1.lower.status                - czy temperatura zewnętrzna jest niższa od progu t1 z uwzględnieniem histerezy setting.t.1.hyst
--
--    counter.t.2.value                       - aktualna wartość progu t2
--
--    counter.t.2.higher.status               - czy temperatura zewnętrzna jest wyższa od progu t2 z uwzględnieniem histerezy setting.t.2.hyst
--
--    Logic uses lua language to implement own behaviour
--
--    ======================
--    mandatory variables
--    ======================
--
--    Logic expects following mandatory variables:
--
--    reload.trigger                          - causes reloading lua script
--
--    memcnt                                  - current amount of memory used by lua in bytes
--
--    Logic expects following kv settings:
--
--    LuaScriptPath                           - path to the lua script - must be absolute
--
--    ======================
--    ChangeLog
--    ======================
--
--    2024-06-24 ver 1.0.0
--
--    # zmiana nazwy parametru outside -> outdoor
--
--    2019-07-02 ver 0.0.0
--
--    # First release
--
-- user can use some functions provided by ibmanager.

-- user can use some functions provided by ibmanager.

-- ibmanager provides following functions to use:
--
-- function returns value of required ibmanager variable
-- @param fullName - string - variable name - name of variable of which value must be returned, for example "rs.0.id.255.input.t.0.value"
-- @return         - string or integer - variable value or "nil" if variable not exist or is not readable
--
-- getValue(fullName)


-- function set value of given ibmanager variable
-- @param fullName - string - variable name - name of variable of which value we want to set, for example "rs.0.id.255.input.t.0.value"
-- @param value    - string, int or boolean - value to set
-- @return         - nothing
--
-- setValue(fullName, value)


-- function returns value of required ibmanager variable
-- @param key      - placed in xml logic configuration file:
--                   * as attribute: Name, in Var, RemoteVar and ImportVar elements in the case of stand alone variables
--                   * as concatenation of two attributes: ListName.Postfix in VarListItem, RemoteVarListItem and ImportVarListItem elements
--                     in the case of variables that are placed in lists
-- @return         - string or integer - variable value or "nil" if variable not exist or is not readable
--
-- getLogicValue(key)


-- function set value of given ibmanager variable
-- @param key      - placed in xml logic configuration file:
--                   * as attribute: Name, in Var, RemoteVar and ImportVar elements in the case of stand alone variables
--                   * as concatenation of two attributes: ListName.Postfix in VarListItem, RemoteVarListItem and ImportVarListItem elements
--                     in the case of variables that are placed in lists
-- @param value    - string, int or boolean - value to set
-- @return         - nothing
--
-- setLogicValue(key, value)

-- function returns two sections of kvsettings from xml configuration file
-- returned value is two element table, each of these elements is table too.
-- indices of returned table are strings and equal "instance" and "global"
-- values of returned tables are tables and contain KVsettings for applicable section.
-- nested tables have form key = value, where key is index in nested table and value is value.
-- example: {"instance" = {"ikey1" = "ivalue1", "ikey2" = "gvalue2"}, "global" = {"gkey1" = "gvalue1", "gkey2" = "gvalue2", "gkey3" = "gvalue3"}}
-- @return          - two dimensional array - kvsettings for global and instance sections
-- getKvSettings()


-- function schedules alert to send.
-- rules are defined in separated alert configuration files and are described in ibmanager instruction manual
-- @param id - alert identifier - must be defined in current logic configuration file in section: <Alert Id="any_identifier" ...
-- scheduleAlert(id)

-- function cancels alert sending, if was previously scheduled. if not then only wakes up alerts handling thread, so if there is no need to call this function, then do not call it.
-- rules are defined in separated alert configuration files and are described in ibmanager instruction manual
-- @param id - alert identifier - must be defined in current logic configuration file in section: <Alert Id="any_identifier" ...
-- cancelAlert(name)

-- function returns table, containing Variables that belongs to required list.
-- @param listName - Name attribute of VarList, RemoteVarList or ImportVarList elemetnst in configurationfile
-- @return array of key-value pairs. Key - variable postfix, Value - Variable value
-- getVarList(listName)

-- function returns monotonic system clock value, that elapsed since specific epoch
-- returned time is expressed in milliseconds.
-- getClock()

-- function logs message to file, if defined in configuration file log level is less than passed to this function
-- @param logLevel - one of:
--        LogLevel.TraceLo
--        LogLevel.Trace
--        LogLevel.TraceHi
--        LogLevel.DebugLo
--        LogLevel.Debug
--        LogLevel.DebugHi
--        LogLevel.Info
--        LogLevel.Notice
--        LogLevel.Warning
--        LogLevel.Error
--        LogLevel.Critical
-- @param logMessage - string to log
-- log(logLevel, logMessage)


-- ibmanager provides following global variables:

-- logic type, (in this case it will always be "Lua") - the same as in logic configuration file in section: <Logic Type="Lua" ...
-- LOGIC_TYPE

-- logic version, the same as in logic configuration file in section: <Logic ... Version="x.y.z" ...
-- LOGIC_VERSION

-- logic sub-type, the same as in logic configuration file in section: <Logic ... SubType="Hysteresis" ...
-- LOGIC_SUBTYPE

-- logic sub-version, the same as in logic configuration file in section: <Logic ... SubVersion="x.y.z" ...
-- LOGIC_SUBVERSION

-- logic instance name - the same as in logic configuration file, in section: <Instance Name="0">
-- LOGIC_INSTANCE_NAME

-- add script directory to package path
package.path = package.path .. ";./logic/scripts/utils/?.lua";

-- use script - without .lua extension - delta class
require("State");
require("DownCounter");

g_outputGhe1 = nil;
g_outputGhe2 = nil;
g_counterT1LowerStatus = nil;
g_counterT2HigherStatus = nil;

g_counterRegPhaseCurrent = 0;
g_counterRegPhaseDowncounter = nil;

g_settingSummerT2Value = nil;
g_settingSummerT1Value = nil;
g_settingWinterT2Value = nil;
g_settingWinterT1Value = nil;

SUPPORTED_SUBLOGIC_TYPE = "GHE02";
SUPPORTED_SUBLOGIC_VERSION = "1.0.0";
g_versionChecked = false;

-- entry point to the logic
-- @param firstCall - tells if logic is called first time
-- @return        - nothing
function onLogicCall(firstCall)

  if not g_versionChecked then
    -- checking sublogic type and sublogic version
    if LOGIC_SUBTYPE ~= SUPPORTED_SUBLOGIC_TYPE then
      error("Wrong logic sub-type. expected " .. SUPPORTED_SUBLOGIC_TYPE .. " but used " .. LOGIC_SUBTYPE);
    end
    local versionWithoutBuild = string.match(LOGIC_SUBVERSION, "[0-9]+%.[0-9]+%.[0-9]+");
    if versionWithoutBuild ~= SUPPORTED_SUBLOGIC_VERSION then
      error("Wrong logic sub-version. expected " .. SUPPORTED_SUBLOGIC_VERSION .. " but used " .. LOGIC_SUBVERSION);
    end
    g_versionChecked = true;
  end

  local inputOutdoorValue = getLogicValue("input.outdoor.value");
  local inputOutdoorErr = getLogicValue("input.outdoor.err");
  local inputSeason = getLogicValue("input.season");
  
  local settingRegPos1 = getLogicValue("setting.reg.pos.1");
  local settingRegPos2 = getLogicValue("setting.reg.pos.2");
  local settingRegPos3 = getLogicValue("setting.reg.pos.3");
  local settingRegTime1 = getLogicValue("setting.reg.time.1");
  local settingRegTime2 = getLogicValue("setting.reg.time.2");
  local settingAlertTOutputGhe1 = getLogicValue("setting.alert.t.output.ghe.1");
  local settingAlertTOutputGhe2 = getLogicValue("setting.alert.t.output.ghe.2");
  local settingSummerT1Value = getLogicValue("setting.summer.t.1.value");
  local settingSummerT2Value = getLogicValue("setting.summer.t.2.value");
  local settingWinterT1Value = getLogicValue("setting.winter.t.1.value");
  local settingWinterT2Value = getLogicValue("setting.winter.t.2.value");
  local settingT1Hyst = getLogicValue("setting.t.1.hyst");
  local settingT2Hyst = getLogicValue("setting.t.2.hyst");

  local counterAlertTState = 0;
  local counterRegPhaseDowncounter = 0;
  local counterT1Value = 0;
  local counterT2Value = 0;

  -- states
  if g_outputGhe1 == nil or firstCall then
    g_outputGhe1 = State.create(0, 0, 100, true);
  end
  g_outputGhe1:call();
  
  if g_outputGhe2 == nil or firstCall then
    g_outputGhe2 = State.create(0, 0, 100, true);
  end
  g_outputGhe2:call();
  
  if g_counterT1LowerStatus == nil or firstCall then
    g_counterT1LowerStatus = State.create(0, 0, 1, true);
  end
  g_counterT1LowerStatus:call();
  
  if g_counterT2HigherStatus == nil or firstCall then
    g_counterT2HigherStatus = State.create(0, 0, 1, true);
  end
  g_counterT2HigherStatus:call();
  
  -- timers

  if g_counterRegPhaseDowncounter == nil or firstCall then
    g_counterRegPhaseDowncounter = DownCounter.create();
  end
  
  -- wartość w zależności od fazy
  if (g_counterRegPhaseCurrent == 0) then
    g_counterRegPhaseDowncounter:updateParams(0);
    g_counterRegPhaseDowncounter:reset();
  elseif (g_counterRegPhaseCurrent == 1) or (g_counterRegPhaseCurrent == 3) then
    g_counterRegPhaseDowncounter:updateParams(settingRegTime1 * 1000);
  else
    g_counterRegPhaseDowncounter:updateParams(settingRegTime2 * 1000);
  end

--  if g_counterRegPhaseDowncounter:elapsed() then
--    g_counterRegPhaseDowncounter:reset();
--  end

  counterRegPhaseDowncounter = g_counterRegPhaseDowncounter:timeTo0() / 1000;
  counterRegPhaseDowncounter = (counterRegPhaseDowncounter < 0) and 0 or counterRegPhaseDowncounter;

  -- obsługa alarmu temperatur
  if (inputOutdoorErr ~= 0) then
      counterAlertTState = 1;
  end

  if ((counterAlertTState ~= 0)) then
    g_outputGhe1:setValue(settingAlertTOutputGhe1);
    g_outputGhe2:setValue(settingAlertTOutputGhe2);
  end

  --zabezpieczenie wartości settingSummer
  if g_settingSummerT2Value == nil or firstCall then
    g_settingSummerT2Value = settingSummerT2Value;
  end

  if g_settingSummerT1Value == nil or firstCall then
    g_settingSummerT1Value = settingSummerT1Value;
  end 

  if (g_settingSummerT2Value ~= settingSummerT2Value) then
    if (settingSummerT2Value <= settingSummerT1Value + settingT1Hyst / 2 + settingT2Hyst / 2) then
      settingSummerT2Value = settingSummerT1Value + settingT1Hyst / 2 + settingT2Hyst / 2;
      setLogicValue("setting.summer.t.2.value", settingSummerT2Value);
    end
  end

  if (g_settingSummerT1Value ~= settingSummerT1Value) then
    if (settingSummerT1Value >= settingSummerT2Value - settingT1Hyst / 2 - settingT2Hyst / 2) then
      settingSummerT1Value = settingSummerT2Value - settingT1Hyst / 2 - settingT2Hyst / 2;
      setLogicValue("setting.summer.t.1.value", settingSummerT1Value);
    end
  end

  -- w przypadku pozostałości ze storage
  if (settingSummerT2Value <= settingSummerT1Value + settingT1Hyst / 2 + settingT2Hyst / 2) then
    settingSummerT2Value = settingSummerT1Value + settingT1Hyst / 2 + settingT2Hyst / 2;
    setLogicValue("setting.summer.t.2.value", settingSummerT2Value);
  end

  g_settingSummerT2Value = settingSummerT2Value;
  g_settingSummerT1Value = settingSummerT1Value;

  --zabezpieczenie wartości settingWinter
  if g_settingWinterT2Value == nil or firstCall then
    g_settingWinterT2Value = settingWinterT2Value;
  end

  if g_settingWinterT1Value == nil or firstCall then
    g_settingWinterT1Value = settingWinterT1Value;
  end 

  if (g_settingWinterT2Value ~= settingWinterT2Value) then
    if (settingWinterT2Value <= settingWinterT1Value + settingT1Hyst / 2 + settingT2Hyst / 2) then
      settingWinterT2Value = settingWinterT1Value + settingT1Hyst / 2 + settingT2Hyst / 2;
      setLogicValue("setting.winter.t.2.value", settingWinterT2Value);
    end
  end

  if (g_settingWinterT1Value ~= settingWinterT1Value) then
    if (settingWinterT1Value >= settingWinterT2Value - settingT1Hyst / 2 - settingT2Hyst / 2) then
      settingWinterT1Value = settingWinterT2Value - settingT1Hyst / 2 - settingT2Hyst / 2;
      setLogicValue("setting.winter.t.1.value", settingWinterT1Value);
    end
  end

  -- w przypadku pozostałości ze storage
  if (settingWinterT2Value <= settingWinterT1Value + settingT1Hyst / 2 + settingT2Hyst / 2) then
    settingWinterT2Value = settingWinterT1Value + settingT1Hyst / 2 + settingT2Hyst / 2;
    setLogicValue("setting.winter.t.2.value", settingWinterT2Value);
  end

  g_settingWinterT2Value = settingWinterT2Value;
  g_settingWinterT1Value = settingWinterT1Value;
  
  -- realizacja regeneracji złoża
  if (g_counterRegPhaseCurrent ~= 0) then
    
    if g_counterRegPhaseDowncounter:elapsed() then
      g_counterRegPhaseCurrent = g_counterRegPhaseCurrent + 1;
      if (g_counterRegPhaseCurrent == 5) then
        g_counterRegPhaseCurrent = 1;
      end
      
      g_counterRegPhaseDowncounter:reset();
    end
    
    if (g_counterRegPhaseCurrent == 1) then
      g_outputGhe1:setValue(settingRegPos1);
      g_outputGhe2:setValue(settingRegPos2);
    elseif (g_counterRegPhaseCurrent == 2) then
      g_outputGhe1:setValue(settingRegPos3);
      g_outputGhe2:setValue(settingRegPos3);
    elseif (g_counterRegPhaseCurrent == 3) then
      g_outputGhe1:setValue(settingRegPos2);
      g_outputGhe2:setValue(settingRegPos1);
    elseif (g_counterRegPhaseCurrent == 4) then
      g_outputGhe1:setValue(settingRegPos3);
      g_outputGhe2:setValue(settingRegPos3);
    end
  
  end

  -- ustalenie temperatur t1 i t2 oraz sposób działania
  if (inputSeason == 0) then
    -- w sezonie zimowym
    counterT1Value = settingWinterT1Value;
    counterT2Value = settingWinterT2Value;

    g_counterT1LowerStatus:set1IfLowerThan(inputOutdoorValue, counterT1Value, settingT1Hyst);
    g_counterT2HigherStatus:set1IfHigherThan(inputOutdoorValue, counterT2Value, settingT2Hyst);
    
    -- Jeżeli temperatura zewnętrzna jest równa lub niższa od setting.winter.t.1.value (np. 0*C) z uwzględnieniem histerezy setting.t.1.hyst (np. 1*C) to następuje pobór powietrza "z GWC".
    if g_counterT1LowerStatus:getValue() == 1 then
      g_outputGhe1:setValue(0);
      g_outputGhe2:setValue(0);
      g_counterRegPhaseCurrent = 0;
    end
    
    -- Jeżeli temperatura zewnętrzna jest równa lub większa od setting.winter.t.2.value (np. 20*C) z uwzględnieniem histerezy setting.t.2.hyst (np. 1*C) to następuje pobór powietrza "z czerpni".
    if g_counterT2HigherStatus:getValue() == 1 then
      g_outputGhe1:setValue(100);
      g_outputGhe2:setValue(100);
      g_counterRegPhaseCurrent = 0;
    end
    
    -- Jeżeli temperatura zewnętrzna jest w zakresie pomiędzy setting.winter.t.1.value (np. 0*C) i setting.winter.t.2.value (np. 20*C) z uwzględnieniem histerezy to następuje "regeneracja złoża".
    if (g_counterT1LowerStatus:getValue() == 0) and (g_counterT2HigherStatus:getValue() == 0) and (g_counterRegPhaseCurrent == 0) then
      g_counterRegPhaseCurrent = 1;
    end   
    
  else
    -- w sezonie letnim
    counterT1Value = settingSummerT1Value;
    counterT2Value = settingSummerT2Value;

    g_counterT1LowerStatus:set1IfLowerThan(inputOutdoorValue, counterT1Value, settingT1Hyst);
    g_counterT2HigherStatus:set1IfHigherThan(inputOutdoorValue, counterT2Value, settingT2Hyst);
  
    -- Jeżeli temperatura zewnętrzna jest równa lub niższa od setting.summer.t.1.value (np. 20*C) z uwzględnieniem histerezy setting.t.1.hyst (np. 1*C) to następuje pobór powietrza "z czerpni".
    if g_counterT1LowerStatus:getValue() == 1 then
      g_outputGhe1:setValue(100);
      g_outputGhe2:setValue(100);
      g_counterRegPhaseCurrent = 0;
    end
  
    -- Jeżeli temperatura zewnętrzna jest równa lub większa od setting.summer.t.2.value (np. 30*C) z uwzględnieniem histerezy setting.t.2.hyst (np. 1*C) to następuje pobór powietrza "z GWC".
    if g_counterT2HigherStatus:getValue() == 1 then
      g_outputGhe1:setValue(0);
      g_outputGhe2:setValue(0);
      g_counterRegPhaseCurrent = 0;
    end

    -- Jeżeli temperatura zewnętrzna jest w zakresie pomiędzy setting.summer.t.1.value (np. 20*C) i setting.summer.t.2.value (np. 30*C) z uwzględnieniem histerezy to następuje "regeneracja złoża".
    if (g_counterT1LowerStatus:getValue() == 0) and (g_counterT2HigherStatus:getValue() == 0) and (g_counterRegPhaseCurrent == 0) then
      g_counterRegPhaseCurrent = 1;
    end   
  end

  -- send logic variables to ibmanager
  setLogicValue("output.ghe.1", g_outputGhe1:getValue());
  setLogicValue("output.ghe.2", g_outputGhe2:getValue());
  setLogicValue("counter.alert.t.state", counterAlertTState); 
  setLogicValue("counter.reg.phase.current", g_counterRegPhaseCurrent); 
  setLogicValue("counter.reg.phase.downcounter", counterRegPhaseDowncounter);
  setLogicValue("counter.t.1.value", counterT1Value);
  setLogicValue("counter.t.1.lower.status", g_counterT1LowerStatus:getValue());
  setLogicValue("counter.t.2.value", counterT2Value);
  setLogicValue("counter.t.2.higher.status", g_counterT2HigherStatus:getValue());

end
