How to format energy data

I have run into a small issue during my attempt to optimize even more the data that is published.

I would like to create a msg property "TimeDelta" with the object parameter (e.g. "ENERGY.Power") and the values of the different iterations.

I was trying to get it done with

let Parameters = ["ENERGY.Power", "ENERGY.Today", "ENERGY.Voltage", "ENERGY.Current", "ENERGY.Factor", "ANALOG.Temperature"]
msg.TimeDeltas = []
msg.TimeDeltas.push({ name: parameter[i], value: 1 })

but the result is

{"TimeDeltas":[{"name":"E","value":0}]}

It should be

[  {
    TimeDelta: {
      ENERGY: {
        Power: {
          "0": 1,
          "1": 2,
          "2": 3,
        }, }, }, },];

What are you trying to do? You talk about two nodes but we see a function which sends a warning.

Sorry, I had fixed that issue and was editing to show my current problem while you responded.

What does the msg.ENERGY.Power contain? the desired result (TimeDelta.ENERGY.Power ?) ?
Or do you just want to add each parameter value into the same array?

There is no msg.ENERGY.Power.

I am trying to create new msg properties.

I will try an easier to explain example:

let Parameters = ["ENERGY.Power", "ENERGY.Today", "ENERGY.Voltage", "ENERGY.Current", "ENERGY.Factor", "ANALOG.Temperature"]
msg.ValueDeltas = []

    for (let parameter of Parameters) {
       msg.ValueDeltas.push({name: parameter[i], value: msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i]})

So, each incoming Parameter has a value. So e.g. msg.payload.ENERGY.Power[0] would have the value 1.
I then want to create a new msg property that looks like

[  {
    ValueDeltas: {
      ENERGY: {
        Power: {
          "0": 1,
          "1": 2,
          "2": 3,
        }, 
        Today: {
          "0": 1,
          "1": 2,
          "2": 3,
        }, 
}, }, },];

and so on. (I hope my syntax for the array is correct, but I think you know what I am aiming for)

EDIT: Updated code example to not perform math operation in the example code.

Power and Today are not arrays but objects.

An array is contained within square brackets not squiggley ones.
An array does not have key: value pairs.
Not sure but I think a trailing comma is illegal in an array.
NB Some other languages do support arrays indexed with a string ("Associative arrays"). Not, I think, javascript.

This is an array:

[1,  2,  3]

Sorry, msg is an array and I am trying to create a new msg property inside that array with nested objects. I think that would be the correct statement ^^

I shortened and modified an existing msg, so I may well have made a syntax mistake or two :frowning:

I should think msg too is an object.

You are correct. msg is an object.
The array is then the lowest level which contains name and value

Bascially I want to create an object like "payload" in the picture which is not named "payload" but ValueDeltas.

Ah yes, in the debug output array elements are printed alongside their (numerical) index.

Normally I would do something like msg.ValueDeltas.ENERGY.Power[i] = "1" but since I am getting the parameters from the array, that does not work so easily.
I tried msg.ValueDeltas[parameter][i] = "1" and some variations of that, but it never worked. I think because I am mixing types.

I think I have to use push but I cannot get the syntax right.

A simple use of push(), to append array elements to an array

let myarray = []                // have to declare myarray as an empty array
myarray.push(msg.payload)  // make array element 0 = payload
myarray.push({ "foo": 1, "bar": 2 }) // array element 1 is an object
myarray[5] = "egg"   // This seems to be legal but inadvisable
msg.payload = myarray
return msg;

Note that the array element can be a simple datatype (string, number etc), an object, another array or probably something else.

1 Like

Ok, i see:

const energy = ["Power", "Today", "Voltage", "Current", "Factor"].reduce((acc, property) => {
  acc[property] = msg.payload.ENERGY[property];
  return acc;
}, {});

const analog = ["Temperature"].reduce((acc, property) => {
  acc[property] = msg.payload.ANALOG[property];
  return acc;
}, {});

msg.ValueDeltas = {
  ENERGY: energy,
  ANALOG: analog,
};

return msg;

Maybe not the best solution...

1 Like

msg is an object but it can be sent as an array ([msg]), this allows you to define several msgs therefore several outputs ([msg1, msg2])

This is what I basically can do without any push() because there is no array being used as part of the naming.

When I want to work with the parameters, I need to get the parameter included.

let Parameters = ["ENERGY.Power", "ENERGY.Today", "ENERGY.Voltage", "ENERGY.Current", "ENERGY.Factor", "ANALOG.Temperature"]
let myValueDeltas = []

for (let parameter of Parameters) {
    myValueDeltas.push({ parameter : msg.payload }) // this uses "parameter" as name but should use the value of parameter
    msg.ValueDeltas = myValueDeltas
}    
return msg;
[{"id":"f6bbb2255bea8924","type":"function","z":"807907a1ba82ffea","name":"function 22","func":"let Parameters = [\"ENERGY.Power\", \"ENERGY.Today\", \"ENERGY.Voltage\", \"ENERGY.Current\", \"ENERGY.Factor\", \"ANALOG.Temperature\"]\nlet myValueDeltas = []\n\nfor (let parameter of Parameters) {\n    myValueDeltas.push({ parameter : msg.payload }) // this uses \"parameter\" as name but should use the value of parameter\n    msg.ValueDeltas = myValueDeltas\n}    \nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":2620,"wires":[["ecea2f597a5493e3"]]},{"id":"92646279f23dd4f1","type":"inject","z":"807907a1ba82ffea","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"25","payloadType":"str","x":420,"y":2630,"wires":[["f6bbb2255bea8924"]]},{"id":"ecea2f597a5493e3","type":"debug","z":"807907a1ba82ffea","name":"debug 332","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":900,"y":2610,"wires":[]}]

@AleXSR700 please continue with this topic as it's a different issue.

1 Like

This looks interesting also. Need to read through it and understand it all first.

But I was trying to not create more constants than I have to. That's why I used ENERGY.Power and ANALAOG.Temperature directly. That way 6 lines turn into 1 line of code.

You can do this too :upside_down_face: :

msg.ValueDeltas = {
  // You create a new object with only the desired properties
  ENERGY:["Power", "Today", "Voltage", "Current", "Factor"].reduce((acc, property) => {
  acc[property] = msg.payload.ENERGY[property];
  return acc;
}, {}),
  ANALOG: ["Temperature"].reduce((acc, property) => {
  acc[property] = msg.payload.ANALOG[property];
  return acc;
}, {}),
};

return msg;

Ah, I think I understand the code now.

I did not specify this earlier because I would never have thought of your solution and what that would mean, but I am creating multiple new properties in my code, so with your approach I would have to execute all of the code once per msg property.... I think.

HEre is a small snippet of a block where I am creating three of these new msg properties

                        if (
                            (msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i] >= flow.get("PowerThresholdHigh") && Math.abs(msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i] - flow.get(msg.topic + parameter + [i])) >= flow.get("PowerDeltaHigh"))
                            || (msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i] <= flow.get("PowerThresholdHigh") && msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i] >= flow.get("PowerThreshold" + flow.get("tasmotaEnd")) && Math.abs(msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i] - flow.get(msg.topic + parameter + [i])) >= flow.get("PowerDelta" + flow.get("tasmotaEnd")))
                            || (context.get("betweenConditions" + [i]) == "True")
                            || (msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i] < flow.get("PowerThreshold1") && Math.abs(msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i] - flow.get(msg.topic + parameter + [i])) >= flow.get("PowerDeltaLow"))
                        ) {
                            msg.ValueDeltas.push({name: parameter[i], value: Math.abs(msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i] - flow.get(msg.topic + parameter + [i]))})
                            msg.TimeDeltas.push({name: parameter[i], value: ((new Date(msg.payload.Time).getTime()) - (new Date(flow.get(msg.topic + parameter + "_Time" + [i])).getTime())) / 1000})
                            msg.UpdateCause.push({name: parameter[i], value: "True"})
                            context.set("betweenConditions" + [i], "False")
                            flow.set(msg.topic + parameter + [i], msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i])
                            flow.set(msg.topic + parameter + "_Time" + [i], msg.payload.Time)
                            context.set(msg.topic + parameter + "_UpdateValue" + [i], msg.payload[parameter.split('.')[0]][parameter.split('.')[1]][i])
                            node.warn("PowerIf" + [i])
                        }

The syntax for the three push() commands is still incorrect as that is what I am trying to fix.

Getting closer. but still not the wanted output

let Parameters = ["ENERGY.Power", "ENERGY.Today", "ENERGY.Voltage", "ENERGY.Current", "ENERGY.Factor", "ANALOG.Temperature"]
let myValueDeltas = []

for (let parameter of Parameters) {
    myValueDeltas.push({ [parameter] : msg.payload })
    msg.ValueDeltas = myValueDeltas
}    
return msg;

image
The object below ValueDeltas should not be named "0" but "ENERGY.Power". And then the indexes below with the value.