Announcement

Collapse
No announcement yet.

How do you do math in Node-RED?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    How do you do math in Node-RED?

    As I continue to learn NR, I'd like to try to take some VB scripts and more their function to NR. I need to perform some calculations on sensor readings and then store the data into HS devices. I know I can use Math from within a function node, but I've also heard from a few sources, that function nodes are slow and should be avoided.

    What are others using to perform calculations within Node-RED?
    "if I have seen further [than others], it is by standing on the shoulders of giants." --Sir Isaac Newton (1675)

    #2
    This depends on the calculations. You can use the Expression option in most nodes, such as the Change node and do calculations using JSONota. There are a couple calculator nodes but they have not been updated in over a year. Could mean there are no changes needed, though, so do not just go by this. A function node is fine if you are doing complex calculations, but most people use them to replace things which could be done with a couple other native nodes. I would look at the JSONota capabilities first.
    Karl S
    HS4Pro on Windows 10
    1070 Devices
    56 Z-Wave Nodes
    104 Events
    HSTouch Clients: 3 Android, 1 iOS
    Google Home: 3 Mini units, 1 Pair Audios, 2 Displays

    Comment


      #3
      I know some "purists" will cringe at this, but I would use a "Function" node which allows you to do javascript calculations. For example, I was trying to track propane usage, and needed to do BTU calculations over time and I did all those calculations in a Function. Yeah others will complain that a function uses too many resources, but I have never experienced this as a problem in real life, only academically. As to a Function being slow ... it is only slow if you write a real bad function. The node itself is not slow.

      There is also a calculation node, node-red-contrib-calc, if that suits your purposes, I am not sure that is any better than just using a Function.

      Last thing I can think of is that you do your math in a node.js script, and then include it into node-red at startup. But, that is a little more difficult to debug in real time.

      Comment


        #4
        I think I'm going to try a "hybrid" approach for now. I need to make a calculation, followed by a switch statement to another calculation, and finally store the result.

        Function Node -> Switch Node -> Function Node -> HS Device Node

        I'll post the flow when I get it working.
        "if I have seen further [than others], it is by standing on the shoulders of giants." --Sir Isaac Newton (1675)

        Comment


          #5
          Consider doing the Switch in the function node, then. Might as well do all the logic there if you are going to use two.
          Karl S
          HS4Pro on Windows 10
          1070 Devices
          56 Z-Wave Nodes
          104 Events
          HSTouch Clients: 3 Android, 1 iOS
          Google Home: 3 Mini units, 1 Pair Audios, 2 Displays

          Comment


            #6
            I agree with ksum ... if you are going to take the hit with a function node, you might as well put the switch there, as functions allow you to add additional outputs.... and then include your other function. No need to load separate functions if you are just separating them by a switch node.

            Comment


              #7
              Advice taken. Here's the code. Don't laugh, I'm a Python programmer. Just learning Javascript.

              Code:
              var pm25val = msg.payload.value
              var Conc, ConcHigh, ConcLow, AQIHigh, AQILow
              var aqival = 0
              
              Conc = (Math.floor(10 * pm25val)) / 10
              
              msg.debug = {}
              msg.debug.Conc = Conc
              
              switch(true) {
                  case Conc < 12.1:
                      AQIHigh = 50; AQILow = 0; ConcHigh = 12; ConcLow = 0
                      break;
                  case Conc < 35.5:
                      AQIHigh = 100; AQILow = 51; ConcHigh = 35.4; ConcLow = 12.1
                      break;
                  case Conc < 55.5:
                      AQIHigh = 150; AQILow = 101; ConcHigh = 55.4; ConcLow = 35.5
                      break;
                  case Conc < 150.5:
                      AQIHigh = 200; AQILow = 151; ConcHigh = 150.4; ConcLow = 55.5
                      break;
                  case Conc < 250.5:
                      AQIHigh = 300; AQILow = 201; ConcHigh = 250.4; ConcLow = 150.5
                      break;
                  case Conc < 350.5:
                      AQIHigh = 400; AQILow = 301; ConcHigh = 350.4; ConcLow = 250.5
                      break;
                  case Conc < 500.5:
                      AQIHigh = 500; AQILow = 401; ConcHigh = 500.4; ConcLow = 350.5
                      break;
                  default:
                      AQIHigh = 1000; AQILow = 501; ConcHigh = 999.5; ConcLow = 500.5
              }
              
              aqival = ((Conc - ConcLow) / (ConcHigh - ConcLow)) * (AQIHigh - AQILow) + AQILow
              msg.debug.aqi = Math.round(aqival)
              
              return msg;
              EDIT: BTW, Can anyone tell me the proper way to paste code and get the indents to work in the code block? I had to insert spaces by hand.
              "if I have seen further [than others], it is by standing on the shoulders of giants." --Sir Isaac Newton (1675)

              Comment


                #8
                Real quick, as I am going offline for a bit: JavaScript normally wants a semicolon a the end of each line of code. So you would have:
                Code:
                var pm25val = msg.payload.value;
                You do not need to separate the lines with carriage returns, meaning the line after each case line is actually 4 lines of code and would be just as valid like this:
                Code:
                case Conc < 12.1:
                  AQIHigh = 50;
                  AQILow = 0;
                  ConcHigh = 12;
                  ConcLow = 0;
                  break;
                but again, it will work as you have it although the semicolon after setting concLow may be needed. The function node MAY allow you to drop the semicoloin, though. Some JavaScript parsers are less strict than others.


                You may want to use let instead of var as let allows you to declare variables that are limited to the scope of a block statement, or expression on which it is used, unlike the var keyword, which declares a variable globally, or locally to an entire function regardless of block scope
                Karl S
                HS4Pro on Windows 10
                1070 Devices
                56 Z-Wave Nodes
                104 Events
                HSTouch Clients: 3 Android, 1 iOS
                Google Home: 3 Mini units, 1 Pair Audios, 2 Displays

                Comment


                  #9
                  Thanks ksum All advice is much appreciated. I've added semicolons and changed to let instead of var. I like the single line of assignments in the case statements as it makes the overall switch a little easier to read, IMHO.
                  "if I have seen further [than others], it is by standing on the shoulders of giants." --Sir Isaac Newton (1675)

                  Comment

                  Working...
                  X