Array selection help - Selecting last item in array

Hi,

I am trying to pull an array from a home assistant sensors attribute, what I want to do is just pass along the last array entry, the issue is the array naming structure is different every time:

[{"id":"8617395361a98887","type":"inject","z":"4fbb0f02.0e5f6","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":1240,"wires":[["2da2ba8af5dd5e7a"]]},{"id":"2da2ba8af5dd5e7a","type":"api-current-state","z":"4fbb0f02.0e5f6","name":"Rates","server":"b3a3253e.d12568","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"octopusagile.rates","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":290,"y":1240,"wires":[["2f73f4624b193e82","5f25a119a3c6af29","edeb3970e07530dc"]]},{"id":"f805ddc9be792893","type":"debug","z":"4fbb0f02.0e5f6","name":"Rates","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":750,"y":1200,"wires":[]},{"id":"5f25a119a3c6af29","type":"function","z":"4fbb0f02.0e5f6","name":"function 11","func":"\n\nconst x = msg.data.attributes[-1]\nmsg.payload = x\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":1240,"wires":[["f805ddc9be792893"]]},{"id":"edeb3970e07530dc","type":"debug","z":"4fbb0f02.0e5f6","name":"Rates","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":750,"y":1240,"wires":[]},{"id":"b3a3253e.d12568","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

My ideal solution is read the last attribute entry and write it to an input helper, at the moment I am just parsing to a debug node before I start sending the entry elsewhere for use, I've had a nosie and found a few similar things, but none of them have worked and/or were unrelated just enough to not be what I am after.

Can anyone point me in a general direction at all please?

Do you mean msg.data.attributes? It's an object not an array.

What do you mean by the last item - in your example is it 18.06 at 22:30 or 22.512 at 14:30?

Ahh yes, it's an object sorry, the attrib treats it like an array, I think I can convert it to an array though by splitting and joining it.

But yes, in my example it will be 14:30, but that will change every 30 minutes, basically I want to pull the last entry every 30 minutes.

Even though that is the earliest timestamp, not the most recent?

Maybe this will work?

msg.payload = msg.data[Object.keys(msg.data)[Object.keys(msg.data).length - 1]]

Generally you cannot rely on the ordering of properties of an object, so possibly the keys should be sorted before taking the first one.

1 Like

I thought it might need sorting too, but the internet claims that more recent js (since 2015) preserves the insertion order as long as the keys are not integers?

Certainly can't hurt to sort.

If I'm not mistaken, that object holds prices for some period, where every item is price which lasts 30 minutes.

You'r intention is to get the last one but that is not fail safe at all.
To get good advise it takes to know what that object actually holds. Is it price list of historical data where youngest item is most recent (maybe even current) or is it look-ahead list.
Then specify your target in terms of time what is your intention. Should it be price which is valid for current moment or for next half of hour or something else.
And then it also depends on timing, when you call the function to get the price of your interest.

So if you can make your intention more clear in all terms above, it'll be fine to figure out best solution.

I think ES6 became standard in nodejs with nodejs v14, which is why node red 3 requires at least v14. There are still many users with earlier versions of nodejs though.

However, in this example, how does one know that the insertion order will always be the same?

Apologies, should have stated my intentions.

Basically Octopus Agile is the pricing structure for an energy plan where the prices change every 30 minutes, the prices are set during the day, the sensor updates every 30 minutes and the attributes are updated.

Generally I've always seen them ordered in that way, top to bottom furthest in the future to most recent at the bottom (Last) where the last entry is the 30 minute window that you are currently in.

They hold the price per Kw in pence, the repo for the service has been dead now for a few years, and people suggest using the newer one, but that only shows you the rates for the half hour you are in if you are on the Agile plan.

What I want to use is get the data myself and use it to workout if it would be cheaper to move over to it.

The rates sensor seems reliable but the current rate sensor doesn't update, its a known bug and I can't see a fix for it, figured I'd be able to use Node Red to parse the data in to an input helper for me to use as I see fit.

In that case, provided you are using nodejs at least version 14, something like @jbudd's solution should work. If you want to be absolutely certain that you get the oldest timestamp then sort the keys and take the first one.

Just tried, this, amended it to the object in question and seems to be working a treat for now.

Many thanks all for the input and help, I will test it for 24 hours and see how it behaves.

Octopus have an API where you can query Agile prices!

Yea I did have a play, if this doesn't work I will use the API, I used it in the past and it can be a bit of a mess

The API provides accurate data. What do you find "messy"?

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