Function: division by 0

I´m pretty new in Node-Red, but all I´ve done till now is working fine.
Sometimes it´s easy to understand how it´s working, but now I´m having a problem with division by 0.
My solution is working, but it must give a better one.

var CP = msg.payload["CP"];
var CC = msg.payload["CC"];
var COP;
if(CP > 0 || CC > 0) { COP = (CP / CC); }
else { COP = 0.0001; }
msg.payload = COP
msg.payload = msg.payload.toFixed(2);
msg.topic = "Cool_COP";
return msg;

Because I´m using 2 decimal places I´m rounding.
What´s a better solution ?
Thanks.

With kind regards,
Thorsten

Consider this, CP = 2, CC = 0

your if statement will be true. Here is the equivalent in works
if(2 > 0 or 0 > 0) { COP = (2 / 0); }

I suspect you meant...

if(CP > 0 && CC > 0) { COP = (CP / CC); }

or, more usually...

if(CC != 0) { COP = (CP / CC); }

Hi Steve.

I´ve tried your proposals.

no result/payload:

 if(CP > 0 && CC > 0) { COP = (CP / CC); }

NaN:

if(CC != 0) { COP = (CP / CC); }

You must know, that both can be 0.
Cool power consumption (CC) and cool power production (CP) are 0 when heat pump is heating water.

This means one of your values is not a number. Add node.warn([CC,CP]) above the if statement to see what they contain (check debug output)


This is, what I´m getting in my way:
flow_payload
And this is with your proposal:
flow_payload_yours

So your msg.payload is an object containing string properties - strings are not ideal for number comparison & math functions.

Try this...

var CP = Number(msg.payload.CP);
var CC = Number(msg.payload.CC);
var COP = 0;
if (CC != 0) {
    COP = (CP / CC);
}
msg.payload = COP.toFixed(2)
msg.topic = "Cool_COP";
return msg;

TBH, you really should not be doing the toFixed(2) as you lose number precision and turn it into a string.

I would recommend keeping the full number until such a time as you display it (then to toFixed(2) or other formatting for display purposes)

Ok, that works, thanks.
Maybe you can help me with my fault on Grafana.
I´m getting the message "unsupported mean iterator type: *query.stringInterruptIterator"

At that moment when I´m choosing a field variable, for example CC, I´m getting this message:
Here´s the query inspector output:
Object
request:Object
method:"GET"
url:"api/datasources/proxy/1/query"
params:Object
db:"iobroker"
q:"SELECT mean("CC") FROM "Testing" WHERE time >= now() - 1h GROUP BY time(2s) fill(null)"
epoch:"ms"
data:null
precision:"ms"
hideFromInspector:false
response:Object
results:Array[1]
0:Object
statement_id:0
*error:"unsupported mean iterator type: query.stringInterruptIterator"
executedQueryString:"SELECT mean("CC") FROM "Testing" WHERE time >= now() - 1h GROUP BY time(2s) fill(null)"

"Switch" is getting the information by MQTT:
switch

function:
msg.payload = msg.payload;
msg.topic = "HP";
return msg;

Next step depends on energy value for calculation the COP or going directly to join.
Is it possible, that the string from "switch" is transfered to the influxdb out ?

Possibly, probably. Have a look in the database.

no strings in the measurement.

So, why I´m getting this message by choosing a field variable ?

Add a debug node showing what you are sending to the influx node and check that the values are not strings. Post the result here if you think it looks ok.

That's the payload after join:
flow_payload

When I´m debugging all messages I get this:

DHW_COP : msg : Object
object
topic: "DHW_COP"
payload: object
qos: 0
retain: false
_topic: "jeisha/main/DHW_Energy_Consumption"
_msgid: "c1817067.3aba"

I´ve trying it in seperate steps and I´m getting the string by the switch node.
But how can I read out a string from MQTT without giving it forward to other nodes ?

If that is what you are sending to influx, then, as you can see, it is showing values such as
HP: "0"
so the value being sent to influx is indeed a string not a number. If it were a number it would appear as
HP: 0
So the values in the the database are strings not numbers so you cannot use influx query functions such as mean. The solution is to convert them all to numbers before sending to influx.

On a separate issue related to your flow, do all the values come in to node-red together or are they coming at different times and you are joining them together? If they arrive at different times then you should write them to separate Measurements in influx. If they are arriving together then you should not split them up and join them together again, but should extract the data direct from the incoming message.

Also you should generally not round the data before writing to influx, you should always keep the data to maximum precision in the database. You can round it when you inspect it later if necessary.

Finally you should generally not write derived values to the database as well as the source data (such as CP, CC and Cool_COP) but should derive it when you use it. There are occasions when it is worth while to save derived data, but generally it is considered a bad idea.

In my flow the output of the 1st function is a number.
So in your opinion I should use a function directly behind the first function without join?
How can I call the variable as a number ? Number(msg.payload.CP) ? Because that´s not working.

msg.payload.CP = Number(msg.payload.CP);

or

msg.payload.CP = parseInt(msg.payload.CP);

do that in the same function before return msg

You should probably do that to all variables in the payload object.


NOTE: I did say...

... what i didnt say was - because if you store the data in a database, it will be in-accurate and potentially the wrong format (it was implied :wink: )


EDIT...
What Colin is alluding to, is often, with influx, the values are stored individually - e.g. instead of joining CC and CP data, write those as individual measures. Then, only when you retrieve and display them do you do any formatting or compound values.

EDIT2...

I suspect the functions called CP and CC are probably converting the values to strings (or, if not, then perhaps inside that function you should do the number conversions before spitting them out)

In first function it´s:

msg.payload = Number(msg.payload);
msg.topic = "CP";
return msg;

and I´m getting a number. If I´m using

msg.payload.CP = Number(msg.payload);

in the 1st function, then it´s a string.
So what´s the best function code for CooL_COP without using the first join ?

It all depends on what you are doing with data, how you display it etc.

Colins advice was to send the CC and CP values individually to influx (skip the join node)

then when you query the database, do a join in your QUERY.

Once you have the data coming back to node, red, you compute the Cool_COP value.


NOTE: I dont understand your entire requirements nor am I fully up to speed with infuxDB - in relational DB terms (mySQL / SQL Server) I would probably have a VIEW or STORED PROCEDURE that returns the data joined and the COOL_COP calculated in the QUERY at the database side (since it is much faster)

Why it´s better to use 3 or more measurements instead of 1 for all 9 values ?
How can I get a number after COP instead a string ?
Here´s an example, what´s not working:

[
    {
        "id": "ee4a7550.dfd258",
        "type": "tab",
        "label": "Flow 4",
        "disabled": false,
        "info": ""
    },
    {
        "id": "541813a6.e0b86c",
        "type": "switch",
        "z": "ee4a7550.dfd258",
        "name": "Heat_Energy_Production",
        "property": "topic",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "jeisha/main/Heat_Energy_Production",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 590,
        "y": 240,
        "wires": [
            [
                "ac0219a8.543438",
                "e09d0e03.75c14"
            ]
        ]
    },
    {
        "id": "2c1a2d2d.641392",
        "type": "switch",
        "z": "ee4a7550.dfd258",
        "name": "Heat_Energy_Consumption",
        "property": "topic",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "jeisha/main/Heat_Energy_Consumption",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 600,
        "y": 280,
        "wires": [
            [
                "d97d92b2.f24e9"
            ]
        ]
    },
    {
        "id": "ac0219a8.543438",
        "type": "function",
        "z": "ee4a7550.dfd258",
        "name": "HP",
        "func": "msg.payload = Number(msg.payload);\nmsg.topic = \"HP\";\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 810,
        "y": 240,
        "wires": [
            [
                "629eda30.603894"
            ]
        ]
    },
    {
        "id": "d97d92b2.f24e9",
        "type": "function",
        "z": "ee4a7550.dfd258",
        "name": "HC",
        "func": "msg.payload = Number(msg.payload);\nmsg.topic = \"HC\";\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 810,
        "y": 280,
        "wires": [
            [
                "629eda30.603894"
            ]
        ]
    },
    {
        "id": "629eda30.603894",
        "type": "function",
        "z": "ee4a7550.dfd258",
        "name": "Heat_COP",
        "func": "var HP = msg.payload.HP;\nvar HC = msg.payload.HC;\nvar COP = 0;\nif(HC !=0) { COP = (HP / HC); } \nmsg.payload = COP.toFixed(2);\nmsg.topic = \"Heat_COP\";\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1030,
        "y": 260,
        "wires": [
            [
                "9157fb98.92f528"
            ]
        ]
    },
    {
        "id": "e09d0e03.75c14",
        "type": "debug",
        "z": "ee4a7550.dfd258",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 920,
        "y": 160,
        "wires": []
    },
    {
        "id": "9157fb98.92f528",
        "type": "debug",
        "z": "ee4a7550.dfd258",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "payload",
        "statusType": "auto",
        "x": 1300,
        "y": 320,
        "wires": []
    },
    {
        "id": "57f8a5dd.4af72c",
        "type": "mqtt in",
        "z": "ee4a7550.dfd258",
        "name": "Panasonic Aquarea",
        "topic": "jeisha/main/#",
        "qos": "0",
        "datatype": "utf8",
        "broker": "c61d6a73.c55788",
        "nl": false,
        "rap": true,
        "rh": 0,
        "x": 270,
        "y": 260,
        "wires": [
            [
                "541813a6.e0b86c",
                "2c1a2d2d.641392"
            ]
        ]
    },
    {
        "id": "c61d6a73.c55788",
        "type": "mqtt-broker",
        "name": "",
        "broker": "127.0.0.1",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "verifyservercert": true,
        "protocolVersion": "3",
        "keepalive": "15",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "sessionExpiry": ""
    }
]

Please help me with this problem. I don´t understand why I´m getting the value as a string and how to solve it. Thanks.

It is a design thing (comes with experience) - see this thread




Reason...
image

As I said before...

... to be 100% clear - delete .toFixed(2) and it WILL be a number.

Sorry, dude, but it´s still a string :wink:

paste the updated flow (just the relevant parts)

and

capture the MQTT message that feeds into it by doing this...

  1. add a debug to the output of the MQTT IN

  2. set the debug to show complete message

  3. press the copy value button that appears under your mouse when you hover on thew debug message object
    image

  4. paste the copied data into a reply with your flow