--    ======================
--    Description
--    ======================
--
--    Obsługa kotła gazowego przez H3F11.
--
--    W trybie pracy 2 (setting.mode) praca kotła gazowego (priorytet wykonania w/g kolejności):
--
--      - jeżeli pompa kominka pracuje (pali się w kominku) to kocioł jest wyłączony
--      - jeżeli pompa kominka nie pracuje a jest błąd któregoś z czujników to stan kotła jest zgodny z wejściem (input.gb.work.signal)
--      - jeżeli na którymkolwiek z czujników w zbiorniku buforowym jest wyższa temperatura
--        niż minimalna to zablokuj prace kotła w celu wykorzystania energii zgromadzonej w buforze
--      - w dalszej kolejności stan kotła jest niezależny od wymaganej temperatury w sprzęgle (jest przenoszony wprost z sygnału input.gb.work.signal)
--
--    Pompa buforowa jest włączona w celu przekazania ciepła z buforu do sprzęgła hydraulicznego jeżeli wszystkie poniższe
--    warunki są spełnione:
--
--      - jest wymagane ogrzewania sprzęgła
--      - na którymkolwiek z czujników w zbiorniku buforowym jest wyższa temperatura niż w sprzęgle hydraulicznym o zadaną DT
--
--    Pompa buforowa jest włączona w celu przekazania nadwyżki ciepła ze sprzęgła hydraulicznego do zbiornika buforowego
--    jeżeli wszystkie poniższe warunki są spełnione:
--
--      - nie jest wymagane ogrzewania sprzęgła
--      - kocioł gazowy jest wyłączony
--      - pompa kominka jest włączona
--      - upłynął ustalony czas od zdjęcia blokady rozładowania sprzęgła hydraulicznego (zabezpieczenie przed zbyt szybkim odebraniem
--        ciepła wyprodukowanego przez źródła konwencjonalne np. kocioł gazowy)
--      - na którymkolwiek z czujników w zbiorniku buforowym jest niższa temperatura niż w sprzęgle hydraulicznym o zadaną DT
--
--    W pozostałych przypadkach pompa buforowa zostaje wyłączona.
--
--    ======================
--    Parameters
--    ======================
--
--    SubLogic supports following variables:
--
--    input.gb.work.signal                    - sygnał wejściowy załączenia kotła [0..1]
--
--    input.buff.pump.block.signal            - sygnał wejściowy blokady pompy buforowej
--
--    input.fp.pump                           - stan pracy pompy kominkowej
--
--    input.tank.buff.top.t.value
--    input.tank.buff.top.t.err               - temperatura u góry zbiornika buforowego
--
--    input.tank.buff.bottom.t.value
--    input.tank.buff.bottom.t.err            - temperatura na dole zbiornika buforowego
--
--    input.hyd.t.value
--    input.hyd.t.err                         - temperatura w sprzęgle hydraulicznym
--
--
--    output.gb.work.signal                   - sygnał wyjściowy załączenia kotła.
--
--    output.buff.pump                        - pompa buforowa
--
--    output.h3f11.setting.heater.signal.mode
--    output.h3f11.setting.hyd.heat.demand
--    output.h3f11.setting.hyd.t.demand
--    output.h3f11.setting.heater.signal.manual.value
--    output.h3f11.setting.buff.pump.mode
--    output.h3f11.setting.buff.pump.manual.value
--                                            - parametry wysyłane do h3f11
--
--    setting.hyd.t.demand                    - temperatura wymagana w sprzęgle hydraulicznym
--
--    setting.hyd.t.hyst                      - histereza dla operacji powiązanych z temperaturą w sprzęgle hydraulicznym
--
--    setting.buff.min.t.demand               - Minimalna temperatura w zbiorniku buforowym do blokowania pracy kotła
--
--    setting.buff.min.t.hyst                 - histereza dla operacji powiązanych z temperaturą w zbiorniku buforowym
--
--    setting.mode                            - tryb pracy
--                                                0 - kocioł wyłączony
--                                                1 - kocioł włączony
--                                                2 - kocioł wyłączony jeżeli pali się w kominku lub w buforze na dole jest odpowiednia temperatura
--                                                3 - kocioł praca niezależna od kominka i bufora
--
--    setting.alert.t.err.buff.pump.state     - jaką ma przyjąć wartość pompa buforowa w przypadku uszkodzenia któregoś czujnika
--
--    setting.buff.pump.dt.on
--    setting.buff.pump.dt.off                - delta uruchomienia pompy buforowej do celów ładowania i rozładowywania bufora
--
--    setting.buff.pump.delay                 - zwłoka czasowa do załączeniu pombu buforowej (do celów ładowanie bufora) od momentu
--                                              zaniku blokady rozładowania sprzęgła hydraulicznego.
--
--    setting.gb.mode                         - tryb pracy kotła (0 - AUTO; 1 - Manual)
--
--    setting.gb.manual.value                 - tryb pracy kotła w trybie manualnym [0..1]
--
--    setting.buff.pump.mode                  - tryb pracy pompy buforowej (0 - AUTO; 1 - Manual)
--
--    setting.buff.pump.manual.value          - tryb pracy pompy buforowej w trybie manualnym [0..1]
--
--    counter.buff2hyd.dt.state               - flaga: czy warunek na różnicy temperatur (setting.buff.pump.dt) pomiędzy temperaturą w buforze
--                                              a temperaturą w sprzęgle hydraulicznym jest spełniony (warunek ładowania sprzęgła, rozładowania bufora)
--
--    counter.hyd2buff.dt.state               - flaga: czy warunek na różnicy temperatur (setting.buff.pump.dt) pomiędzy temperaturą w sprzęgle hydraulicznym
--                                              a temperaturą w buforze jest spełniony (warunek ładowania bufora, rozładowania sprzęgła)
--
--    counter.hyd.t.demand                    - flaga: czy jest wymagane ogrzewanie sprzegła hydraulicznego.
--
--    counter.buff.t.min                      - flaga: czy jest spełniony warunek temperatury minimalnej
--                                              (czy temperatura w buforze jest poniżej minimalnej setting.buff.min.t.demand).
--
--    counter.buff.pump.dt.state              - stan pompy z uwagi na różnicę temperatur (setting.buff.pump.dt):
--
--                                                0 - pompa buforowa nie pracuje
--                                                1 - pompa buforowa pracuje ponieważ temp. w sprzęgle jest większa niż
--                                                    temp. w buforze (ładuje bufor, rozładowuje sprzęgło) i temperatura
--                                                    panująca w sprzęgle jest wyższa niż wymagana
--                                                2 - pompa buforowa pracuje ponieważ temp. w buforze jest większa niż
--                                                    temp. w sprzęgle (ładuje sprzęgło, rozładowuje bufor) i temperatura
--                                                    panująca w sprzęgle jest wyższa niż wymagana
--
--    counter.buff.pump.delay.downtimer       - pozostały czas blokady pompy buforowej (do celów ładowanie bufora)
--
--    counter.alert.t.err                     - flaga: wartość 1 oznacza uszkodzenie jakiegokolwiek czujnika. Uszkodzenie czujnika nie ma wpływu na prace kotła gazowego.
--
--    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
--    ======================
--
--    2019-12-05 ver 0.3.5.0
--
--    + obsługa manualna pompy buforowej i kotła gazowego
--    # ładowanie zbiornika buforowego jest możliwe tylko jeżeli pracuje pompa kominka
--
--    2019-05-15 ver 0.2.4.0
--
--    # zmiana nazw wejść i wyjść gb
--    + obsługa pompy buforowej
--
--    2017-06-23 ver 0.1.3.0
--
--    # bug związany z pracą zależną od kominka
--
--    2017-06-23 ver 0.0.2.0
--
--    # zabezpieczenie przed nieprawidłową wartością minimalną wymaganej w sprzęgle hydraulicznym.
--
--    2017-06-07 ver 0.0.1.825
--
--    # obsługa automatycznego build'a
--
--    2017-03-31 ver 0.0.0
--
--    # First release
--
--
-- 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_outputGbWorkSignal = nil;
g_outputBuffPump = nil;
g_counterBuff2hydDtState = nil;
g_counterHyd2buffDtState = nil;
g_counterHydTDemand = nil;
g_counterBuffTMin = nil;

g_counterBuffPumpDelayDowntimer = nil;


g_settingBuffPumpDtOn = nil;
g_settingBuffPumpDtOff = nil;

SUPPORTED_SUBLOGIC_TYPE = "Gbh3f11v4";
SUPPORTED_SUBLOGIC_VERSION = "0.3.5";
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 inputGbWorkSignal = getLogicValue("input.gb.work.signal");
  local inputFpPump = getLogicValue("input.fp.pump");
  local inputBuffPumpBlockSignal = getLogicValue("input.buff.pump.block.signal");
  local inputTankBuffTopTValue = getLogicValue("input.tank.buff.top.t.value");
  local inputTankBuffTopTErr = getLogicValue("input.tank.buff.top.t.err");
  local inputTankBuffBottomTValue = getLogicValue("input.tank.buff.bottom.t.value");
  local inputTankBuffBottomTErr = getLogicValue("input.tank.buff.bottom.t.err");
  local inputHydTValue = getLogicValue("input.hyd.t.value");
  local inputHydTErr = getLogicValue("input.hyd.t.err");
  local settingHydTDemand = getLogicValue("setting.hyd.t.demand");
  local settingHydTHyst = getLogicValue("setting.hyd.t.hyst");
  local settingBuffMinTDemand = getLogicValue("setting.buff.min.t.demand");
  local settingBuffMinTHyst = getLogicValue("setting.buff.min.t.hyst");
  local settingMode = getLogicValue("setting.mode");
  local settingAlertTErrBuffPumpState = getLogicValue("setting.alert.t.err.buff.pump.state");
  local settingBuffPumpDtOn = getLogicValue("setting.buff.pump.dt.on");
  local settingBuffPumpDtOff = getLogicValue("setting.buff.pump.dt.off");
  local settingBuffPumpDelay = getLogicValue("setting.buff.pump.delay");
  local settingGbMode = getLogicValue("setting.gb.mode");
  local settingGbManualValue = getLogicValue("setting.gb.manual.value");
  local settingBuffPumpMode = getLogicValue("setting.buff.pump.mode");
  local settingBuffPumpManualValue = getLogicValue("setting.buff.pump.manual.value");

  local outputH3f11SettingHeaterSignalMode = 1;
  local outputH3f11SettingHydHeatDemand = 0;
  local outputH3f11SettingHydTDemand = 10;
  local outputH3f11SettingHeaterSignalManualValue = 0;
  local outputH3f11SettingBuffPumpMode = 1;
  local outputH3f11SettingBuffPumpManualValue = 0;

  local counterAlertTErr = 0;
  local counterBuffPumpDtState = 0;
  local counterBuffPumpDelayDowntimer = 0;

-- timers
  if g_counterBuffPumpDelayDowntimer == nil or firstCall then
    g_counterBuffPumpDelayDowntimer = DownCounter.create();
  end
  g_counterBuffPumpDelayDowntimer:updateParams(settingBuffPumpDelay * 1000);

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

  if (inputBuffPumpBlockSignal == 1) then
    g_counterBuffPumpDelayDowntimer:reset();
  end

  counterBuffPumpDelayDowntimer = g_counterBuffPumpDelayDowntimer:timeTo0() / 1000;
  counterBuffPumpDelayDowntimer = (counterBuffPumpDelayDowntimer < 0) and 0 or counterBuffPumpDelayDowntimer;

-- states
  if g_outputGbWorkSignal == nil or firstCall then
    g_outputGbWorkSignal = State.create(0, 0, 1, true);
  end
  g_outputGbWorkSignal:call();

  if g_outputBuffPump == nil or firstCall then
    g_outputBuffPump = State.create(0, 0, 1, true);
  end
  g_outputBuffPump:call();

  if g_counterBuff2hydDtState == nil or firstCall then
    g_counterBuff2hydDtState = State.create(0, 0, 1, true);
  end
  g_counterBuff2hydDtState:call();

  if g_counterHyd2buffDtState == nil or firstCall then
    g_counterHyd2buffDtState = State.create(0, 0, 1, true);
  end
  g_counterHyd2buffDtState:call();

  if g_counterHydTDemand == nil or firstCall then
    g_counterHydTDemand = State.create(0, 0, 1, true);
  end
  g_counterHydTDemand:call();

  if g_counterBuffTMin == nil or firstCall then
    g_counterBuffTMin = State.create(0, 0, 1, true);
  end
  g_counterBuffTMin:call();

  --BuffPumpDt - zabezpieczenie przed nieprawidłowymi wartościami dt
  if g_settingBuffPumpDtOn == nil or firstCall then
    g_settingBuffPumpDtOn = settingBuffPumpDtOn;
  end

  if g_settingBuffPumpDtOff == nil or firstCall then
    g_settingBuffPumpDtOff = settingBuffPumpDtOff;
  end

  if (g_settingBuffPumpDtOn ~= settingBuffPumpDtOn) then
    if (settingBuffPumpDtOn <= settingBuffPumpDtOff) then
      settingBuffPumpDtOn = settingBuffPumpDtOff + 1;
      setLogicValue("setting.buff.pump.dt.on", settingBuffPumpDtOn);
    end
  end

  if (g_settingBuffPumpDtOff ~= settingBuffPumpDtOff) then
    if (settingBuffPumpDtOff >= settingBuffPumpDtOn) then
      settingBuffPumpDtOff = settingBuffPumpDtOn - 1;
      setLogicValue("setting.buff.pump.dt.off", settingBuffPumpDtOff);
    end
  end

  -- w przypadku pozostałości ze storage
  if (settingBuffPumpDtOn <= settingBuffPumpDtOff) then
    settingBuffPumpDtOn = settingBuffPumpDtOff + 1;
    setLogicValue("setting.buff.pump.dt.on", settingBuffPumpDtOn);
  end

  g_settingBuffPumpDtOn = settingBuffPumpDtOn;
  g_settingBuffPumpDtOff = settingBuffPumpDtOff;

  -- wymagana temperatura która trafia do sterownika (zabezpieczenie)
  outputH3f11SettingHydTDemand = settingHydTDemand;
  if (outputH3f11SettingHydTDemand < 10) then
    outputH3f11SettingHydTDemand = 10;
  end

  -- alert uszkodzonego czujnika
  if (inputTankBuffTopTErr ~= 0) or
     (inputTankBuffBottomTErr ~= 0) or
     (inputHydTErr ~= 0) then
    counterAlertTErr = 1;
  end

  -- sterowanie kotłem gazowym w trybie manualnym
  if settingGbMode == 1 then
    g_outputGbWorkSignal:setValue(settingGbManualValue);
  end

  -- sterowanie pompą buforową w trybie manualnym
  if settingBuffPumpMode == 1 then
    g_outputBuffPump:setValue(settingBuffPumpManualValue);
  end

  g_counterHydTDemand:set1IfLowerThan(inputHydTValue, settingHydTDemand, settingHydTHyst);


  if (inputTankBuffTopTValue > inputTankBuffBottomTValue) then
     g_counterBuff2hydDtState:setIfDelta(inputTankBuffTopTValue, inputHydTValue, settingBuffPumpDtOn, settingBuffPumpDtOff);
     g_counterHyd2buffDtState:setIfDelta(inputHydTValue, inputTankBuffBottomTValue, settingBuffPumpDtOn, settingBuffPumpDtOff);
     g_counterBuffTMin:set1IfLowerThan(inputTankBuffTopTValue, settingBuffMinTDemand, settingBuffMinTHyst);
  else
     g_counterBuff2hydDtState:setIfDelta(inputTankBuffBottomTValue, inputHydTValue, settingBuffPumpDtOn, settingBuffPumpDtOff);
     g_counterHyd2buffDtState:setIfDelta(inputHydTValue, inputTankBuffTopTValue, settingBuffPumpDtOn, settingBuffPumpDtOff);
     g_counterBuffTMin:set1IfLowerThan(inputTankBuffBottomTValue, settingBuffMinTDemand, settingBuffMinTHyst);
  end

  -- stan wyjść podczas alertu uszkodzonego czujnika
  if counterAlertTErr == 1 then
    g_outputBuffPump:setValue(settingAlertTErrBuffPumpState);
  end

  -- sterowanie kotłem gazowym w zależności od trybu pracy

  -- kocioł stale włączony
  if settingMode == 1 then
    g_outputGbWorkSignal:setValue(1);

  -- kocioł wyłączony jeżeli pali się w kominku lub w buforze na dole jest odpowiednia temperatura
  elseif settingMode == 2 then

    -- jeżeli pompa kominka nie pracuje
    if  inputFpPump == 0 then

      -- jeżeli któryś z czujników uszkodzony to kocioł pracuje zgodnie z sygnałem wejściowym
      if counterAlertTErr == 1 then
        g_outputGbWorkSignal:setValue(inputGbWorkSignal);
      end

      -- jeżeli na którymkolwiek z czujników w zbiorniku buforowym jest wyższa temperatura
      -- niż minimalna to zablokuj prace kotła w celu wykorzystania energii zgromadzonej w buforze

      if (g_counterBuffTMin:getValue() == 0) then
        g_outputGbWorkSignal:setValue(0);
      end

      g_outputGbWorkSignal:setValue(inputGbWorkSignal);

    else
      -- jeżeli pompa kominka pracuje to wyłącz kocioł gazowy
      g_outputGbWorkSignal:setValue(0);
    end

  -- praca niezależna od kominka lub temperatury w buforze
  elseif settingMode == 3 then
    g_outputGbWorkSignal:setValue(inputGbWorkSignal);
  else

    -- kocioł wyłączony
    g_outputGbWorkSignal:setValue(0);
  end


  -- sterowanie pompą buforową

  if (g_counterHydTDemand:getValue() == 1) and (g_counterBuff2hydDtState:getValue() == 1) then
    g_outputBuffPump:setValue(1);
  end

  if (g_counterHydTDemand:getValue() == 0) and
     (g_outputGbWorkSignal:getValue() == 0) and
     (counterBuffPumpDelayDowntimer == 0) and
     (inputFpPump == 1) and
     (g_counterHyd2buffDtState:getValue() == 1) then
    g_outputBuffPump:setValue(1);
  end

  g_outputBuffPump:setValue(0);

  -- przełącz obsługę wyjść w sterowniku na sterowanie ręczne (czyli z logiki)
  outputH3f11SettingHeaterSignalMode = 1;
  outputH3f11SettingBuffPumpMode = 1;

  -- wpisanie wartości do sterownika
  outputH3f11SettingHeaterSignalManualValue = g_outputGbWorkSignal:getValue();
  outputH3f11SettingBuffPumpManualValue = g_outputBuffPump:getValue();
  outputH3f11SettingHydHeatDemand = g_counterHydTDemand:getValue();

-- send logic variables to ibmanager
  setLogicValue("output.gb.work.signal", g_outputGbWorkSignal:getValue());
  setLogicValue("output.buff.pump", g_outputBuffPump:getValue());
  setLogicValue("output.h3f11.setting.heater.signal.mode", outputH3f11SettingHeaterSignalMode);
  setLogicValue("output.h3f11.setting.hyd.heat.demand", outputH3f11SettingHydHeatDemand);
  setLogicValue("output.h3f11.setting.hyd.t.demand", outputH3f11SettingHydTDemand);
  setLogicValue("output.h3f11.setting.heater.signal.manual.value", outputH3f11SettingHeaterSignalManualValue);
  setLogicValue("output.h3f11.setting.buff.pump.mode", outputH3f11SettingBuffPumpMode);
  setLogicValue("output.h3f11.setting.buff.pump.manual.value", outputH3f11SettingBuffPumpManualValue);
  setLogicValue("counter.alert.t.err", counterAlertTErr);
  setLogicValue("counter.buff2hyd.dt.state", g_counterBuff2hydDtState:getValue());
  setLogicValue("counter.hyd2buff.dt.state", g_counterHyd2buffDtState:getValue());
  setLogicValue("counter.hyd.t.demand", g_counterHydTDemand:getValue());
  setLogicValue("counter.buff.t.min", g_counterBuffTMin:getValue());
  setLogicValue("counter.buff.pump.dt.state", counterBuffPumpDtState);
  setLogicValue("counter.buff.pump.delay.downtimer", counterBuffPumpDelayDowntimer);

end
