Virtual AC Load node: example of parameters to inject

In another topic the question was raised on how to use the Virtual AC Load node.
I grabbed (most of) the fields with MQTT Explorer and made this example to inject them into the node.

Hopefully someone can use this to their benefit :slight_smile:

[{"id":"e4a02e8dd8f25f92","type":"victron-virtual","z":"9f95e47b9a8d70a1","name":"","outputs":1,"device":"acload","default_values":false,"acload_nrofphases":1,"enable_s2support":false,"battery_capacity":25,"include_battery_temperature":false,"battery_voltage_preset":"24","battery_voltage_custom":24,"generator_type":"ac","generator_nrofphases":1,"include_engine_hours":false,"include_starter_voltage":false,"include_history_energy":false,"grid_nrofphases":1,"include_motor_temp":false,"include_controller_temp":false,"include_coolant_temp":false,"include_motor_rpm":true,"include_motor_direction":true,"position":0,"pvinverter_nrofphases":1,"switch_1_type":1,"switch_1_min":0,"switch_1_max":"","switch_1_initial":0,"switch_1_label":"","switch_1_unit":"","switch_1_step":1,"switch_1_customname":"","switch_1_group":"","switch_1_include_measurement":false,"switch_1_rgb_color_wheel":false,"switch_1_cct_wheel":false,"switch_1_rgb_white_dimmer":false,"fluid_type":0,"include_tank_battery":false,"include_tank_temperature":false,"tank_battery_voltage":3.3,"tank_capacity":0.2,"temperature_type":2,"include_humidity":false,"include_pressure":false,"include_temp_battery":false,"temp_battery_voltage":3.3,"x":320,"y":460,"wires":[["93fa80a7081fa9ab"]]},{"id":"93fa80a7081fa9ab","type":"debug","z":"9f95e47b9a8d70a1","name":"debug 7","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":520,"y":460,"wires":[]},{"id":"f0a888d88d7bfdd8","type":"inject","z":"9f95e47b9a8d70a1","name":"","props":[{"p":"topic","v":"0","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":350,"y":400,"wires":[["5bd91fdac60b4e2a"]]},{"id":"5bd91fdac60b4e2a","type":"function","z":"9f95e47b9a8d70a1","name":"AC Load","func":"msg.payload = {\n    \"/Serial\": 1,\n    \"/Ac/L1/Voltage\": 235,\n    \"/Ac/L1/Current\": 1,\n    \"/Ac/L1/Power\": 200,\n    \"/Ac/L1/PowerFactor\": 1,\n    \"/Ac/L1/Energy/Forward\": 1000,\n    \"/Ac/L1/Energy/Reverse\": 0,\n/*\n    \"Ac/L2/Voltage\": 235,\n    \"/Ac/L2/Current\": 1,\n    \"/Ac/L2/Power\": 200,\n    \"/Ac/L2/PowerFactor\": 1,\n    \"/Ac/L2/Energy/Forward\": 1000,\n    \"/Ac/L2/Energy/Reverse\": 0,\n    \"/Ac/L3/Voltage\": 235,\n    \"/Ac/L3/Current\": 1,\n    \"/Ac/L3/Power\": 200,\n    \"/Ac/L3/PowerFactor\": 1,\n    \"/Ac/L3/Energy/Forward\": 1000,\n    \"/Ac/L3/Energy/Reverse\": 0,\n*/\n    \"/Ac/Power\": 200,\n    \"/Ac/Energy/Forward\": 1000,\n    \"/Ac/Energy/Reverse\": 0,\n};\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":400,"wires":[["e4a02e8dd8f25f92"]]},{"id":"13da2462149302af","type":"global-config","env":[],"modules":{"@victronenergy/node-red-contrib-victron":"1.6.56"}}]
1 Like

Thanks Bart, I was still using custom inputs and just reconfigured everything based on your post. I am using HomeWizard meters and sockets to measure my PV. It currently looks like this:

[
    {
        "id": "c638519ca3f162f8",
        "type": "group",
        "z": "b51fc0718e9c7f9d",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "c942bad4ad7105fd",
            "8116ebb3ac362090",
            "8f65547a34d2b35f",
            "8519a23a0f847c60",
            "a01c2d5855f30b8d",
            "a008613031afeb37",
            "811096c848896695",
            "1aa0d1b15a78f3be",
            "2ee0b636cdba77fa"
        ],
        "x": 54,
        "y": 2139,
        "w": 1272,
        "h": 202
    },
    {
        "id": "c942bad4ad7105fd",
        "type": "victron-virtual",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "PV Veranda",
        "outputs": 1,
        "device": "pvinverter",
        "default_values": false,
        "enable_s2support": false,
        "battery_capacity": 25,
        "include_battery_temperature": false,
        "battery_voltage_custom": "",
        "include_engine_hours": false,
        "include_starter_voltage": false,
        "include_history_energy": false,
        "grid_nrofphases": 1,
        "include_motor_temp": false,
        "include_controller_temp": false,
        "include_coolant_temp": false,
        "include_motor_rpm": true,
        "include_motor_direction": true,
        "position": "1",
        "pvinverter_nrofphases": "3",
        "fluid_type": 0,
        "include_tank_battery": false,
        "include_tank_temperature": false,
        "tank_battery_voltage": 3.3,
        "tank_capacity": 0.2,
        "temperature_type": 2,
        "include_humidity": false,
        "include_pressure": false,
        "include_temp_battery": false,
        "temp_battery_voltage": 3.3,
        "x": 1010,
        "y": 2240,
        "wires": [
            [
                "2ee0b636cdba77fa"
            ]
        ]
    },
    {
        "id": "8116ebb3ac362090",
        "type": "inject",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "5",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 170,
        "y": 2220,
        "wires": [
            [
                "8f65547a34d2b35f"
            ]
        ]
    },
    {
        "id": "8f65547a34d2b35f",
        "type": "http request",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "PV - HomeWizard Measurements",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://192.168.88.170/api/v1/data",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 460,
        "y": 2220,
        "wires": [
            [
                "1aa0d1b15a78f3be"
            ]
        ]
    },
    {
        "id": "8519a23a0f847c60",
        "type": "inject",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": "5",
        "topic": "/Ac/MaxPower",
        "payload": "4",
        "payloadType": "num",
        "x": 510,
        "y": 2180,
        "wires": [
            [
                "1aa0d1b15a78f3be"
            ]
        ]
    },
    {
        "id": "a01c2d5855f30b8d",
        "type": "http request",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "PV - HomeWizard Information",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://192.168.88.170/api",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 470,
        "y": 2260,
        "wires": [
            [
                "1aa0d1b15a78f3be"
            ]
        ]
    },
    {
        "id": "a008613031afeb37",
        "type": "inject",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": "1",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 170,
        "y": 2260,
        "wires": [
            [
                "a01c2d5855f30b8d"
            ]
        ]
    },
    {
        "id": "811096c848896695",
        "type": "link in",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "Throttle",
        "links": [
            "7a1d5ae47e397e2e"
        ],
        "x": 585,
        "y": 2300,
        "wires": [
            [
                "1aa0d1b15a78f3be"
            ]
        ]
    },
    {
        "id": "1aa0d1b15a78f3be",
        "type": "function",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "Parse & Route PV Data",
        "func": "const data = msg.payload;\n\nlet payload = {};\nlet statusCode = null;\n\n// --- Throttling (optional): if you send msg.topic=\"throttling\" ---\nif (msg.topic === \"throttling\" && (data === true || data === false)) {\n    context.set(\"isThrottling\", data);\n    return null;\n}\nconst isThrottling = context.get(\"isThrottling\") === true;\nif (isThrottling) statusCode = 12;\n\n// --- One-time inject: /Ac/MaxPower ---\nif (msg.topic === \"/Ac/MaxPower\") {\n    payload[\"/Ac/MaxPower\"] = Number(data);\n    msg.payload = payload;\n    return msg;\n}\n\n// --- Determine phase mode from product_type (when available) ---\n// HWE-KWH3 => 3-phase\n// HWE-KWH1, HWE-SKT, unknown => 1-phase\nlet phaseMode = null; // 1 or 3\n\nif (typeof data === \"object\" && data && data.product_type) {\n    payload[\"/ProductName\"] = String(data.product_type);\n    if (data.serial) payload[\"/Serial\"] = String(data.serial);\n\n    if (data.product_type === \"HWE-KWH3\") phaseMode = 3;\n    else phaseMode = 1; // includes HWE-KWH1, HWE-SKT, and any unknown types\n\n    // Save mode so measurement messages can use it\n    context.set(\"phaseMode\", phaseMode);\n\n    msg.payload = payload;\n    return msg;\n}\n\n// If no product_type in this msg, fall back to last known mode (default 1)\nphaseMode = context.get(\"phaseMode\") || 1;\n\n// --- Measurement handling ---\nif (typeof data === \"object\" && data && (\"wifi_ssid\" in data)) {\n\n    if (phaseMode === 3) {\n        // Voltage\n        payload[\"/Ac/L1/Voltage\"] = Number(data.active_voltage_l1_v);\n        payload[\"/Ac/L2/Voltage\"] = Number(data.active_voltage_l2_v);\n        payload[\"/Ac/L3/Voltage\"] = Number(data.active_voltage_l3_v);\n\n        // Current\n        payload[\"/Ac/L1/Current\"] = Number(data.active_current_l1_a);\n        payload[\"/Ac/L2/Current\"] = Number(data.active_current_l2_a);\n        payload[\"/Ac/L3/Current\"] = Number(data.active_current_l3_a);\n\n        // Power (negated for PV export display)\n        payload[\"/Ac/L1/Power\"] = -1 * Number(data.active_power_l1_w);\n        payload[\"/Ac/L2/Power\"] = -1 * Number(data.active_power_l2_w);\n        payload[\"/Ac/L3/Power\"] = -1 * Number(data.active_power_l3_w);\n        payload[\"/Ac/Power\"]    = -1 * Number(data.active_power_w);\n\n        // Energy\n        if (\"total_power_export_kwh\" in data) {\n            const total = Number(data.total_power_export_kwh);\n            payload[\"/Ac/Energy/Forward\"] = total;\n\n            const perPhase = total / 3;\n            payload[\"/Ac/L1/Energy/Forward\"] = perPhase;\n            payload[\"/Ac/L2/Energy/Forward\"] = perPhase;\n            payload[\"/Ac/L3/Energy/Forward\"] = perPhase;\n        }\n\n        // StatusCode fallback (if not throttling)\n        if (statusCode === null) {\n            statusCode = Math.abs(Number(data.active_power_w)) > 0 ? 7 : 8;\n        }\n\n    } else {\n        // 1-phase (L1 only)\n        payload[\"/Ac/L1/Voltage\"] = Number(data.active_voltage_v);\n        payload[\"/Ac/L1/Current\"] = Number(data.active_current_a);\n\n        // Power (negated for PV export display)\n        payload[\"/Ac/L1/Power\"] = -1 * Number(data.active_power_l1_w);\n        payload[\"/Ac/Power\"]    = -1 * Number(data.active_power_w);\n\n        // Energy\n        if (\"total_power_export_kwh\" in data) {\n            const total = Number(data.total_power_export_kwh);\n            payload[\"/Ac/Energy/Forward\"]    = total;\n            payload[\"/Ac/L1/Energy/Forward\"] = total;\n        }\n\n        // StatusCode fallback (if not throttling)\n        if (statusCode === null) {\n            statusCode = Math.abs(Number(data.active_power_w)) > 0 ? 7 : 8;\n        }\n    }\n\n    if (statusCode !== null) payload[\"/StatusCode\"] = statusCode;\n\n    msg.payload = payload;\n    return msg;\n}\n\nreturn null;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 770,
        "y": 2240,
        "wires": [
            [
                "c942bad4ad7105fd"
            ]
        ]
    },
    {
        "id": "2ee0b636cdba77fa",
        "type": "debug",
        "z": "b51fc0718e9c7f9d",
        "g": "c638519ca3f162f8",
        "name": "debug 12",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1220,
        "y": 2240,
        "wires": []
    },
    {
        "id": "f26b4f5c6c83d546",
        "type": "global-config",
        "env": [],
        "modules": {
            "@victronenergy/node-red-contrib-victron": "1.6.56"
        }
    }
]

And this is what it looks like for an AC Load:

[
    {
        "id": "ac5c81226c76d6e8",
        "type": "group",
        "z": "b51fc0718e9c7f9d",
        "style": {
            "stroke": "#999999",
            "stroke-opacity": "1",
            "fill": "none",
            "fill-opacity": "1",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "c5c969651cadb2e7",
            "c016a63ac04337a5",
            "30111398d9e167ce",
            "0910ad649486a7a7",
            "fdb30a6c6fbb023d",
            "e59be2c46b7c12b9",
            "5015e22747103914"
        ],
        "x": 34,
        "y": 1119,
        "w": 1252,
        "h": 142
    },
    {
        "id": "c5c969651cadb2e7",
        "type": "victron-virtual",
        "z": "b51fc0718e9c7f9d",
        "g": "ac5c81226c76d6e8",
        "name": "Heatpump",
        "outputs": 1,
        "device": "acload",
        "default_values": false,
        "acload_nrofphases": 1,
        "enable_s2support": false,
        "battery_capacity": 25,
        "include_battery_temperature": false,
        "battery_voltage_preset": "24",
        "battery_voltage_custom": 24,
        "generator_type": "ac",
        "generator_nrofphases": 1,
        "include_engine_hours": false,
        "include_starter_voltage": false,
        "include_history_energy": false,
        "grid_nrofphases": 1,
        "include_motor_temp": false,
        "include_controller_temp": false,
        "include_coolant_temp": false,
        "include_motor_rpm": true,
        "include_motor_direction": true,
        "position": 0,
        "pvinverter_nrofphases": 1,
        "switch_1_type": 1,
        "switch_1_min": 0,
        "switch_1_max": "",
        "switch_1_initial": 0,
        "switch_1_label": "",
        "switch_1_unit": "",
        "switch_1_step": 1,
        "switch_1_customname": "",
        "switch_1_group": "",
        "switch_1_include_measurement": false,
        "switch_1_rgb_color_wheel": false,
        "switch_1_cct_wheel": false,
        "switch_1_rgb_white_dimmer": false,
        "fluid_type": 0,
        "include_tank_battery": false,
        "include_tank_temperature": false,
        "tank_battery_voltage": 3.3,
        "tank_capacity": 0.2,
        "temperature_type": 2,
        "include_humidity": false,
        "include_pressure": false,
        "include_temp_battery": false,
        "temp_battery_voltage": 3.3,
        "x": 970,
        "y": 1180,
        "wires": [
            [
                "5015e22747103914"
            ]
        ]
    },
    {
        "id": "c016a63ac04337a5",
        "type": "inject",
        "z": "b51fc0718e9c7f9d",
        "g": "ac5c81226c76d6e8",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "5",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 150,
        "y": 1160,
        "wires": [
            [
                "fdb30a6c6fbb023d"
            ]
        ]
    },
    {
        "id": "30111398d9e167ce",
        "type": "inject",
        "z": "b51fc0718e9c7f9d",
        "g": "ac5c81226c76d6e8",
        "name": "",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": "1",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 150,
        "y": 1220,
        "wires": [
            [
                "0910ad649486a7a7"
            ]
        ]
    },
    {
        "id": "0910ad649486a7a7",
        "type": "http request",
        "z": "b51fc0718e9c7f9d",
        "g": "ac5c81226c76d6e8",
        "name": "AC - HomeWizard Information",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://192.168.88.59/api",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 390,
        "y": 1220,
        "wires": [
            [
                "e59be2c46b7c12b9"
            ]
        ]
    },
    {
        "id": "fdb30a6c6fbb023d",
        "type": "http request",
        "z": "b51fc0718e9c7f9d",
        "g": "ac5c81226c76d6e8",
        "name": "AC - HomeWizard Measurements",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://192.168.88.59/api/v1/data",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 400,
        "y": 1160,
        "wires": [
            [
                "e59be2c46b7c12b9"
            ]
        ]
    },
    {
        "id": "e59be2c46b7c12b9",
        "type": "function",
        "z": "b51fc0718e9c7f9d",
        "g": "ac5c81226c76d6e8",
        "name": "Parse & Route AC Data",
        "func": "const data = msg.payload;\n\n// Load last-known state so we can merge /api + /api/v1/data updates\nconst state = flow.get(\"device_stats\") || {};\nlet payload = { ...state };\n\nlet changed = false;\n\n// --- Power Data Handling ---\nif (typeof data === \"object\" && data && (\"wifi_ssid\" in data)) {\n    payload[\"/Ac/L1/Voltage\"]        = data.active_voltage_v;\n    payload[\"/Ac/L1/Current\"]        = data.active_current_a;\n    payload[\"/Ac/L1/Power\"]          = Number(data.active_power_l1_w);\n    payload[\"/Ac/L1/PowerFactor\"]    = data.active_power_factor;\n    payload[\"/Ac/L1/Energy/Forward\"] = data.total_power_import_kwh;\n    payload[\"/Ac/L1/Energy/Reverse\"] = 0;\n\n    payload[\"/Ac/Power\"]             = Number(data.active_power_w);\n    payload[\"/Ac/Energy/Forward\"]    = data.total_power_import_kwh;\n    payload[\"/Ac/Energy/Reverse\"]    = 0;\n\n    changed = true;\n}\n\n// --- Product Info Handling ---\nif (typeof data === \"object\" && data && (\"product_type\" in data) && (\"serial\" in data)) {\n    payload[\"/ProductName\"] = data.product_type;\n    payload[\"/Serial\"]      = data.serial;\n\n    changed = true;\n}\n\n// If neither block matched, don't send anything\nif (!changed) return null;\n\n// Save merged state\nflow.set(\"device_stats\", payload);\n\n// Output to victron-virtual\nmsg.payload = payload;\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 730,
        "y": 1180,
        "wires": [
            [
                "c5c969651cadb2e7"
            ]
        ]
    },
    {
        "id": "5015e22747103914",
        "type": "debug",
        "z": "b51fc0718e9c7f9d",
        "g": "ac5c81226c76d6e8",
        "name": "debug 2",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1180,
        "y": 1180,
        "wires": []
    },
    {
        "id": "bd417682b346c63b",
        "type": "global-config",
        "env": [],
        "modules": {
            "@victronenergy/node-red-contrib-victron": "1.6.56"
        }
    }
]
1 Like

Hello,
thanks for sharing. Maybe you can help me:
I try to have a Shelly Plus RGBW PM visualized as an AC Load in the dashboard and also add it as a switch to turn it on and off.
First I tried to add it as PV inverter, which works (at least in the ‘devices” section of the UI, no switching possible), but it actually does not show as an extra ‘load’ on the dashboard.

Now I found your flows with the virtual device of type ‘acload’
When I try to add something like this in my Node Red, then it always asks me to choose a type (PV inverter, Battery, …) etc.
I can not add it as an acload

Also when I import your virtual nodes, it shows this

grafik

I can not figure out how to achieve this. Any help appreciated!
Can I even achieve my goals with this virtual node (to render my Shelly load and add as a switch?)

I also have tried to write on the DBUS directly using MQTT but failed miserably….