Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
You can also replace [0].innerHTML with jQuery's .html()
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
13.06.2016, 09:18
(This post was last modified: 13.06.2016, 09:30 by Erwin van der Zwart.)
(13.06.2016, 09:02)admin Wrote: You can also replace [0].innerHTML with jQuery's .html()
Thanks Admin,
The code will be like this then:
Here is the final sample for changing color with css based on setpoint and actual value difference.
Give the first setpoint these additional classes 'Setp Setp_1', the 2nd 'Setp Setp_2', the 3th 'Setp Setp_3' etc
Give the first actual these additional classes 'Temp Temp_1', the 2nd 'Temp Temp_2', the 3th 'Temp Temp_3' etc
So all setpoints will have 2 additional classes (Setp and Setp_nr) and all actuals will have 2 additional classes (Temp and Temp_nr)
Make sure to use incredimental sequense 1,2,3,4,5 etc. without gaps as Temp_nr and Setp_nr (the number makes the match between both)
Put this code in your custom JavaScript:
Code: $(function(){
// Set color values
var defaultcolor = $('.Temp').css("color") // Use color that is default set on the object
var highcolor = 'rgb(0, 153, 204)' // Blue
var lowcolor = 'rgb(204, 153, 0)' // Orange
// Function to change colors on values
function CheckSetpointandValue(){
// Check if and how many elements there are with additional class 'Temp'
if ($(".Temp").length > 0){
// Set number of items to loop through based on additional class 'Temp' items
var TempValueItems = $(".Temp").length // Determine number of compare items
// Set difference between actual and setpoint to change color
var MinimalDifference = 0.5 // Determine minnimal difference between setpoint and actual temperature
// Loop to items to set CSS
for (i = 1; (i-1) < TempValueItems; i++) {
// Set conditions for Setp_nr and Temp_nr
if ( Number( $(".Temp_" + i).html() ) > ( Number( $(".Setp_" + i).html() ) + MinimalDifference ) ){
$(".Temp_" + i).css("color", highcolor);
} else if ( ( Number( $(".Temp_" + i).html() ) + MinimalDifference ) < Number( $(".Setp_" + i).html() ) ){
$(".Temp_" + i).css("color", lowcolor);
} else {
$(".Temp_" + i).css("color", defaultcolor);
}
}
}
}
// Check for changes on value of item with Temp
$('.Temp').bind("DOMSubtreeModified",function(){
CheckSetpointandValue();
});
// Check for changes on value of item with Setp
$('.Setp').bind("DOMSubtreeModified",function(){
CheckSetpointandValue();
});
// Initial execution
CheckSetpointandValue();
});
BR,
Erwin
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
You are very wise
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
(13.06.2016, 09:36)buuuudzik Wrote: You are very wise
No, i just like to puzzle (;
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
Maybe you can describe in very simple way how to:
- read from object database value of some group address,
- write to object database value of some group address(with or without write to the bus),
- read some additional object's info like "updatetime".
And also if there is a possibility to prepare the OR and AND gates for a few objects for calculating the room statuses and central statuses or something else.
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
13.06.2016, 13:09
(This post was last modified: 13.06.2016, 13:29 by Erwin van der Zwart.)
(13.06.2016, 12:21)buuuudzik Wrote: Maybe you can describe in very simple way how to:
- read from object database value of some group address,
- write to object database value of some group address(with or without write to the bus),
- read some additional object's info like "updatetime".
And also if there is a possibility to prepare the OR and AND gates for a few objects for calculating the room statuses and central statuses or something else.
Hi Buuuudzik,
All your questions are possible and are used in many of the custom JavaScript samples on this forum.
Please try to create some scripts based on those samples. I'm happy to give samples / solutions that are not on the forum yet.
The idea is that the users are helped with our samples, not to do the work for them (;
Why do you want to create the logic client side? The logic won't work when visu is not active. I would advice to keep logic server side with LUA
Here are the answers on your question:
// Look at possible values from objects (updatetime is not there) It's possible to get that info when using a APP with .lp files but not from Custom Javascript
console.log(objectStore.objects)
// Get values from object(s)
value = objectStore.objects[Scada.encodeGroupAddress('1/1/3')].value
value1 = objectStore.objects[Scada.encodeGroupAddress('1/1/3')].value
name = objectStore.objects[Scada.encodeGroupAddress('1/1/3')].name
console.log(value)
console.log(name)
// Write to object
var id = Scada.encodeGroupAddress('1/1/3'), obj = objectStore.objects[ id ], value = 10;
setObjectValue({ address: obj.address , rawdatatype: obj.rawdatatype }, value, "text");
// AND fuction
if ( value == 1 && value1 == 1 ) {
// dosomething)
}
// OR function
if ( value == 1 || value1 == 1 ) {
// dosomething)
}
BR,
Erwin
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
(13.06.2016, 13:09)Erwin van der Zwart Wrote: (13.06.2016, 12:21)buuuudzik Wrote: Maybe you can describe in very simple way how to:
- read from object database value of some group address,
- write to object database value of some group address(with or without write to the bus),
- read some additional object's info like "updatetime".
And also if there is a possibility to prepare the OR and AND gates for a few objects for calculating the room statuses and central statuses or something else.
Hi Buuuudzik,
All your questions are possible and are used in many of the custom JavaScript samples on this forum.
Please try to create some scripts based on those samples. I'm happy to give samples / solutions that are not on the forum yet.
The idea is that the users are helped with our samples, not to do the work for them (;
Why do you want to create the logic client side? The logic won't work when visu is not active. I would advice to keep logic server side with LUA
Here are the answers on your question:
// Look at possible values from objects (updatetime is not there) It's possible to get that info when using a APP with .lp files but not from Custom Javascript
console.log(objectStore.objects)
// Get values from object(s)
value = objectStore.objects[Scada.encodeGroupAddress('1/1/3')].value
value1 = objectStore.objects[Scada.encodeGroupAddress('1/1/3')].value
name = objectStore.objects[Scada.encodeGroupAddress('1/1/3')].name
console.log(value)
console.log(name)
// Write to object
var id = Scada.encodeGroupAddress('1/1/3'), obj = objectStore.objects[ id ], value = 10;
setObjectValue({ address: obj.address , rawdatatype: obj.rawdatatype }, value, "text");
// AND fuction
if ( value == 1 && value1 == 1 ) {
// dosomething)
}
// OR function
if ( value == 1 || value1 == 1 ) {
// dosomething)
}
BR,
Erwin
I want use this function on client side because when you have a house which has much more than few rooms using tags and event-based scripts on regular LM is not the best solution(in my opinion). Maybe I can improve something in my scripts but maybe it is optimal way and LM can't deal with a lot of changes in a very little time e.g. central off.
Central statuses e.g. "Room_n status" or "Floor_n status" or "All_Floors status" are used general on the visualisation so preparing them by the client is also good and much faster than the regular LM.
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
13.06.2016, 14:09
(This post was last modified: 13.06.2016, 14:14 by Erwin van der Zwart.)
Hi Buuuudzik,
I would definitly check your scripts, we use our controller for buildings up to 20 floors where we have approx 500 KNX devices behind each controller (as zone coupler) and those have much more data then a single house. We run all scripts server side...
Also be aware when you open your visu on multiple locations your logic runs multiple times, don't write to the controller on those cases, but keep client side logic inside visu only.
BR,
Erwin
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
(13.06.2016, 14:09)Erwin van der Zwart Wrote: Hi Buuuudzik,
I would definitly check your scripts, we use our controller for buildings up to 20 floors where we have approx 500 KNX devices behind each controller (as zone coupler) and those have much more data then a single house. We run all scripts server side...
Also be aware when you open your visu on multiple locations your logic runs multiple times, don't write to the controller on those cases, but keep client side logic inside visu only.
BR,
Erwin
I know this and I am aware about that in such case logic can run multiple times.
I can show my mechanism which is based on this:
http://forum.logicmachine.net/showthread...l+statuses
This is what I do:
This lamps has tag "Room1" and change the status of Room1_status:
Lamp1.1_status
Lamp1.2_status
Lamp1.3_status...
The same is with rooms which have tags e.g. "Floor1_status":
Room1_status
Room2_status
Room3_status...
Third level is "Central_status" which is configured in the same way.
All of this functions are based on the function tag_or(tag) which is included in user-libraries:
Code: function tag_or(tag)
local objects, result
result = false
objects = grp.tag(tag)
for _, object in ipairs(objects) do
result = result or object.data
end
return result
end
The advantage of this solution is that the statuses are structured and simple to change or extend with new one.
I respect you Erwin, and probably there some other way to do this but I don't know in what other way I can do this. How do you do this in your big projects? Do you create also Room statuses or no?
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
13.06.2016, 19:59
(This post was last modified: 13.06.2016, 20:42 by Erwin van der Zwart.)
Hi Buuuudzik,
I think the iterate of the result table is taking a lot of resources, especially when having the execution of multiple scripts in parallel from the tag group
You could try to do it with a direct query from DB to avoid the table iterate and speed up things a bit.
Code: function tag_or(tag)
local result = db:getall('SELECT id FROM objects WHERE datahex = "01" AND tagcache LIKE "%' .. tag .. '%"')
if #result == 0 then
return false
else
return true
end
end
You can also add this script in the start of your script to kill previous script when executed multiple times in parallel.
Code: --check for earlier started scrips
storagename = 'TAG_OR' -- Must be unique for every script
--check storage for tpid value
tpid = storage.get(storagename)
--check if tpid has a value
if tpid == nil then
pid = os.getpid()
storage.set(storagename, pid)
else
pid = os.getpid()
-- create new pid for next time to kill
storage.set(storagename, pid)
-- kill earlier running script
os.kill(tpid, signal.SIGKILL)
end
If this doesn't do the trick you can use the semaphore library making it possible to block parallel execution of scripts
See http://openrb.com/docs/semaphore.htm or http://openrb.com/event-script-which-can...rotection/
BR,
Erwin van der Zwart
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
13.06.2016, 20:32
(This post was last modified: 13.06.2016, 20:35 by buuuudzik.)
(13.06.2016, 19:59)PErwin van der Zwart Wrote: Hi Buuuudzik,
I think the iterate of the result table is taking a lot of resources, especially when having the execution of multiple scripts in parallel from the tag group
You could try to do it with a direct query from DB to avoid the table iterate and speed up things a bit.
Code: function tag_or(tag)
local result = db:getall('SELECT id FROM objects WHERE datahex = "01" AND tagcache LIKE "%' .. tag .. '%"')
if #result == 0 then
return false
else
return true
end
end
You can also add this script in the start of your script to kill previous script when executed multiple times in parallel.
Code: --check for earlier started scrips
storagename = 'TAG_OR' -- Must be unique for every script
--check storage for tpid value
tpid = storage.get(storagename)
--check if tpid has a value
if tpid == nil then
pid = os.getpid()
storage.set(storagename, pid)
else
pid = os.getpid()
-- create new pid for next time to kill
storage.set(storagename, pid)
-- kill earlier running script
os.kill(tpid, signal.SIGKILL)
end
If this doesn't do the trick you can use the semaphore library making it possible to block parallel execution of scripts
See http://openrb.com/docs/semaphore.htm
BR,
Erwin van der Zwart
Very good tip, I will try tommorrow. Thanks, you're the best. I think this will be helpful for a lot of LM medium programmers like me?
Posts: 187
Threads: 43
Joined: Jul 2015
Reputation:
2
(13.04.2016, 11:27)edgars Wrote: In the firmware starting from 4.2016 there is Custom JavaScript feature available in LogicMachine --> Scripting --> Tools --> Edit custom JavaScript.
It is possible to create different dynamic tasks, like detect short/long press from visualization using one icon (Erwin, will you please add your example here) or as in this example, we can open specific Floor/Plan when some grp address is triggered - useful e.g. when you want IP Camera page automatically to be opened when Intercom button is pressed:
Code: $(function(){
if (typeof objectStore !== 'undefined') {
var id = Scada.encodeGroupAddress('1/1/2');
objectStore.addListener(id, function(object, type) {
if (type == 'value') {
showPlan(69);
}
});
}
});
showPlan() value can be get when you hover your mouse over specific plan name and click on the arrow. Please see in pictures attached.
Is it possible to open a widget with the same function?
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
buuuudzik, have a look at this example for AND / OR status calculation:
http://forum.logicmachine.net/showthread...18#pid1518
Note: you should avoid accessing the database directly, there's no guarantee that there won't be any changes in the firmware which can completely break your scripts which are using undocumented "features"
gtsamis
Add a unique CSS class (open-widget in this example) to the button that open's your widget, then use this code to trigger click on the button:
Code: $('.open-widget').trigger('vclick')
Put this after showPlan so the correct plan containing the widget is shown first.
Posts: 15
Threads: 1
Joined: Dec 2015
Reputation:
0
(13.04.2016, 11:27)edgars Wrote: In the firmware starting from 4.2016 there is Custom JavaScript feature available in LogicMachine --> Scripting --> Tools --> Edit custom JavaScript.
It is possible to create different dynamic tasks, like detect short/long press from visualization using one icon (Erwin, will you please add your example here) or as in this example, we can open specific Floor/Plan when some grp address is triggered - useful e.g. when you want IP Camera page automatically to be opened when Intercom button is pressed:
Code: $(function(){
if (typeof objectStore !== 'undefined') {
var id = Scada.encodeGroupAddress('1/1/2');
objectStore.addListener(id, function(object, type) {
if (type == 'value') {
showPlan(69);
}
});
}
});
showPlan() value can be get when you hover your mouse over specific plan name and click on the arrow. Please see in pictures attached.
Where is the new firmware for downloading?????
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
25.06.2016, 10:51
(This post was last modified: 25.06.2016, 10:54 by Erwin van der Zwart.)
(24.06.2016, 10:31)AdriSaliai Wrote: Where is the new firmware for downloading?????
See: http://forum.logicmachine.net/showthread.php?tid=292
BR,
Erwin
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
Small example: play a beep sound each time 1/1/1 value is set to true. Note that it will only work with the upcoming firmware.
Code: $(function(){
var locked;
var ctx = new(window.AudioContext ||
window.webkitAudioContext ||
window.mozAudioContext ||
window.oAudioContext ||
window.msAudioContext);
function beep(duration, freq, cb) {
var osc = ctx.createOscillator();
osc.frequency.value = freq;
osc.connect(ctx.destination);
osc.start ? osc.start(0) : osc.noteOn(0);
setTimeout(function () {
osc.disconnect();
if (typeof cb == "function") {
cb();
}
}, duration);
}
/*
beep each time value of 1/1/1 is true
note that 3rd listen parameter must be set to true
to execute the callback each time new value arrives
otherwise callback is executed only when value changes
*/
grp.listen('1/1/1', function(object, state) {
if (state == 'value' && object.value && !locked) {
locked = true;
beep(200, 432, function() {
locked = false;
});
}
}, true);
});
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
01.07.2016, 10:12
(This post was last modified: 01.07.2016, 10:12 by Erwin van der Zwart.)
Hi Admin,
Nice feature (;
There is only a small problem ..
If you execute it multiple times (more then 5 time) with value 1 then it stops working, the console shows:
Code: Uncaught NotSupportedError: Failed to construct 'AudioContext': The number of hardware contexts provided (6) is greater than or equal to the maximum bound (6).
BR,
Erwin
Posts: 7764
Threads: 42
Joined: Jun 2015
Reputation:
447
Thanks, Erwin! I've modified the script to create an audio context only once and re-use it. See if it works for you now.
Posts: 1764
Threads: 6
Joined: Jul 2015
Reputation:
117
Hi,
I just wanted to post to keep the var new ctx out of the function (;
BR,
Erwin
Posts: 940
Threads: 161
Joined: Jul 2015
Reputation:
33
(13.06.2016, 06:27)buuuudzik Wrote: (12.06.2016, 22:36)Erwin van der Zwart Wrote: Hi Buuudzik,
Here is a sample for changing color with css based on setpoint and actual value difference.
Give the first setpoint these additional classes 'Setp Setp_1', the 2nd 'Setp Setp_2', the 3th 'Setp Setp_3' etc
Give the first actual these additional classes 'Temp Temp_1', the 2nd 'Temp Temp_2', the 3th 'Temp Temp_3' etc
So all setpoints will have 2 additional classes (Setp and Setp_nr) and all actuals will have 2 additional classes (Temp and Temp_nr)
Put this code in your custom JavaScript:
Code: $(function(){
// Set color values
var defaultcolor = $('.Temp').css("color")
var highcolor = 'rgb(0, 255, 0)'
var lowcolor = 'rgb(128, 128, 255)'
// Function to change colors on values
function CheckSetpointandValue(){
// Set conditions for Setp_1 and Temp_1
if ( $(".Temp_1")[0].innerHTML == $(".Setp_1")[0].innerHTML){
$(".Temp_1").css("color", defaultcolor);
} else if ( $(".Temp_1")[0].innerHTML > $(".Setp_1")[0].innerHTML){
$(".Temp_1").css("color", highcolor);
} else if ( $(".Temp_1")[0].innerHTML < $(".Setp_1")[0].innerHTML){
$(".Temp_1").css("color", lowcolor);
}
// Set conditions for Setp_2 and Temp_2
if ( $(".Temp_2")[0].innerHTML == $(".Setp_2")[0].innerHTML){
$(".Temp_2").css("color", defaultcolor);
} else if ( $(".Temp_2")[0].innerHTML > $(".Setp_2")[0].innerHTML){
$(".Temp_2").css("color", highcolor);
} else if ( $(".Temp_2")[0].innerHTML < $(".Setp_2")[0].innerHTML){
$(".Temp_2").css("color", lowcolor);
}
// Set conditions for Setp_3 and Temp_3
if ( $(".Temp_3")[0].innerHTML == $(".Setp_3")[0].innerHTML){
$(".Temp_3").css("color", defaultcolor);
} else if ( $(".Temp_3")[0].innerHTML > $(".Setp_3")[0].innerHTML){
$(".Temp_3").css("color", highcolor);
} else if ( $(".Temp_3")[0].innerHTML < $(".Setp_3")[0].innerHTML){
$(".Temp_3").css("color", lowcolor);
}
}
// Check for changes on value of item with Temp
$('.Temp').bind("DOMSubtreeModified",function(){
CheckSetpointandValue();
});
// Check for changes on value of item with Setp
$('.Setp').bind("DOMSubtreeModified",function(){
CheckSetpointandValue();
});
// Initial execution
CheckSetpointandValue();
});
All items with additional class 'Setp' and 'Temp' are monitored on changes and wil execute the function. Based on values the css of the correct item (Temp_nr) will be changed
If you have more then 3 items then you need to add them inside the function CheckSetpointandValue().
BR,
Erwin van der Zwart
Very nice function
Unfortunately this script isn't working on LM Load Balancer
|