Energy Counter & Reset

Hi

I'm trying to set-up a energy dashboard based on modbus-energy meters. My goal is to have the energy-consumption (kWh) displayed in the dashbaord and the possibility to reset this value to zero by pressing a button. I was able to create a solution based on a "context.global" variable and many many nodes... However I'm convinced there must by a very simple solution.

[{"id":"c510b3456e9827d8","type":"inject","z":"4b82e3cc342b356d","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":310,"y":760,"wires":[["d5d5effccc369269"]]},{"id":"3c3390e38f48baeb","type":"ui_button","z":"4b82e3cc342b356d","name":"","group":"546cf34f3a19d849","order":8,"width":0,"height":0,"passthru":false,"label":"Reset","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"[]","payloadType":"str","topic":"topic","topicType":"msg","x":490,"y":840,"wires":[["d5d5effccc369269"]]},{"id":"d5d5effccc369269","type":"ui_text","z":"4b82e3cc342b356d","group":"546cf34f3a19d849","order":7,"width":0,"height":0,"name":"","label":"Energy (kWh)","format":"{{msg.payload}}","layout":"row-spread","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":780,"y":760,"wires":[]},{"id":"546cf34f3a19d849","type":"ui_group","name":"Test","tab":"5ba44142e5a211e2","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"5ba44142e5a211e2","type":"ui_tab","name":"Test","icon":"dashboard","disabled":false,"hidden":false}]

The inject-node (timestamp) is a "simulator" for the energy-values (modbus + buffer parser). I'm looking for a function or other node in the red marked area, which saves the current energy-value when reset is pressed (e.g. in a context.global variable). Output should be "actual value" minus "stored context.global value".

Reseting the energy-meter is not what I want.

Injecting a timestamp is a poor substitution for your input data.
It would have been better to capture a real buffer and inject that, including the buffer parser node.

You have not said what triggers an energy reading - is it timed? Can you interrogate the meter for current "energy value" (Watts?)

Why do you propose global context storage? Is this value used in other Node-red editor tabs (other flows)? Is it used in other nodes in this flow?

You can set a context variable from a message payload property using a change node.
.

Do you mean that the "function or other node" should output "actual value" minus "stored context.global value" (as msg.payload), or do you mean store the result of that calculation in the context variable?

Hi

here is a screenshot of my current dashboard from 2 energy meters... The power (in kW) and the energy (in kWh) in depency of time. In addition I have on the right bottom side a text-display of consumed energy (raw-data of energy meter: 184670.06kWh) and a energy-value linked to the reset button below. Once button is pressed counter starts from zero again. However this is a very complicated solution and I'm convinced there must be a better / easier solution.

In case it helps, I put the raw-data from energy here

{"topic":"polling","payload":184685.02,"responseBuffer":{"data":[0,0,2818,4567],"buffer":[0,0,0,0,11,2,17,215]},"input":{"topic":"polling","from":"Trafo 8 Schneider - Energie (Wh)","payload":{"unitid":"255","fc":3,"address":"32095","quantity":"4","messageId":"6799d63103c972fb93763592"},"queueLengthByUnitId":{"unitId":255,"queueLength":0},"queueUnitId":255,"unitId":255},"sendingNodeId":"a87e2fcfebde19cd","_msgid":"c1cc497038757e16","originalPayload":[0,0,2818,4567],"specification":{"options":{"byteSwap":[],"resultType":"value","singleResult":true,"msgProperty":"payload","setTopic":true},"items":[{"type":"bigint64be","name":"Energioe (Wh)","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":"","id":0,"value":"184685015"}]},"values":["184685015"],"objectResults":{"Energioe (Wh)":{"type":"bigint64be","name":"Energioe (Wh)","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":"","id":0,"value":"184685015"}},"keyvalues":{"Energioe (Wh)":"184685015"},"arrayResults":[{"type":"bigint64be","name":"Energioe (Wh)","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":"","id":0,"value":"184685015"}],"buffer":[0,0,0,0,11,2,17,215]}

I fully agree, that timestamp injection is a poor substitution... however it simulates the output of energy pretty well.
Yes, I want the output in msg.payload

In your data there are several numbers which look like the raw meter reading, eg msg.payload.specification.items[0].value == 184685015
And you have msg.payload.payload == 184685.02

I guess that this value scaled and rounded to 2dp is inserted by a function node somewhere earlier in the flow?

Here is one possible approach using a flow context variable (using persistent storage) to retain the most recent reading and a base value to subtract from it

flow.latestkwh = {
    "meter": 184685.02,
    "resetAt": 184677.55,
    "usage": 7.47
}

When a meter reading arrives (in the function node I guessed/imagined above maybe)

let latestmeter = flow.get('latestmeter') ?? { "resetat": 0 } // default value for the subtraction
latestmeter.meter = msg.payload  // Or one of the raw reading values
latestmeter.usage = latestmeter.meter - latestmeter.resetat
flow.set('latestmeter', latestmeter)

When the button is pressed, in another function (hence flow context scope not node context)

let latestmeter = flow.get('latestmeter') ?? { 'meter': 0 } // default value for the subtraction
latestmeter.resetat = latestmeter.meter
latestmeter.usage = latestmeter.meter - latestmeter.resetat
flow.set('latestmeter', latestmeter)

Both of these functions should set msg.payload to the value you want there, and should be wired up to the text nodes.

I can't remember offhand if a dashboard 2 text node can only show a simple msg.payload value (in which case you'd have to have send two messages from each function not just one)

thanks a lot... this solution works...

[{"id":"b5efe697c6237477","type":"group","z":"4b82e3cc342b356d","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["c510b3456e9827d8","3c3390e38f48baeb","d5d5effccc369269","100ff4491858a2a5","d7df27b2622b6c53"],"x":194,"y":719,"w":692,"h":162},{"id":"c510b3456e9827d8","type":"inject","z":"4b82e3cc342b356d","g":"b5efe697c6237477","name":"simulator","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":310,"y":760,"wires":[["100ff4491858a2a5"]]},{"id":"3c3390e38f48baeb","type":"ui_button","z":"4b82e3cc342b356d","g":"b5efe697c6237477","name":"","group":"546cf34f3a19d849","order":11,"width":0,"height":0,"passthru":false,"label":"Reset","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"","payloadType":"str","topic":"topic","topicType":"msg","x":310,"y":840,"wires":[["d7df27b2622b6c53"]]},{"id":"d5d5effccc369269","type":"ui_text","z":"4b82e3cc342b356d","g":"b5efe697c6237477","group":"546cf34f3a19d849","order":10,"width":0,"height":0,"name":"","label":"Energy (kWh)","format":"{{msg.payload}}","layout":"row-spread","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":780,"y":760,"wires":[]},{"id":"100ff4491858a2a5","type":"function","z":"4b82e3cc342b356d","g":"b5efe697c6237477","name":"function 8","func":"let latestmeter = flow.get('latestmeter') ?? { \"resetat\": 0 } // default value for the subtraction\nlatestmeter.meter = msg.payload  // Or one of the raw reading values\nmsg.payload = latestmeter.meter - latestmeter.resetat\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":760,"wires":[["d5d5effccc369269"]]},{"id":"d7df27b2622b6c53","type":"function","z":"4b82e3cc342b356d","g":"b5efe697c6237477","name":"function 9","func":"let latestmeter = flow.get('latestmeter') ?? { 'meter': 0 } // default value for the subtraction\nlatestmeter.resetat = latestmeter.meter\nflow.set('latestmeter', latestmeter)","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":540,"y":840,"wires":[[]]},{"id":"546cf34f3a19d849","type":"ui_group","name":"Test","tab":"5ba44142e5a211e2","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"5ba44142e5a211e2","type":"ui_tab","name":"Test","icon":"dashboard","disabled":false,"hidden":false}]

only remaining issue - I need to press the reset-button twice after restart of node-red...

Are you using persistent context storage (ie on disk not in memory)?

You might need an inject node set to fire at startup to get the stored data. I'm not too sure about this, it should not be necessary.

Your function 8 is not saving the context variable.

thanks a lot... in the meantime I transferred this functions to my real dashboard (including modbus) and I can confirm that it works well

1 Like