Logic Machine Forum
OR LOGIC VIA TAG - Printable Version

+- Logic Machine Forum (https://forum.logicmachine.net)
+-- Forum: LogicMachine eco-system (https://forum.logicmachine.net/forumdisplay.php?fid=1)
+--- Forum: Scripting (https://forum.logicmachine.net/forumdisplay.php?fid=8)
+--- Thread: OR LOGIC VIA TAG (/showthread.php?tid=3446)



OR LOGIC VIA TAG - RafalBor - 26.06.2021

Hi,

could you please check script below. All tagged properly in the project, but when true signal comes from one of 30 objects nothing is being written to group 34/1/10

Code:
if not client then
  -- each group has 3 fields:
  -- tag - status object tag
  -- output - status output object
  -- mode - calculate mode (and/or/avg)
  groups =
 
    { tag = 'ORGATEZONESDEMAND', output = '34/1/10', mode = 'or' }

 

  -- time to wait between last telegram from any status in group and update
  updatedelay = 0.5

  -- object value cache
  values = {}

  -- object datatype cache
  datatypes = {}

  -- send update only when value changes
  grp.checkupdate = function(alias, value)
    if values[ alias ] ~= value then
      grp.update (alias, value)
    end
  end

  calc = {}

  -- AVERAGE value
  calc['avg'] = function(group)
    local result, count, value = 0, 0

    for _, address in ipairs(group.objects) do
      value = values[ address ]

      -- number must be in [0..100] range
      if type(value) == 'number' then
        result = result + value
        count = count + 1
      -- boolean true is 100%, false is 0%
      elseif type(value) == 'boolean' then
        if toboolean(value) then
          result = result + 100
        end

        count = count + 1
      end
    end

    if count > 0 then
      result = math.floor(result / count + 0.5)
      grp.checkupdate(group.output, result)
    end
  end

  -- AND gate
  calc['and'] = function(group)
    local result = true

    for _, address in ipairs(group.objects) do
      result = result and toboolean(values[ address ])
    end

    grp.checkupdate(group.output, result)
  end

  -- OR gate
  calc['or'] = function(group)
    local result = false

    for _, address in ipairs(group.objects) do
      result = result or toboolean(values[ address ])
    end

    grp.checkupdate(group.output, result)
  end

  -- prepare each group
  for _, group in ipairs(groups) do
    object = grp.find(group.output)

    -- cache output status object value and datatype
    values[ object.address ] = object.data
    datatypes[ object.address ] = object.datatype
    group.output = object.address

    -- group input status object list
    group.objects = {}

    -- find all status objects and cache values and datatypes
    objects = grp.tag(group.tag)
    for _, object in ipairs(objects) do
      values[ object.address ] = object.data
      datatypes[ object.address ] = object.datatype
      table.insert(group.objects, object.address)
    end

    -- force update on first run
    group.timer = 0

    -- calc function reference
    group.fn = calc[ group.mode ]
  end

  -- handle group writes
  function eventhandler(event)
    local dst, datatype

    dst = event.dst
    datatype = datatypes[ event.dst ]
    -- unknown object, stop
    if not datatype then
      return
    end

    values[ dst ] = dpt.decode(event.datahex, datatype)

    -- check if any group needs to be updated
    for _, group in ipairs(groups) do
      for _, address in ipairs(group.objects) do
        if address == dst then
          group.timer = updatedelay
        end
      end
    end
  end

  require('genohm-scada.eibdgm')
  client = eibdgm:new({ timeout = 0.25 })
  client:sethandler('groupwrite', eventhandler)
end

tsec, tusec = os.microtime()
client:step()
delta = os.udifftime(tsec, tusec)

-- check if any group has an active timer
for _, group in ipairs(groups) do
  timer = group.timer

  if timer then
    timer = timer - delta

    -- timer expired, run calc function
    if timer <= 0 then
      group.fn(group)
      timer = nil
    end

    group.timer = timer
  end
end



RE: OR LOGIC VIA TAG - admin - 26.06.2021

You are missing {} around groups definition, it should be like this:
Code:
groups = {
  { tag = ... }
}



RE: OR LOGIC VIA TAG - RafalBor - 26.06.2021

(26.06.2021, 13:26)admin Wrote: You are missing {} around groups definition, it should be like this:
Code:
groups = {
  { tag = ... }
}

Thank you,

still no update signal coming to 34/1/10. I'm just thinking if in the part --send update  instead of grp.update should be grp.write


RE: OR LOGIC VIA TAG - RafalBor - 26.06.2021

grp. write doesn't work either


RE: OR LOGIC VIA TAG - admin - 28.06.2021

Works for me (resident, sleep time = 0). Make sure that the output object is created and that it does not have ORGATEZONESDEMAND tag.
Code:
if not client then
  -- each group has 3 fields:
  -- tag - status object tag
  -- output - status output object
  -- mode - calculate mode (and/or/avg)
  groups = {  
    { tag = 'ORGATEZONESDEMAND', output = '34/1/10', mode = 'or' }
  }
  
  -- time to wait between last telegram from any status in group and update
  updatedelay = 0.5

  -- object value cache
  values = {}

  -- object datatype cache
  datatypes = {}

  -- send update only when value changes
  grp.checkupdate = function(alias, value)
    if values[ alias ] ~= value then
      grp.update (alias, value)
    end
  end

  calc = {}

  -- AVERAGE value
  calc['avg'] = function(group)
    local result, count, value = 0, 0

    for _, address in ipairs(group.objects) do
      value = values[ address ]

      -- number must be in [0..100] range
      if type(value) == 'number' then
        result = result + value
        count = count + 1
      -- boolean true is 100%, false is 0%
      elseif type(value) == 'boolean' then
        if toboolean(value) then
          result = result + 100
        end

        count = count + 1
      end
    end

    if count > 0 then
      result = math.floor(result / count + 0.5)
      grp.checkupdate(group.output, result)
    end
  end

  -- AND gate
  calc['and'] = function(group)
    local result = true

    for _, address in ipairs(group.objects) do
      result = result and toboolean(values[ address ])
    end

    grp.checkupdate(group.output, result)
  end

  -- OR gate
  calc['or'] = function(group)
    local result = false

    for _, address in ipairs(group.objects) do
      result = result or toboolean(values[ address ])
    end

    grp.checkupdate(group.output, result)
  end

  -- prepare each group
  for _, group in ipairs(groups) do
    object = grp.find(group.output)

    -- cache output status object value and datatype
    values[ object.address ] = object.data
    datatypes[ object.address ] = object.datatype
    group.output = object.address

    -- group input status object list
    group.objects = {}

    -- find all status objects and cache values and datatypes
    objects = grp.tag(group.tag)
    for _, object in ipairs(objects) do
      values[ object.address ] = object.data
      datatypes[ object.address ] = object.datatype
      table.insert(group.objects, object.address)
    end

    -- force update on first run
    group.timer = 0

    -- calc function reference
    group.fn = calc[ group.mode ]
  end

  -- handle group writes
  function eventhandler(event)
    local dst, datatype

    dst = event.dst
    datatype = datatypes[ event.dst ]
    -- unknown object, stop
    if not datatype then
      return
    end

    values[ dst ] = dpt.decode(event.datahex, datatype)

    -- check if any group needs to be updated
    for _, group in ipairs(groups) do
      for _, address in ipairs(group.objects) do
        if address == dst then
          group.timer = updatedelay
        end
      end
    end
  end

  require('genohm-scada.eibdgm')
  client = eibdgm:new({ timeout = 0.25 })
  client:sethandler('groupwrite', eventhandler)
end

tsec, tusec = os.microtime()
client:step()
delta = os.udifftime(tsec, tusec)

-- check if any group has an active timer
for _, group in ipairs(groups) do
  timer = group.timer

  if timer then
    timer = timer - delta

    -- timer expired, run calc function
    if timer <= 0 then
      group.fn(group)
      timer = nil
    end

    group.timer = timer
  end
end



RE: OR LOGIC VIA TAG - manos@dynamitec - 06.04.2022

Hello admin,

Can the part below be edit to be able to calculate with a resolution of 1 decimal point the average value of 2byte float or any byte value (temp, brightness, power ...)? Now in the script says the value must be between 0-100.

Code:
-- AVERAGE value
  calc['avg'] = function(group)
    local result, count, value = 0, 0

    for _, address in ipairs(group.objects) do
      value = values[ address ]

      -- number must be in [0..100] range!!!!!!!!!!!!!!!!!
      if type(value) == 'number' then
        result = result + value
        count = count + 1
      -- boolean true is 100%, false is 0%
      elseif type(value) == 'boolean' then
        if toboolean(value) then
          result = result + 100
        end

        count = count + 1
      end
    end

    if count > 0 then
      result = math.floor(result / count + 0.5)
      grp.checkwrite(group.output, result)
    end
  end

Thank you in advance

(06.04.2022, 20:49)manos@dynamitec Wrote: Hello admin,

Can the part below be edit to be able to calculate with a resolution of 1 decimal point the average value of 2byte float or any byte value (temp, brightness, power ...)? Now in the script says the value must be between 0-100.

Code:
-- AVERAGE value
  calc['avg'] = function(group)
    local result, count, value = 0, 0

    for _, address in ipairs(group.objects) do
      value = values[ address ]

      -- number must be in [0..100] range!!!!!!!!!!!!!!!!!
      if type(value) == 'number' then
        result = result + value
        count = count + 1
      -- boolean true is 100%, false is 0%
      elseif type(value) == 'boolean' then
        if toboolean(value) then
          result = result + 100
        end

        count = count + 1
      end
    end

    if count > 0 then
      result = math.floor(result / count + 0.5)
      grp.checkwrite(group.output, result)
    end
  end

Thank you in advance


I guess just removing math.floor(..........+0.5) is the solution to this?


RE: OR LOGIC VIA TAG - admin - 07.04.2022

The 0..100 range is only needed when binary and scale objects are used together. This way binary ON is considered 100%.

For general average use this:
Code:
-- AVERAGE value
  calc['avg'] = function(group)
    local result, count, value = 0, 0

    for _, address in ipairs(group.objects) do
      value = values[ address ]

      if type(value) == 'number' then
        result = result + value
        count = count + 1
      end
    end

    if count > 0 then
      grp.checkwrite(group.output, result / count)
    end
  end



RE: OR LOGIC VIA TAG - manos@dynamitec - 07.04.2022

(07.04.2022, 06:53)admin Wrote: The 0..100 range is only needed when binary and scale objects are used together. This way binary ON is considered 100%.

For general average use this:
Code:
  -- AVERAGE value
  calc['avg'] = function(group)
    local result, count, value = 0, 0

    for _, address in ipairs(group.objects) do
      value = values[ address ]

      if type(value) == 'number' then
        result = result + value
        count = count + 1
      end
    end

    if count > 0 then
      grp.checkwrite(group.output, result / count)
    end
  end


Thank you for the great support as usual!!! Smile