Node Red help with shedule discharge charge during an event

So what i hope to do is with an manual press get an event set for a 1200 with a SOC above 65% start so it discharges the battery if it gets below 60% stop and a 1300 it starts charging until 1400 when the event finishes and send a stop notification and -50 grid set point and a -1 DVCC in addition to this i would like after the event if i press it again it would run the next day and a manual press so i can stop the event from starting if pressed accidentally ideally i would like a push to tell me if the event is is running ie pushed accidentally. Here is what i got after days of banging my head and i still can’t get it to work . Any help would be appreciated

[
    {
        "id": "1a63f41645ba5e52",
        "type": "tab",
        "label": "Power Up Session Alpha",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "84b2246d471931f0",
        "type": "change",
        "z": "1a63f41645ba5e52",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "soc",
                "pt": "flow",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 410,
        "y": 40,
        "wires": [
            []
        ]
    },
    {
        "id": "dd912d151a1569b6",
        "type": "change",
        "z": "1a63f41645ba5e52",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "setpoint",
                "pt": "flow",
                "to": "payload",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 400,
        "y": 100,
        "wires": [
            []
        ]
    },
    {
        "id": "4e1516ce53b0a0f2",
        "type": "victron-input-battery",
        "z": "1a63f41645ba5e52",
        "service": "com.victronenergy.battery/512",
        "path": "/Soc",
        "serviceObj": {
            "service": "com.victronenergy.battery/512",
            "name": "Pylontech battery"
        },
        "pathObj": {
            "path": "/Soc",
            "type": "float",
            "name": "State of charge (%)"
        },
        "name": "",
        "onlyChanges": true,
        "x": 170,
        "y": 20,
        "wires": [
            [
                "84b2246d471931f0"
            ]
        ]
    },
    {
        "id": "d67ca93879292897",
        "type": "victron-input-ess",
        "z": "1a63f41645ba5e52",
        "service": "com.victronenergy.settings",
        "path": "/Settings/CGwacs/AcPowerSetPoint",
        "serviceObj": {
            "service": "com.victronenergy.settings",
            "name": "Venus settings"
        },
        "pathObj": {
            "path": "/Settings/CGwacs/AcPowerSetPoint",
            "type": "integer",
            "name": "Grid set-point (W)"
        },
        "name": "",
        "onlyChanges": true,
        "x": 160,
        "y": 80,
        "wires": [
            [
                "dd912d151a1569b6"
            ]
        ]
    },
    {
        "id": "5da65ef8f136a94c",
        "type": "inject",
        "z": "1a63f41645ba5e52",
        "name": "Manual Start",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "topic": "",
        "payload": "manual_start",
        "payloadType": "str",
        "x": 110,
        "y": 140,
        "wires": [
            [
                "d95c8cdf200c096c"
            ]
        ]
    },
    {
        "id": "2bad45313e6ac5ff",
        "type": "inject",
        "z": "1a63f41645ba5e52",
        "name": "Manual Stop",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "",
        "topic": "",
        "payload": "manual_stop",
        "payloadType": "str",
        "x": 110,
        "y": 260,
        "wires": [
            [
                "a67bb775a23251a6"
            ]
        ]
    },
    {
        "id": "d95c8cdf200c096c",
        "type": "function",
        "z": "1a63f41645ba5e52",
        "name": "Set Event Date",
        "func": "const now = new Date();\nconst startTime = new Date(now);\nconst stopTime = new Date(now);\n\n// Define event times\nstartTime.setHours(12, 0, 0);\nstopTime.setHours(14, 0, 0);\n\n// If current time is past the stop time, schedule for the next day\nif (now >= stopTime) {\n    startTime.setDate(startTime.getDate() + 1);\n    stopTime.setDate(stopTime.getDate() + 1);\n}\n\nflow.set('event_date', startTime);\nflow.set('event_stop_time', stopTime);\nflow.set('event_running', true);\nflow.set('soc', 70); // Initial SOC for testing\nreturn msg;",
        "outputs": 1,
        "x": 230,
        "y": 160,
        "wires": [
            [
                "235c3185b210d918"
            ]
        ]
    },
    {
        "id": "a67bb775a23251a6",
        "type": "function",
        "z": "1a63f41645ba5e52",
        "name": "Stop Event",
        "func": "flow.set('event_running', false);\nflow.set('grid_set_point_sent', false);\nflow.set('dvcc_sent', false);\nreturn [{ payload: -50 }, { payload: -1 }];",
        "outputs": 2,
        "x": 230,
        "y": 220,
        "wires": [
            [
                "eae850e5c87f816f"
            ],
            [
                "a7d49d7c5d95063f"
            ]
        ]
    },
    {
        "id": "235c3185b210d918",
        "type": "function",
        "z": "1a63f41645ba5e52",
        "name": "Event Control",
        "func": "const now = new Date();\nconst eventDate = flow.get('event_date');\nconst stopTime = flow.get('event_stop_time');\nconst eventRunning = flow.get('event_running') || false;\nconst soc = flow.get('soc') || 70; // Dynamic SOC\n\nif (now >= eventDate && now <= stopTime && eventRunning) {\n    const currentHour = now.getHours();\n    const currentMinute = now.getMinutes();\n\n    if (currentHour === 12 && currentMinute >= 0 && currentMinute < 60 && soc > 68) {\n        return { payload: 'max_discharge' };\n    } else if (currentHour === 13 && currentMinute >= 0 && currentMinute < 60 && soc > 30) {\n        return { payload: 'max_charge' };\n    } else if (now > stopTime) {\n        flow.set('event_running', false);\n        return { payload: 'stop_event' };\n    } else {\n        return null;\n    }\n} else {\n    return null;\n}\n",
        "outputs": 1,
        "x": 400,
        "y": 160,
        "wires": [
            [
                "63a2a378e670c2af"
            ]
        ]
    },
    {
        "id": "63a2a378e670c2af",
        "type": "switch",
        "z": "1a63f41645ba5e52",
        "name": "Handle Event",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "max_discharge",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "max_charge",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "stop_event",
                "vt": "str"
            }
        ],
        "outputs": 3,
        "x": 570,
        "y": 160,
        "wires": [
            [
                "315c1b925c255e97"
            ],
            [
                "b98e28ce14682b74"
            ],
            [
                "d9acc5ebd0964677"
            ]
        ]
    },
    {
        "id": "315c1b925c255e97",
        "type": "function",
        "z": "1a63f41645ba5e52",
        "name": "Check SOC for Discharge",
        "func": "const soc = flow.get('soc') || 70;\nif (soc >= 65) {\n    return { payload: -6700 };\n} else {\n    return [{ payload: -50 }, { payload: -1 }];\n}\n",
        "outputs": 2,
        "x": 670,
        "y": 100,
        "wires": [
            [
                "eae850e5c87f816f"
            ],
            [
                "a7d49d7c5d95063f"
            ]
        ]
    },
    {
        "id": "b98e28ce14682b74",
        "type": "function",
        "z": "1a63f41645ba5e52",
        "name": "Check SOC for Charge",
        "func": "const soc = flow.get('soc') || 70;\nif (soc >= 30) {\n    return { payload: 8000 };\n} else {\n    return [{ payload: -50 }, { payload: -1 }];\n}\n",
        "outputs": 2,
        "x": 590,
        "y": 280,
        "wires": [
            [
                "eae850e5c87f816f"
            ],
            [
                "a7d49d7c5d95063f"
            ]
        ]
    },
    {
        "id": "eae850e5c87f816f",
        "type": "function",
        "z": "1a63f41645ba5e52",
        "name": "Grid Set Point",
        "func": "const action = msg.payload;\nconst currentGridSetPointSent = flow.get('grid_set_point_sent');\n\nif (action === -6700 || action === 8000) {\n    flow.set('grid_set_point_sent', action === -50);\n    return { payload: action };\n} else if (action === 'stop_event') {\n    if (!currentGridSetPointSent) {\n        flow.set('grid_set_point_sent', true);\n        return { payload: -50 };\n    } else {\n        return null;\n    }\n} else {\n    return null;\n}\n",
        "outputs": 1,
        "x": 900,
        "y": 80,
        "wires": [
            [
                "ca3448310c69e4c3"
            ]
        ]
    },
    {
        "id": "a7d49d7c5d95063f",
        "type": "function",
        "z": "1a63f41645ba5e52",
        "name": "DVCC Output",
        "func": "const action = msg.payload;\nconst dvccSent = flow.get('dvcc_sent');\n\nif (action === -1) {\n    flow.set('dvcc_sent', true);\n    return { payload: -1 };\n} else if (action === 'stop_event') {\n    if (!dvccSent) {\n        flow.set('dvcc_sent', true);\n        return { payload: -1 };\n    } else {\n        return null;\n    }\n} else {\n    return null;\n}\n",
        "outputs": 1,
        "x": 860,
        "y": 360,
        "wires": [
            [
                "ca3448310c69e4c3"
            ]
        ]
    },
    {
        "id": "d9acc5ebd0964677",
        "type": "function",
        "z": "1a63f41645ba5e52",
        "name": "Session End",
        "func": "flow.set('event_running', false);\nflow.set('grid_set_point_sent', false);\nflow.set('dvcc_sent', false);\nreturn [{ payload: -50 }, { payload: -1 }];",
        "outputs": 2,
        "x": 740,
        "y": 200,
        "wires": [
            [
                "eae850e5c87f816f"
            ],
            [
                "a7d49d7c5d95063f"
            ]
        ]
    },
    {
        "id": "ca3448310c69e4c3",
        "type": "debug",
        "z": "1a63f41645ba5e52",
        "name": "Debug Output",
        "active": true,
        "tosidebar": true,
        "x": 920,
        "y": 280,
        "wires": []
    }
]

I am not using the victron contrib nodes to control my ESS, hence I cannot import your flow fully.
Some observations:

  • way to many function nodes…this is a no-code-platform after all :wink:
  • using a flow variable for SOC is a good idea, as you will need to check SOC value in more than one occasion. However I don’t see the value in using a flow variable for grid-setpoint, as you simly want to set its value, not check it.
  • The above said… when I import your flow, I don’t see a node that actually sets the gid-setpoint in ESS (and no node that sets DVCC value).
  • your time-slots overlap at 13:00 … you cannot set the system to charge and discharge at the same time.

Here is an alternate version, without any function node - you still need to connect nodes to set grid-setpoint and DVCC, though.
This flow makes use of the contrib-simple-gate node to control on/off events…install it via the palette.

flows.json.zip (1,6 KB)

1 Like

Not exactly, it is a visual coding platform. You are not going to make particularly efficient nor complex flows without function nodes helping with the logic.

Well, right. However, I’ve managed to avoid function nodes - especilly when you have to change a flow at a later time, “the way it works” is much easier to concive (again) with fewer function nodes.

Maybe my very potent NAS, where I deploy all my nodes to, compensates for the inefficiency of my flows :wink:

For a newbie, who is not a js literate, I’d actually recommend to not copy function nodes from the various internet ressources but rather work with standard and contrib nodes to start.

Hi thanks for that the function node is so that it doesn’t keep sending the signal to the grid as I’ve got notifications on the them so didn’t want them pinging all the time and the other parts of the flow was if it gets triggered after 1400 that it would start the next day I’ve been battling with chatGPT telling it it’s now working change XYZ but still can’t do it been annoying me for over a week now just trying to get it working :frowning:

…note that you can use a filter node to only let pass a message when payload has changed.

You can create time based events, like for scheduling alarms, by many means. There are contrib nodes, like cron and some others out there. My example with the inject nodes was just a simple start and my not be suitable for all needs.

1 Like

No thanks it’s increasing my understanding of this as I’m not a coder and have never coded so steep learning curve lol