GX Opportunity Loads and Node-RED

The 3.80 release of Venus brings us Opportunity Loads. Which is an awesome way to make maximum use of the PV power (by activating extra loads, ev charging, etc). Now the initial release within Venus “only” supports our battery, EV charger and Shelly devices. Node-RED users of course want more, and preferably in an easy and user friendly way. In this post I am going to explain a bit on how to accomplish just that.

It is good to know that under the hood, Opportunity Loads, communicates with the resources over the S2 protocol. S2 is a communication standard for energy flexibility in homes and buildings, developed by TNO in the Netherlands and becoming an international standard. If you are interested in diving into that rabbit hole, I can certainly recommend starting on https://s2standard.org/ and reading the white-paper there at some point.

Luckily we can hop over that hole for now and focus on getting an extra load working. All we need to know is that Opportunity Loads works with Operation Mode Based Control types and that each extra defined load needs its own Resource Manager. An operation mode can be as simple as “on” or “off”, but also a bit more advanced as steering anything between 0 and 100% power. And will need some way to attach energy consumption to the state. Which is enough intro to get started with getting a third party load as opportunity load into Node-RED.

First we need to install the palette: node-red-contrib-s2 into Node-RED. At some future moment we’ll pre-install that into Venus, but as the package is still being actively changed regularly I like the benefit of being able to update it outside of a Venus release for now.

The most simple example is just a simple load to a wifi plug (TuYa, Ikea, Tapo, Acara and countless others) and a load of say 500 Watts when switched on, 0 Watts when switched off. So we start by pulling the simplest node: s2-resource onto the canvas and configure that.

Configuration has a few tabs, lets go through them in order:

Starting with the Connection tab. The Transport is the way the load will communicate to the GX device. S2 supports multiple transport options and so does this node. For the GX connection, the Built-in - D-Bus (Victron Energy) is the best choice.

Under the hood, the s2-resource will create a virtual device, just like the regular virtual devices, on the dbus and it will need some extra information to be able to do that. If you click the + for the Virtual Device, you’ll get the following options:

Connection can be left to Auto, Device Type can be either AC load or heatpump. Likely you’ll just connect a single phase device on a certain phase and position. Power measurements are there to be able to tell opportunity loads the amount of energy the device is using. Measurements report in instantaneous power (W).

Setting the checkbox for showing the raw S2 messages in debug sidebar will help check what S2 communication is going on between the Resource Manager and the CEM (Opportunity Loads).

Then on to the next tab, which is the Resource Manager (or RM). There is no need to fill out anything here, as it mostly is used for identification purposes. Only note that, because the AC load is consuming energy, the “Consumer” checkbox needs to be checked.

The last tab consists of configuring the modes the device can be in.

As mentioned before, the used control type for opportunity loads is Operation Mode Based. For most Resource Mangers, the S2 standard also adds “Not controllable” as control type. Meaning that, if that is the active control type, the device cannot be controlled. E.g. when it is plugged out or for some other reason.

Then the “Friendly” panel gives a list, by default with just one item, to specify all of the modes the AC load can be in. For a 2 state device, you should add a second item, describing the used power when on. The minimum time for the mode is a per-mode minimum-duration timer (e.g. don’t cycle a compressor faster than every N minutes).

Lastly there is a dropdown for setting the default mode (or none) on deploy of the flow. And the option to automatically confirm mode switches (default unchecked). This should be checked if you don’t have a way to actually tell in what state the device is, instead of manually telling the resource manager in what state the device is. For the wifi plugs wire the plug’s real on/off feedback into the s2-resource input as a ModeConfirmation instead.

I hope this is enough to get you started with configuring resource managers for Opportunity loads within Node-RED. Also note that there are importable examples for the nodes too.

If you’re having issues building flows, kindly post them into new or existing, similar topics. Thanks.

Hi @dfaber and @nickdb

thanks a lot for introducing Opportunity Loads in Node-RED!

You already show a simple example flow, but perhaps a similar example using a Shelly could be a useful addition, as this might be a fairly common use case in practice: Resource → Virtual Switch → Shelly

It also shows the required message translations and connections between the nodes and could give users another practical starting point.

Perhaps you have some ideas for improvements or suggestions on how this could best be integrated into the documentation?

Just an idea — I thought it might be useful for people getting started with Opportunity Loads. :blush:

Best,
Axel


Power measurement:

msg.payload = {
  "Ac/L1/Power": msg.payload
};

return msg;

Mode confirmation:

var state = msg.payload ;

if (state === 1) {
  msg.topic = "ModeConfirmation";
  msg.payload = {
  label: "On"
  };
return msg;
}

if (state === 0) {
  msg.topic = "ModeConfirmation";
  msg.payload = {
  label: "Off"
  };
return msg;
}

return null;

Mode Instrucion:

var label = msg.payload && msg.payload.label;

if (label === "On") {
  msg.payload = {
  "SwitchableOutput/output_1/State": 1
  };
return msg;
}

if (label === "Off") {
  msg.payload = {
  "SwitchableOutput/output_1/State": 0
  };
return msg;
}

return null;

Auto

if (msg.payload === 1) {
  msg.payload = {
  command: "SetAvailableControlTypes",
    availableControlTypes: ["OPERATION_MODE_BASED_CONTROL"]
  };
return msg;
}

if (msg.payload === 0) {
  msg.payload = {
  command: "SetAvailableControlTypes",
  availableControlTypes: [ "NOT_CONTROLABLE" ]
  };
return msg;
}

return null;