This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

Custom JavaScript examples
#41
You can also replace [0].innerHTML with jQuery's .html()
Reply
#42
(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
Reply
#43
You are very wise Smile
Reply
#44
(13.06.2016, 09:36)buuuudzik Wrote: You are very wise Smile

No, i just like to puzzle (;
Reply
#45
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.
Reply
#46
(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
Reply
#47
(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.
Reply
#48
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
Reply
#49
(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?
Reply
#50
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
Reply
#51
(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?
Reply
#52
(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?
Reply
#53
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.
Reply
#54
(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?????
Reply
#55
(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
Reply
#56
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);
});
Reply
#57
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
Reply
#58
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.
Reply
#59
Hi,

I just wanted to post to keep the var new ctx out of the function (;

BR,

Erwin
Reply
#60
(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 functionWink

Unfortunately this script isn't working on LM Load BalancerSad
Reply


Forum Jump: