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!!!
|