Posts: 133
Threads: 28
Joined: May 2016
Reputation:
3
05.01.2017, 08:08
(This post was last modified: 07.01.2017, 10:57 by Habib.
Edit Reason: add solved Tag
)
Hi,
at moment I search for a way to get a total sum of all Lights in my house with state on. The same I have for opened windows and it works for me, but I think my way is not much elegenat.
I have create one KNX Object for the sum count total. Then I created on each windows object an event which gets the value from the total sum and add or substract the total value (+1 or -1).
That works because are only few windows (19) and the action on that is very slow. But if I try to do it for my downlights on the same way it doesn't works.
I have 110 Downlights in my house and each of them has its own status object. I have done that, because I use many different scenes and wants to have in all ways the exact visualisiation. In my living room I have 30 downlights and If I do the calculation in that way I described before, It calculates every times wrong.
In next step I reverted that and put the calculation in the event script of the event trigger (switch/button) and do the calculation for the whole group (+3 or +24 and so on). But it doesn't work also. In some cases it works, in other combination not...
My idea is now to create a functionality to get the status of all tagged objects (maybe tag: "downlight status") on every 2 minutes. but the disadvantage is, that I have much more traffic and CPU/Bus load.
What is the best way to do such functionality?
Thank you forwards
BR
Habib
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
05.01.2017, 11:31
(This post was last modified: 07.01.2017, 11:40 by buuuudzik.)
Hi Habib,
this is a script for central status calculations from forum with a little update of sum function.
output - how many lamps are switched on from tagged
counter - how many lamps are tagged for sum
This should be Resident script 0s.
Code: if not client then
-- each group has 3 or 4 fields:
-- tag - status object tag
-- output - status output object
-- mode - calculate mode (and/or/avg/sum)
-- counter - calculate number of light which are tagged(only sum function)
groups = {
--samples
-- { tag = 'my_group_and', output = '4/0/0', mode = 'and' },
-- { tag = 'my_group_or', output = '4/0/1', mode = 'or' },
-- { tag = 'my_group_avg', output = '4/0/2', mode = 'avg' },
-- { tag = 'my_group_sum', output = '4/0/3', mode = 'sum', counter = '4/0/4' },
--mean temperature
{ tag = 'Lamp', output = '8/2/37', mode = 'sum', counter = '8/2/25' },
--number of lights which are switched on
{ tag = 'Kitchen_L_sum', output = '0/0/64', mode = 'sum', counter = '0/0/65' },
{ tag = 'Livingroom_L_sum', output = '0/0/64', mode = 'sum', counter = '0/0/65' },
{ tag = 'Garderobe_L_sum', output = '0/0/64', mode = 'sum', counter = '0/0/65' },
{ tag = 'Hall_L_sum', output = '0/0/64', mode = 'sum', counter = '0/0/65' },
{ tag = 'Floor1_L_sum', output = '0/0/64', mode = 'sum', counter = '0/0/65' },
}
-- time to wait between last telegram from any status in group and update
updatedelay = 0.5
timeout = updatedelay / 2
-- 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
-- SUM value
calc['sum'] = 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 value then
result = result + 1
end
count = count + 1
end
if count > 0 then
grp.checkupdate(group.output, result)
grp.checkupdate(group.counter, count)
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.1 })
client:sethandler('groupwrite', eventhandler)
end
delta = 0
repeat
tsec, tusec = os.microtime()
client:step()
tdelta = os.udifftime(tsec, tusec)
-- clock jump
if tdelta < 0 then
delta = timeout
else
delta = delta + tdelta
end
until delta >= timeout
-- 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
Posts: 133
Threads: 28
Joined: May 2016
Reputation:
3
Hi buuuudzik,
wow, thx. A ready solution? I will try it at weekend.
A resident script with 0s. Produce it not to much CPU load?
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
No, because there is a variable updatedelay=0,5s(you can change this for more) so the effect is that this script has interval more than 0,5s.
But be careful with number of group addresses which are calculated by this script. I think the sum of 100-200 shouldn't be a problem but more and more can produce some weard beahaviour(in your case bad number of lamps which are switched on and number of whole lamps).
Posts: 411
Threads: 103
Joined: Oct 2016
Reputation:
9
Hi
In my project I have > 500 bulbs. My experience is the better way is to use two layers in these calculations. First layer (aka kitchen, bedroom) where every room contains less than 10 lights is calculated in per event based scripts. The second layer is calculated just from the first layer's results as a resident task.
I use DALI gateways. I experimented with DALI cumulative feedback but the result was unreliable. The reason was DALI sends not one but few other cumulative feedback according to DALI program and DALI bus state. And from time to time it happened on KNX bus the first telegram outran the second telegram.
LM5Lp, firmware: 2018.08.22 and 2021.12.15, FlashSYS v2, ARMv7 Processor rev 5 (v7l), kernel 4.4.151 and 4.4.259
Posts: 200
Threads: 60
Joined: Jun 2015
Reputation:
7
Hi,
I do a similar thing, individual lights are tagged to rooms, the rooms are tagged to a floor or areas, the floors\areas are tagged to the whole house \ apartment. That works great. That way you get a status at all of the levels.
Thanks
Roger
Posts: 133
Threads: 28
Joined: May 2016
Reputation:
3
07.01.2017, 09:49
(This post was last modified: 07.01.2017, 09:49 by Habib.)
Hi,
@buuuudzik
it works great for me. What I don't understand is, why the "OR" logic don't works...
AND and AVERAGE works, so I made a simple quick&dirty mod and added a forth object "COUNT" and modified for that the function avarage to get the amount of lights which are in state on.
I understand that script in that way, that I can use one script for each room, or sum of windows and so on, for each value I will count. Is that correct?
For example I count with Tag "Spots" all my Downlights which I tagged... If I want to count open windows, I take another copy of that script and Tag all my windows status objects with "windows", and I will get a value for opened windows. ...
Posts: 200
Threads: 60
Joined: Jun 2015
Reputation:
7
Hi,
I have also applied this with temperatures too, the following will average Celsius temps and then convert it to Fahrenheit.
Code: -- Temperature AVERAGE value
calc['tempavg'] = 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
end
end
if count > 0 then
result = result / count
local fahren= math.floor(((result * 9 / 5 + 32) * 10^2) + 0.5) / (10^2)
grp.checkupdate(group.output, fahren)
end
end
Thanks,
Roger
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
But event scripts can be not a good solution when there is some change of whole room or much more when there is whole floor change. Then there are a lot of unnecessary serial calculations of every event. With this resident script you can also prepare some layers and I use also such solutions.
More on this forum about this task(more about OR calculations but also universal):
http://forum.logicmachine.net/showthread...l+statuses
http://forum.logicmachine.net/showthread...l+statuses
Posts: 133
Threads: 28
Joined: May 2016
Reputation:
3
@buuuudzik
did you mean me with your answer? If yes, you missunderstood me. I use multiple resident scripts to count for different groups. I agree with you, taht event based scripts for an global stat is not a good idea. That was the reason for this thread.
Thank you very much :-)
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
(07.01.2017, 11:32)Habib Wrote: @buuuudzik
did you mean me with your answer? If yes, you missunderstood me. I use multiple resident scripts to count for different groups. I agree with you, taht event based scripts for an global stat is not a good idea. That was the reason for this thread.
Thank you very much :-)
This was only an exchange of some experience with this complex subject that everybody should have whole background of this subject(Preparing the elegant solution for calculating central statuses).
But for this script recommended is to using only 1 with whole groups(Kitchen, Livingroom, 1Floor etc.). I updated this script a few minute ago because I saw that there was no sum function Now there is. Please check.
Posts: 133
Threads: 28
Joined: May 2016
Reputation:
3
that's great :-)
I have adopted your new version. I think the functionality should be part of the original installation.
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
07.01.2017, 18:57
(This post was last modified: 07.01.2017, 19:00 by buuuudzik.)
First version was prepared by Edgars so he can everything. I agree with you but I think it should be not a script but a special app with simple editor. Another think is that this version is simpler to change for suit it to specific solutions.
|