Node-red-contrib-cron-plus and Save State

Hi,
I’m using the node-red-contrib-cron-plus node (version 2.1.0 with Node-RED 4.0.9) to start a flow every day at 16:00.
I also have another cron-plus node that stops the flow at 21:00 each evening.

However, if the computer is shut down for example, due to an unexpected power outage after 16:00 and then restarted, the flow doesn’t run until 16:00 the next day.
That means the event is essentially lost if the system was offline at the scheduled time.

I’ve enabled the Save State option and selected File: local file system, but how should I configure it? Is there an example flow available?

Is there a recommended way to detect or recover from missed schedule events?
Or is there a better alternative for ensuring the flow starts if it was missed during downtime?

Any advice, example flows, or best practices would be very much appreciated.
Thanks!

What do you mean by this? Do you have a msg looping forever until it is stopped at 21:00?

There are things you can do at startup like an inject set to trigger after 0.1s - you can use that to determined if the time is valid to "start your flow"

You don't need 2 cron plus nodes to get your result.

I would recommend, that you are sending your commands every 5 min and put a filter between cronplus and your device. Then it would start latest 5 min after reboot to send the commands.
check cron guidelines for periods.

I am using this method for my heating system and it works perfectly.

Thanks for your quick replies. Sorry if I was unclear. Maybe it’s easier if I show you a copy of my flow.

[
    {
        "id": "261f4e79e74055a7",
        "type": "tab",
        "label": "Test",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "de88c3da99ce4e3f",
        "type": "serial request",
        "z": "261f4e79e74055a7",
        "name": "",
        "serial": "ccaf0526df580fed",
        "x": 950,
        "y": 300,
        "wires": [
            [
                "a6e8f7f960057c36"
            ]
        ]
    },
    {
        "id": "c9f41354ae47aaaa",
        "type": "function",
        "z": "261f4e79e74055a7",
        "name": "Add <CR>",
        "func": "msg.payload += \"\\r\";\nreturn msg; ",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 690,
        "y": 300,
        "wires": [
            [
                "de88c3da99ce4e3f"
            ]
        ]
    },
    {
        "id": "f048436be7eef71b",
        "type": "comment",
        "z": "261f4e79e74055a7",
        "name": "Read RGB values every second between 16:00 and 21:00",
        "info": "",
        "x": 270,
        "y": 260,
        "wires": []
    },
    {
        "id": "108f253b3df8cc74",
        "type": "comment",
        "z": "261f4e79e74055a7",
        "name": "-- STOP --",
        "info": "",
        "x": 120,
        "y": 400,
        "wires": []
    },
    {
        "id": "a4afcc3cbdc3d75d",
        "type": "http request",
        "z": "261f4e79e74055a7",
        "name": "OLA Set DMX",
        "method": "POST",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://localhost:9090/set_dmx",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 760,
        "y": 480,
        "wires": [
            []
        ]
    },
    {
        "id": "a0550cc720fb0a52",
        "type": "function",
        "z": "261f4e79e74055a7",
        "name": "Blackout",
        "func": "var dmxValues = \"0,0,0\";\nmsg.payload = {\n    u: 1,\n    d: dmxValues\n};\nmsg.headers = {\n    'Content-Type': 'application/x-www-form-urlencoded'\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 600,
        "y": 480,
        "wires": [
            [
                "a4afcc3cbdc3d75d"
            ]
        ]
    },
    {
        "id": "812f46f53fe20e17",
        "type": "delay",
        "z": "261f4e79e74055a7",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 460,
        "y": 480,
        "wires": [
            [
                "a0550cc720fb0a52"
            ]
        ]
    },
    {
        "id": "08b1aba77d5e9c3b",
        "type": "function",
        "z": "261f4e79e74055a7",
        "name": "Read RGB value",
        "func": "var outputMsg = { payload: 'r' };\nreturn outputMsg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 510,
        "y": 300,
        "wires": [
            [
                "c9f41354ae47aaaa"
            ]
        ]
    },
    {
        "id": "9202fd7b14eb71ac",
        "type": "cronplus",
        "z": "261f4e79e74055a7",
        "name": "Set LED brightness to 0 % at 21:01",
        "outputField": "payload",
        "timeZone": "",
        "storeName": "file",
        "commandResponseMsgOutput": "output1",
        "defaultLocation": "",
        "defaultLocationType": "default",
        "outputs": 1,
        "options": [
            {
                "name": "time",
                "topic": "time",
                "payloadType": "date",
                "payload": "",
                "expressionType": "cron",
                "expression": "01 21 * * *",
                "location": "",
                "offset": "0",
                "solarType": "all",
                "solarEvents": "sunrise,sunset"
            }
        ],
        "x": 220,
        "y": 440,
        "wires": [
            [
                "812f46f53fe20e17",
                "807a9066f3cd8c1e",
                "e5477089ee32ee0b"
            ]
        ]
    },
    {
        "id": "807a9066f3cd8c1e",
        "type": "delay",
        "z": "261f4e79e74055a7",
        "name": "",
        "pauseType": "delay",
        "timeout": "15",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 460,
        "y": 520,
        "wires": [
            [
                "6a77d1bed4dd3e83"
            ]
        ]
    },
    {
        "id": "6a77d1bed4dd3e83",
        "type": "http request",
        "z": "261f4e79e74055a7",
        "name": "Shutdown OLA",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://localhost:9090/quit",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 620,
        "y": 520,
        "wires": [
            []
        ]
    },
    {
        "id": "b4f5289545d7e708",
        "type": "exec",
        "z": "261f4e79e74055a7",
        "command": "olad -f",
        "addpay": false,
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "",
        "x": 370,
        "y": 100,
        "wires": [
            [],
            [],
            []
        ]
    },
    {
        "id": "5f4d38ff0e23e31f",
        "type": "cronplus",
        "z": "261f4e79e74055a7",
        "name": "Every second between 16:00 and 21:00",
        "outputField": "payload",
        "timeZone": "",
        "storeName": "",
        "commandResponseMsgOutput": "output1",
        "defaultLocation": "",
        "defaultLocationType": "default",
        "outputs": 1,
        "options": [
            {
                "name": "evening_trigger",
                "topic": "evening_trigger",
                "payloadType": "date",
                "payload": "",
                "expressionType": "cron",
                "expression": "*/1 * 16-20 * * *",
                "location": "",
                "offset": "0",
                "solarType": "all",
                "solarEvents": "sunrise,sunset"
            }
        ],
        "x": 240,
        "y": 300,
        "wires": [
            [
                "08b1aba77d5e9c3b"
            ]
        ]
    },
    {
        "id": "5376f56dcefed806",
        "type": "comment",
        "z": "261f4e79e74055a7",
        "name": "-- START --",
        "info": "#",
        "x": 130,
        "y": 60,
        "wires": []
    },
    {
        "id": "e5477089ee32ee0b",
        "type": "function",
        "z": "261f4e79e74055a7",
        "name": "Set LED brightness to 0 %",
        "func": "var outputMsg = { payload: 'L,0' };\nreturn outputMsg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 520,
        "y": 440,
        "wires": [
            [
                "a3613f3f26cff17a"
            ]
        ]
    },
    {
        "id": "12ef3850e35f6f60",
        "type": "cronplus",
        "z": "261f4e79e74055a7",
        "name": "Start OLA at 15:59",
        "outputField": "payload",
        "timeZone": "",
        "storeName": "file",
        "commandResponseMsgOutput": "output1",
        "defaultLocation": "",
        "defaultLocationType": "default",
        "outputs": 1,
        "options": [
            {
                "name": "time",
                "topic": "time",
                "payloadType": "date",
                "payload": "",
                "expressionType": "cron",
                "expression": "59 15 * * *",
                "location": "",
                "offset": "0",
                "solarType": "all",
                "solarEvents": "sunrise,sunset"
            }
        ],
        "x": 170,
        "y": 100,
        "wires": [
            [
                "b4f5289545d7e708"
            ]
        ]
    },
    {
        "id": "378f4b62bf59ca39",
        "type": "function",
        "z": "261f4e79e74055a7",
        "name": "Set LED brightness to 90 %",
        "func": "var outputMsg = { payload: 'L,90' };\nreturn outputMsg;\n",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 520,
        "y": 160,
        "wires": [
            [
                "86f70d3c9b34b51e"
            ]
        ]
    },
    {
        "id": "70475b19b0357ca3",
        "type": "cronplus",
        "z": "261f4e79e74055a7",
        "name": "Set LED brightness to 90 % at 16:00",
        "outputField": "payload",
        "timeZone": "",
        "storeName": "file",
        "commandResponseMsgOutput": "output1",
        "defaultLocation": "",
        "defaultLocationType": "default",
        "outputs": 1,
        "options": [
            {
                "name": "time",
                "topic": "time",
                "payloadType": "date",
                "payload": "",
                "expressionType": "cron",
                "expression": "00 16 * * *",
                "location": "",
                "offset": "0",
                "solarType": "all",
                "solarEvents": "sunrise,sunset"
            }
        ],
        "x": 230,
        "y": 160,
        "wires": [
            [
                "378f4b62bf59ca39"
            ]
        ]
    },
    {
        "id": "a3613f3f26cff17a",
        "type": "function",
        "z": "261f4e79e74055a7",
        "name": "Add <CR>",
        "func": "msg.payload += \"\\r\";\nreturn msg; ",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 730,
        "y": 440,
        "wires": [
            [
                "de88c3da99ce4e3f"
            ]
        ]
    },
    {
        "id": "86f70d3c9b34b51e",
        "type": "function",
        "z": "261f4e79e74055a7",
        "name": "Add <CR>",
        "func": "msg.payload += \"\\r\";\nreturn msg; ",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 730,
        "y": 160,
        "wires": [
            [
                "de88c3da99ce4e3f"
            ]
        ]
    },
    {
        "id": "b0079f04f5550aed",
        "type": "http request",
        "z": "261f4e79e74055a7",
        "name": "OLA Set DMX",
        "method": "POST",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://localhost:9090/set_dmx",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 1440,
        "y": 300,
        "wires": [
            []
        ]
    },
    {
        "id": "6644018ab414267d",
        "type": "comment",
        "z": "261f4e79e74055a7",
        "name": "-- Send DMX values to OLA --",
        "info": "",
        "x": 1440,
        "y": 260,
        "wires": []
    },
    {
        "id": "a6e8f7f960057c36",
        "type": "function",
        "z": "261f4e79e74055a7",
        "name": "Send RGB values (scale to 0-255)",
        "func": "var message = msg.payload;\n\nif (message && typeof message === 'string') {\n    var values = message.split(',');\n\n    if (values.length >= 3) {\n        var red = values[0];\n        var green = values[1];\n        var blue = values[2].replace(\"*OK\", \"\").trim();\n\n        var redValue = parseInt(red);\n        var greenValue = parseInt(green);\n        var blueValue = parseInt(blue);\n\n        redValue = Math.min(redValue, 255);\n        greenValue = Math.min(greenValue, 255);\n        blueValue = Math.min(blueValue, 255);\n\n        var universe = 1; \n        msg.headers = {'Content-Type': 'application/x-www-form-urlencoded'};\n        msg.payload = \"u=\" + universe + \"&d=\" + redValue + \",\" + greenValue + \",\" + blueValue;\n    }\n}\n\nreturn msg;",
        "outputs": 1,
        "timeout": 0,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1200,
        "y": 300,
        "wires": [
            [
                "b0079f04f5550aed"
            ]
        ]
    },
    {
        "id": "ccaf0526df580fed",
        "type": "serial-port",
        "name": "EZO RGB Sensor",
        "serialport": "/dev/ttyUSB0",
        "serialbaud": "9600",
        "databits": "8",
        "parity": "none",
        "stopbits": "1",
        "waitfor": "",
        "dtr": "none",
        "rts": "none",
        "cts": "none",
        "dsr": "none",
        "newline": "\\n",
        "bin": "false",
        "out": "char",
        "addchar": "",
        "responsetimeout": "1"
    }
]

For simple on off then the node-red-node-timeswitch can do a simple on off once a day - and will send the value 0 or 1 either only on the transitions, or once per minute - which can then be followed by a filter (RBE) node so that it only sends once if restarted.

1 Like

Thanks! I will try Timeswitch and RBE filter.