Is there a "better" way to run this - i.e. how to remove the loop node

I am going to piggyback on this thread, as I have a question somehow related to the loop aspect.

[note by moderator: this post has been moved from another thread to keep them seperate]

I am currently using the loop node to process entries in an array.
I have an API call (weather) that gives me 48 forecast (1 per hour for the next two days). I want to push each value to HA.
At the moment my flow looks like:

The start of the output of the WSFT HTTP call is:

{"position":{"lat":43.583,"lon":1.434,"alti":137,"name":"Toulouse-Stade de Toulouse","country":"FR - France","dept":"31","rain_product_available":0,"timezone":"Europe/Paris","insee":"3155521","bulletin_cote":0},"updated_on":1599129900,"daily_forecast":[{"dt":1599091200,"T":{"min":9.6,"max":28.8,"sea":null},"humidity":{"min":20,"max":80},"precipitation":{"24h":0},"uv":7,"weather12H":{"icon":"p1j","desc":"Sunny"},"sun":{"rise":1599110445,"set":1599157513}},{"dt":1599177600,"T":{"min":11.7,"max":32.6,"sea":null},"humidity":{"min":25,"max":70},"precipitation":{"24h":0},"uv":7,"weather12H":{"icon":"p1j","desc":"Sunny"},"sun":{"rise":1599196912,"set":1599243807}},{"dt":1599264000,"T":{"min":15.6,"max":29.8,"sea":null},"humidity":{"min":30,"max":95},"precipitation":{"24h":0},"uv":7,"weather12H":{"icon":"p1j","desc":"Sunny"},"sun":{"rise":1599283379,"set":1599330099}},{"dt":1599350400,"T":{"min":14.6,"max":24.7,"sea":null},"humidity":{"min":45,"max":80},"precipitation":{"24h":0},"uv":5,"weathe...

Is there a "better" way (say following NR principles) to do the same kind of thing?
That is repeating the same action for many identical part of a large JSON.

Hope it makes sense.

GV

What 'value' do you want to send to HA?

Im gonna go with yes :smiley:

Post your flow and real data sample captured from the WSFT node (attach a debug to the output of the WSFT node and use the copy button in the debug output to grab a copy of real data so that we can use it to inject into your flow for testing purposes)

I knew you were up to the challenge !!

wsft.txt (26.7 KB)

Here is the complete output. Copy/paste out of debug doesn't work, it is too big.

And the flow.

[{"id":"228836bd.ed4b1a","type":"function","z":"f5b50430.ea48b8","name":"MF2Array","func":"var ech = [];\nvar temp = [];\nvar precipi = [];\nvar windf = [];\nvar windg = [];\nvar windd = [];\n\nflow.set(\"ech\",\"\");\nflow.set(\"temp\",\"\");\nflow.set(\"precipi\",\"\");\nflow.set(\"precipp\",\"\");\nflow.set(\"windf\",\"\");\nflow.set(\"windg\",\"\");\nflow.set(\"windd\",\"\");\n\nfor (var i=0; i<24;i++) {\n  ech.push(msg.payload.forecast[i].dt);\n  temp.push(msg.payload.forecast[i].T.value);\n  precipi.push(msg.payload.forecast[i].rain[\"1h\"]);\n  windf.push(msg.payload.forecast[i].wind.speed);\n  windg.push(msg.payload.forecast[i].wind.gust);\n  windd.push(msg.payload.forecast[i].wind.icon);\n}\n\nflow.set(\"ech\",ech);\nflow.set(\"temp\",temp);\nflow.set(\"precipi\",precipi);\nflow.set(\"windf\",windf);\nflow.set(\"windg\",windg);\nflow.set(\"windd\",windd);\nflow.set(\"nbstep\",24);\nflow.set(\"index\",0);\nreturn msg;\n","outputs":1,"noerr":0,"x":500,"y":880,"wires":[["cc6aaa78.40ffb8"]]},{"id":"cc6aaa78.40ffb8","type":"counter-loop","z":"f5b50430.ea48b8","name":"Step?","counter":"kjsqhdhsifhsj","counterType":"msg","reset":false,"resetValue":"value-null","initial":"0","initialType":"num","operator":"lt","termination":"nbstep","terminationType":"flow","increment":1,"incrementType":"num","x":690,"y":880,"wires":[[],["282d038e.77a30c"]]},{"id":"282d038e.77a30c","type":"function","z":"f5b50430.ea48b8","name":"Reassemble","func":"var host = global.get(\"host\");\nvar token = global.get(\"token\");\n\nvar ech = flow.get(\"ech\");\nvar temp = flow.get(\"temp\");\nvar precipi = flow.get(\"precipi\");\nvar windf = flow.get(\"windf\");\nvar windd = flow.get(\"windd\");\nvar windg = flow.get(\"windg\",\"\");\nvar i = flow.get(\"index\");\n\n// var windtext=[\"N\",\"NNE\",\"NE\",\"ENE\",\"E\",\"ESE\", \"SE\", \"SSE\",\"S\",\"SSO\",\"SO\",\"OSO\",\"O\",\"ONO\",\"NO\",\"NNO\",\"N\"]\n\nvar hour = new Date(ech[i]*1000).getHours();\nvar hour_format = \"\";\nif ( hour <= 9 ) { hour_format = \"0\" + hour + \":00\" }\nelse { hour_format = hour + \":00\" }\n\nvar raini = precipi[i];\nif ( raini == \"unknown\" ) { raini = \"-\" }\nelse raini = raini.toFixed(1)\n\n\nvar windgkm = ( windg[i] * 3.6 ).toFixed(0) + \")\";\nvar windfkm = ( windf[i] * 3.6 ).toFixed(0) + \" km/h (\" + windgkm;\n// var wind_index = (windd[i] / 22.5).toFixed(0) - 1;\n\nmsg.payload = {\n    \"state\": 'forecast',\n    \"attributes\" : {\n        \"hour\": hour_format,\n        \"temp\": temp[i].toFixed(1),\n        \"rain\": raini,\n        \"wind\": windfkm,\n        \"dir\" : windd[i]\n    }\n}\n\nvar sensor = 'forecast' + i;\nmsg.url = host + \"/api/states/sensor.\" + sensor;\nmsg.method = \"POST\";\nmsg.headers = {\n    'Authorization': 'Bearer ' + token,\n    'content-type': 'application/json',\n} ;\ni = i + 1;\nflow.set(\"index\",i);\nreturn msg;\n","outputs":1,"noerr":0,"x":573,"y":980,"wires":[["23c9d18f.f84ace"]]},{"id":"23c9d18f.f84ace","type":"https-node","z":"f5b50430.ea48b8","name":"HA OUT","method":"use","ret":"txt","url":"","authorized":false,"agent":true,"x":740,"y":980,"wires":[["cc6aaa78.40ffb8"]]},{"id":"f2b0fee2.29624","type":"http request","z":"f5b50430.ea48b8","name":"WSFT","method":"GET","ret":"txt","paytoqs":"ignore","url":"http://webservice.meteofrance.com/premiumforecast?token=private_token&lat=43.58&lon=1.44&lang=en","tls":"","persist":false,"proxy":"","authType":"","x":230,"y":880,"wires":[["1976f02d.9def7"]]},{"id":"1976f02d.9def7","type":"json","z":"f5b50430.ea48b8","name":"","property":"payload","action":"","pretty":false,"x":350,"y":880,"wires":[["228836bd.ed4b1a"]]},{"id":"4d35554e.99276c","type":"inject","z":"f5b50430.ea48b8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":80,"y":880,"wires":[["f2b0fee2.29624"]]}]

In the WSFT node, I have removed the token (personal info).

The functions are probably badly written as well... But, my question is really about doing one action per entry in the JSON output.

Thanks for looking into this!

GV

Ok, so as you already loop through the items in the MF2Array node - I am uncertain why you have then went on to store the data in flow context, then use a contrib node to perform looping then pull each item back out of flow context before sending on to a http node?

In this instance (unlike the other thread where this started) looping (in a function) was already necessary (or rather most suitable) as you do a fair bit of processing of the data (inside re-assemble node).

In this case, I feel you almost have the best methodology (just lose the extra junk)

Here is the content of that function...

var host = global.get("host") || "NNN.FAKE_HOST.COM";
var token = global.get("token") || "FaK3_t0K3N";


let forecast = msg.payload.forecast; //shortcut to the data

let loopLimit = forecast.length; //never loop more than you should!
loopLimit = 24; //FORCE LIMIT 24 items - remove me if you want all of them in data

//now loop the forecast data and build messages to send
for (let i=0; i<loopLimit; i++) {
    let ech = forecast[i].dt;
    let temp = forecast[i].T.value;
    let raini = forecast[i].rain["1h"] || 0;
    let windf = forecast[i].wind.speed || 0;
    let windg = forecast[i].wind.gust || 0;
    let windd = forecast[i].wind.icon;
  
    let hour = new Date(ech*1000).getHours();
    let hour_format = "";
    if ( hour <= 9 ) { 
        hour_format = "0" + hour + ":00" 
    } else { 
        hour_format = hour + ":00" 
    }

    if ( raini == "unknown" ) { 
        raini = "-";
    } else {
        raini = raini.toFixed(1);
    }

    let windgkm = ( windg * 3.6 ).toFixed(0) + ")";
    let windfkm = ( windf * 3.6 ).toFixed(0) + " km/h (" + windgkm;
  
    let m = {};
    let sensor = 'forecast' + i;
    m.url = host + "/api/states/sensor." + sensor;
    m.method = "POST";
    m.headers = {
        'Authorization': 'Bearer ' + token,
        'content-type': 'application/json',
    };    
    m.payload = {
        "state": 'forecast',
        "attributes" : {
            "hour": hour_format,
            "temp": (temp || 0).toFixed(1),
            "rain": raini,
            "wind": windfkm,
            "dir" : windd
        }
    };
    node.send(m); //send a msg to next node
}

PS, there has yet to be an instance where i have ever needed a looping node (uninstall it and put a sticky note on your monitor to never re-install it :wink: )

2 Likes

Thanks for taking the time to educate us :slight_smile:
The bit that I was really missing in my stuff was the node.send(m). I didn't know it existed!
So, in order to loop (sorry I know it is bad ), I had to "get out of the node" (not sure how to say this the right way).
This node.send avoids the outer loop.
I'll go and buy some post-it !

GV

2 Likes

I swear, as a true NR aficionado, never to install the loop node again :slight_smile: :innocent:

2 Likes

Haha - to be fair, i am certain it is a fine and capable node & the developer likely put a lot of time and effort into it. I am certain it is of use for some folks - I just havent found it to be useful for me at all.

but then it took me sometime to find start using the split node (over writing my own function loops)

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.