question

alphalinux avatar image
alphalinux asked

Advise Node-Red Flow with Battery SoC

Hi all
I'm a newbie to Node Red and just started with.

I would like to have a flow with Battery SoC, aTimer and Relay 2 on Cerbo.

Logically i would like to achieve this flow:

Timer On at Time + Battery SoC above value = Relay 2 On
Timer On at Time + Battery SoC below value = Relay 2 Off
Timer Off at Time + Battery SoC above value = Relay 2 Off

Basically i have started with the Flow below which turns on/off Relay 2 when Battery SoC is above value configured on the switch Node and Timer is On/Off.

1682863764636.png

The question is now how to integrate the switch Node output for value below Battery SoC.

I had the idea of replacing the switch Node by a change node with regular expression which matches SoC valus between 70-99.
1682863984394.png

configured like this the change node will still output the SoC value instead of 1; either regex does not match or i do misunderstand the usage of a change node for my purpose ...


thanks for any advice how to properly configure a flow to achieve my requirement.

best regards,



Node-RED
1682863764636.png (31.9 KiB)
1682863984394.png (15.3 KiB)
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

7 Answers
derrick thomas avatar image
derrick thomas answered ·

Probably be much simpler to use a function node that way you can combine the timer and SOC arguments with &&. You can call and set the SOC to a flow message using a change node then use it in the function node. You can combine several conditions in one function node and output a single payload message to the relay control. Clear as mud?

2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

alphalinux avatar image
alphalinux answered ·

Hi
appreciate feedback.
A function node seems to be pretty powerful. would also make the flow much simpler.
unfortunately I'm not familiar with javascript ...
Do you recommend any code examples to adopt ?

2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

hominidae avatar image
hominidae answered ·

...although a function node can make it more simple, I don't think that this alone would suffice.

Node-red is event driven. There are two events / states that need to be combined when evaluating the logic.

Timer-event and SoC%-change event....both occur asynchronously in time to each other.

I suggest to store the last state of each event in a flow variable (context variable) when it happens. then evaluate the logic (AND) from both, every time one event occurs. Regarding context stores in NR, see https://nodered.org/docs/user-guide/context

2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

helmut51 avatar image
helmut51 answered ·

Why don't you just use the first switch on the left? It checks, if SoC is below or above, and then you get two paths for the respective SoC. The asynchronous events are no problem in your case, as the AND is blocking (sending no message) until both events are registered by the AND.

I did not check everything, but it seems that you just need another change node for the second output of the switch and it works.

2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

nishad avatar image
nishad answered ·

flows.txtHere's my untested flow. I use something similar on my system. My flow shows my devices, but you can easily adapt it for your devices.

The first flow saves the SoC in a global context called StateOfCharge everytime SoC changes.

The second flow triggers the flow with Off/On at 12pm/1pm respectively. The SetRelay functions that gets the SoC saved it the global contexts and executes the logic to set the relay state appropriately.

1683046601895.png

SetRelay function body:

var soc = global.get("StateOfCharge");
if (msg.payload == true) {
    // timer on
    if (soc >= 50) {
        // set relay on
        msg.payload = 1;
    } else {
        // set relay off
        msg.payload = 0;
    }
} else {
    // timer off
    if (soc >= 50) {
        // set relay off
        msg.payload = 0;
    } else {
        // stop further processing
        msg.payload = null;
    }    
}
return msg;




1683046601895.png (60.1 KiB)
flows.txt (4.5 KiB)
2 comments
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

alphalinux avatar image alphalinux commented ·
Hi all

will give it a try when i'm back again, thanks so far


0 Likes 0 ·
bruggie avatar image bruggie commented ·

The line msg.payload = null should be msg = null just in case someone is interested in using this and runs into errors that dbus cant serialize null like myself.

0 Likes 0 ·
alphalinux avatar image
alphalinux answered ·

Relay-Timer_Flow.txt
Hi

I just rebuild the flow from your input.
It does switch Relay 2 On at timer event and Battery SoC.
Nevertheless it does not switch Relay 2 Off; regardless of timer state and/or SoC.
Did i miss something ?

Node-RED flow is attached
1683233467118.png


1683233467118.png (24.8 KiB)
2 comments
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

nishad avatar image nishad commented ·

Add a debug node after SetRelay. The output should help you debug it.


Here's another issue. Path to the relay in the attached JSON says, /Relay/1/State. The node name indicates Relay 2.

0 Likes 0 ·
Show more comments
alphalinux avatar image
alphalinux answered ·

Hi

since the flows are driven by state changes i struggled to have a working flow to set the Relay 2 Off at a certain SoC.

currently i have setup an inject node as "Timer On" to a function node which is setting the message payload to 1 at >= SoC. If SoC is not met message payload is 0.

To switch Relay 2 Off an another function node is setup in interval mode to have the state pushed every minute and check against SoC to protect battery from low discharge. It keeps Relay 2 On as long as Soc is >= xx; while Relay 2 Off when SoC < 30

Maybe someone has a more elegant way to accomplish the same functionality ?

1683666706238.png

SetRelayOn

var soc = global.get("StateOfCharge");
if (msg.payload == true) {
    // Timer On
    if (soc >= 90) {
        // Set Relay On
        msg.payload = 1;
    } else {
        // Set Relay Off
        msg.payload = 0;
    }
}
return msg;

SetRelayOff

var soc = global.get("StateOfCharge");
if (msg.payload == false) {
    if (soc >= 30) {
        // Set Relay On
        msg.payload = 1;
    } else {
    if (soc < 30) {
        msg.payload = 0;
    }
}
}
return msg;




1683666706238.png (36.6 KiB)
3 comments
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

helmut51 avatar image helmut51 commented ·

Well, elegant might be subjective, but just as a comment: the idea of any library in a computer language is that it should be used (as it is tested thoroughly). And here, the function node should be only used, when there is no alternative. But in this case the function is a simple rule, which can be certainly implemented with standard nodes.

0 Likes 0 ·
alphalinux avatar image alphalinux helmut51 commented ·
Hi

I absolutely agree with you regarding the preferred use of "standard nodes" but so far i was not able to build a working flow with these.

any contribution is very welcome




0 Likes 0 ·
helmut51 avatar image helmut51 commented ·

You just have to connect the second output of the switch to another change node, which adds a 0 for the below SoC status. You could also use a single change node instead of the switch and two change nodes, then you have to change the SoC status to 0/1 using a JSONata expression.

The same way you could substitute the other switch/change combination by a single JSONata change node. I would call this elegant..;-)

0 Likes 0 ·