Trigger a Flow Based Upon Date and Time matching System Date and Time

I have the following setup. It takes a date picker for the user interface and the time entry for the user interface in EST, taking into account DST. When entered it stores these two variables in global sources called triggerTime and triggerDate. It stores them in UTC 24 hour formatting. In my check date and time function I'm trying to compare the date and time entered against the system time and when they match trigger source11 to go through the flow. It is not matching or there is some other issue, maybe the system date is in a different format? I have the debug on all of my nodes. I get the date entry and the time entry and see that it is stored in the global sources correctly. I do not see any other debug info after the time entry.

If I unwire the Check Date and Time from Split Digits/Assign IR and wire in an eztimer node to Split Digits/Assign IR and choose a time in the future, the system will send source11 through the flow when that time is reached. eztimer doesn't take into account a date, just a time. It will not work for my situation as I need to check a date and a time. Everything after check date and time in my flow works to send source11 through...

For a date picked as 5/23/2024 and a time entered as 3:17 PM EST it stores triggerDate "05/23/2024" and triggerTime "19:17:00". In my eztimer node if I enter in 19:17:00, when that time is reached it will trigger source11 through the flow as mentioned above.

Any help would be appreciate...Thanks in adavance!

[
    {
        "id": "841a93d93256814b",
        "type": "globalcache-out",
        "z": "bfa8244b190d540b",
        "name": "Source11",
        "controller": "e0bfc5286dd39809",
        "unit_number": "1",
        "output": "1",
        "gccommand": "sendir",
        "x": 1820,
        "y": 2640,
        "wires": []
    },
    {
        "id": "de0fc19df0d25941",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Send IR to GC",
        "func": "// Retrieve matchedCommands array from global context\nvar matchedCommands11 = global.get('matchedCommands11');\n\n// Check if matchedCommands is defined and is an array\nif (Array.isArray(matchedCommands11)) {\n    // Iterate over each IR command in the matchedCommands array\n    matchedCommands11.forEach(function(irCommand) {\n        // Construct a message object with the IR command as the payload\n        var msgToSend = {\n            payload: irCommand\n        };\n        \n        // Send the message to the Global Cache device\n        // Make sure to replace 'globalCacheNode' with the actual name of your Global Cache node\n        node.send(msgToSend);\n    });\n} else {\n    // Handle the case when matchedCommands is empty or not an array\n    node.error(\"No matched IR commands found in the global context.\");\n}\n\n// Don't forget to return the message\nreturn null;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1580,
        "y": 2640,
        "wires": [
            [
                "841a93d93256814b"
            ]
        ]
    },
    {
        "id": "7db0eef0a925f692",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Split digits/Assign IR",
        "func": "// Define IR commands array\nvar irCommands = [\n    // ir command 0\n    \"1,58000,1,37,23,351,23,164,23,94,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,94,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    // ir command 1\n    \"1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    //ir command 2\n    \"1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    //ir command 3\n    \"1,58000,1,37,23,351,23,164,23,164,23,164,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,164,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    //ir command 4\n    \"1,58000,1,37,23,351,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    //ir command 5\n    \"1,58000,1,37,23,351,23,164,23,164,23,94,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,164,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    //ir command 6\n    \"1,58000,1,37,23,351,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    //ir command 7\n    \"1,58000,1,37,23,351,23,164,23,164,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    //ir command 8\n    \"1,58000,1,37,23,351,23,164,23,164,23,94,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,94,23,164,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\",\n    //ir command 9\n    \"1,58000,1,37,23,351,23,164,23,164,23,94,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351,23,164,23,164,23,94,23,94,23,94,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,164,23,351\"\n    // Add more commands as needed\n];\n\n// Get the value of source11 from the message payload\nvar source11 = msg.payload;\n\n// Check if source11 is a number\nif (typeof source11 === 'number') {\n    // Convert source11 to a string to handle multi-digit numbers\n    var source11String = source11.toString();\n\n    // Convert source2String to an array of digits\n    var numberArray = source11String.split('').map(Number);\n\n    // Initialize an array to store matched IR commands\n    var matchedCommands11 = [];\n\n    // Iterate over each digit in the number array\n    numberArray.forEach(function(digit) {\n        // Ensure the digit is within the range 0-9\n        if (digit >= 0 && digit <= 9) {\n            // Get the corresponding IR command for the digit\n            var command = irCommands[digit];\n            // Push the command to the array of matched commands\n            matchedCommands11.push(command);\n        } else {\n            node.warn(\"Invalid digit: \" + digit);\n        }\n    });\n\n    // Store the array of matched commands in the global context\n    global.set(\"matchedCommands11\", matchedCommands11);\n} else {\n    // Handle the case when source11 is not a number\n    node.error(\"Default channel must be a number.\");\n}\n\n// Return the message\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1320,
        "y": 2640,
        "wires": [
            [
                "de0fc19df0d25941"
            ]
        ]
    },
    {
        "id": "da010df42e283fb9",
        "type": "ui_text_input",
        "z": "bfa8244b190d540b",
        "name": "Set Trigger Time",
        "label": "Enter Time (hh:mm AM/PM):",
        "tooltip": "Time needs to be in non-24-hour format (e.g., 4:00 PM)",
        "group": "1f50c834885d8903",
        "order": 3,
        "width": 3,
        "height": 1,
        "passthru": true,
        "mode": "text",
        "delay": 300,
        "topic": "",
        "topicType": "str",
        "x": 160,
        "y": 2580,
        "wires": [
            [
                "b833486452a31031",
                "ebd015427b917d12"
            ]
        ]
    },
    {
        "id": "ebd015427b917d12",
        "type": "debug",
        "z": "bfa8244b190d540b",
        "name": "Debug",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 810,
        "y": 2500,
        "wires": []
    },
    {
        "id": "9f5678f9c6a6e760",
        "type": "ui_date_picker",
        "z": "bfa8244b190d540b",
        "name": "Set Trigger Date",
        "label": "Select Date (mm/dd/yyyy)",
        "group": "1f50c834885d8903",
        "order": 2,
        "width": 5,
        "height": 1,
        "passthru": true,
        "topic": "",
        "topicType": "str",
        "x": 160,
        "y": 2640,
        "wires": [
            [
                "f2da2682d19a231b",
                "ebd015427b917d12"
            ]
        ]
    },
    {
        "id": "f2da2682d19a231b",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Date Picker to Object",
        "func": "// Check if the payload is a valid date string or a timestamp\nvar dateStr = msg.payload.toString(); // Ensure the payload is treated as a string\nnode.log('Received payload: ' + dateStr);\n\n// Check if the payload is a valid timestamp (numeric value)\nvar timestamp = parseInt(dateStr, 10);\nif (!isNaN(timestamp)) {\n    // Convert timestamp to Date object\n    var date = new Date(timestamp);\n\n    // Check if the created Date object is valid\n    if (isNaN(date.getTime())) {\n        node.error('Invalid timestamp: ' + dateStr);\n        return null; // Return null to end the function execution\n    }\n\n    // Set the payload to the Date object\n    msg.payload = date;\n\n    // Pass the message to the next node in the flow\n    return msg;\n}\n\n// Parse the date string using a regular expression\nvar match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\nif (!match) {\n    node.error('Invalid date format: ' + dateStr);\n    return null; // Return null to end the function execution\n}\n\n// Extract day, month, and year from the matched groups\nvar day = parseInt(match[2], 10);\nvar month = parseInt(match[1], 10) - 1; // Month is 0-based in JavaScript Date object\nvar year = parseInt(match[3], 10);\n\n// Create a new Date object\nvar date = new Date(year, month, day);\n\n// Check if the created Date object is valid\nif (isNaN(date.getTime())) {\n    node.error('Invalid date: ' + dateStr);\n    return null; // Return null to end the function execution\n}\n\n// Set the payload to the Date object\nmsg.payload = date;\n\n// Pass the message to the next node in the flow\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 440,
        "y": 2640,
        "wires": [
            [
                "c19b210ff990938e",
                "ebd015427b917d12"
            ]
        ]
    },
    {
        "id": "c19b210ff990938e",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Set Global Trigger Date",
        "func": "// Set Global Trigger Date function\nif (!(msg.payload instanceof Date)) {\n    node.error('Payload is not a Date object');\n    return null;\n}\n\nvar date = msg.payload;\n\n// Adjust the date to the local timezone\nvar localDate = new Date(date.toLocaleString('en-US', {timeZone: 'America/New_York'}));\nnode.log('Local date: ' + localDate);\n\n// Extract date components from the adjusted date\nvar localDay = localDate.getDate();\nvar localMonth = localDate.getMonth() + 1; // Month index starts from 0, so add 1\nvar localYear = localDate.getFullYear();\n\n// Rearrange to mm/dd/yyyy format\nvar triggerDate = localMonth + '/' + localDay + '/' + localYear;\nnode.log('Trigger date set to: ' + triggerDate);\n\n// Store the date in the global context variable 'triggerDate'\nglobal.set('triggerDate', triggerDate);\n\n// Return null to end function execution without emitting any message\nreturn null;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 730,
        "y": 2640,
        "wires": [
            [
                "352983aa107ccbfb",
                "ebd015427b917d12"
            ]
        ]
    },
    {
        "id": "b833486452a31031",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Set Global Trigger Time",
        "func": "// Set Global Trigger Time function\nvar timeInput = msg.payload.trim(); // Trim any leading/trailing whitespace\nnode.log('Received time input: ' + timeInput);\n\n// Parse the time input to extract hours, minutes, and AM/PM designation\nvar match = timeInput.match(/^(1[0-2]|0?[1-9]):([0-5][0-9])\\s?(AM|PM)$/i);\nif (!match) {\n    node.error('Invalid time format: ' + timeInput);\n    return null;\n}\n\nvar hours = parseInt(match[1], 10);\nvar minutes = parseInt(match[2], 10);\nvar period = match[3].toUpperCase();\nnode.log('Parsed time: ' + hours + ':' + minutes + ' ' + period);\n\n// Adjust hours for PM times\nif (period === 'PM' && hours < 12) {\n    hours += 12;\n} else if (period === 'AM' && hours === 12) {\n    hours = 0; // Midnight edge case\n}\n\n// Create a new Date object for the input time in EST\nvar inputDate = new Date();\ninputDate.setHours(hours, minutes, 0);\nnode.log('Input date object: ' + inputDate);\n\n// Determine if the current date is within DST\nvar jan = new Date(inputDate.getFullYear(), 0, 1);\nvar jul = new Date(inputDate.getFullYear(), 6, 1);\nvar isDST = Math.min(jan.getTimezoneOffset(), jul.getTimezoneOffset()) === inputDate.getTimezoneOffset();\nnode.log('Daylight saving time: ' + (isDST ? 'yes' : 'no'));\n\n// Get the UTC offset including DST\nvar utcOffset = isDST ? 4 : 5; // EDT (UTC-4) during DST, EST (UTC-5) otherwise\nnode.log('UTC offset: ' + utcOffset);\n\n// Adjust for the timezone difference\ninputDate.setHours(inputDate.getHours() + utcOffset);\n\n// Format UTC time (24-hour format)\nvar utcHours = ('0' + inputDate.getUTCHours()).slice(-2);\nvar utcMinutes = ('0' + inputDate.getUTCMinutes()).slice(-2);\nvar utcTime = utcHours + ':' + utcMinutes + ':00';\nnode.log('UTC time: ' + utcTime);\n\n// Store the UTC time in the global context variable 'triggerTime'\nglobal.set(\"triggerTime\", utcTime);\n\n// Store the date in the desired format (mm/dd/yyyy) in the global context variable 'triggerDate'\nvar month = ('0' + (inputDate.getMonth() + 1)).slice(-2); // Month is 0-based, so add 1\nvar day = ('0' + inputDate.getDate()).slice(-2);\nvar year = inputDate.getFullYear();\nvar triggerDate = month + '/' + day + '/' + year;\nglobal.set(\"triggerDate\", triggerDate);\n\n// Return null to end function execution without emitting any message\nreturn null;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 450,
        "y": 2580,
        "wires": [
            [
                "ebd015427b917d12"
            ]
        ]
    },
    {
        "id": "352983aa107ccbfb",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Check Date and Time",
        "func": "// Check Date and Time function\nvar triggerTime = global.get('triggerTime'); // Get triggerTime from global context\nvar triggerDate = global.get('triggerDate'); // Get triggerDate from global context\n\nif (!triggerTime || !triggerDate) {\n    node.warn('Global triggerTime or triggerDate not set.');\n    return null;\n}\n\n// Format the current date and time in UTC\nvar now = new Date();\nvar utcNow = now.getUTCHours() + ':' + ('0' + now.getUTCMinutes()).slice(-2) + ':00';\n\nnode.log('Current UTC time: ' + utcNow);\nnode.log('Trigger time: ' + triggerTime);\n\n// Compare current UTC time with triggerTime\nif (utcNow === triggerTime) {\n    node.log('Time match found. Triggering source11.');\n    msg.payload = 'source11'; // Replace with your actual payload or trigger mechanism\n    return msg;\n} else {\n    node.log('Time match not found.');\n    return null;\n}\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1040,
        "y": 2640,
        "wires": [
            [
                "ebd015427b917d12",
                "7db0eef0a925f692"
            ]
        ]
    },
    {
        "id": "e0bfc5286dd39809",
        "type": "globalcache-controller",
        "name": "Test.GC.MFT",
        "host": "172.16.11.228",
        "port": "4998",
        "mode": "request-disconnect"
    },
    {
        "id": "1f50c834885d8903",
        "type": "ui_group",
        "name": "Jason",
        "tab": "0ceb20451ccb4b40",
        "order": 1,
        "disp": true,
        "width": 8,
        "collapse": false
    },
    {
        "id": "0ceb20451ccb4b40",
        "type": "ui_tab",
        "name": "Jason Test",
        "icon": "dashboard",
        "order": 6,
        "disabled": false,
        "hidden": false
    }
]

You might want to adjust your approach.

Node-red-contrib-cron-plus can be programmatically set and it will just happen. No compares or timezones to worry about.

Flow:
UI node > change node(to set parameters) > Cron node > flow to execute.

If you wish to go down this route, check out the built in examples (ctrl-i > examples >
node-red-contrib-cron-plus)

1 Like

Thanks for your help! I've been trying off and on today to work with CronPlus without much luck. I have the following code. I'm trying to setup a flow allowing a user to take a predetermined source or default channel I've called source11 here, set a date (triggerDate) and a time (triggerTime), stored as a global sources, to send source11 through the flow once the system reaches the triggerDate and triggerTime; therefore, defaulting the device back to it's default channel. Right now when I open my date picker and chose a date, say today 5/24/2024, it changes the date to 5/25/2024. The time seems to be okay...thinking I might still be over thinking this; however, I don't want to send Source11 through every minute or something, just when the entered date and time have been reached. If it sends it through and the dates/times are not updated, then nothing else should happen until the dates/times are in the future again.

[
    {
        "id": "dee88c7031dd55b1",
        "type": "ui_text_input",
        "z": "bfa8244b190d540b",
        "name": "Set Trigger Time",
        "label": "Enter Time (hh:mm AM/PM):",
        "tooltip": "Time needs to be in non-24-hour format (e.g., 4:00 PM)",
        "group": "1f50c834885d8903",
        "order": 3,
        "width": 3,
        "height": 1,
        "passthru": true,
        "mode": "text",
        "delay": 300,
        "topic": "",
        "topicType": "str",
        "x": 100,
        "y": 2520,
        "wires": [
            [
                "7703ea6c4dc12194",
                "ebb5afcb59638585"
            ]
        ]
    },
    {
        "id": "bfc48767bb252baf",
        "type": "ui_date_picker",
        "z": "bfa8244b190d540b",
        "name": "Set Trigger Date",
        "label": "Select Date (mm/dd/yyyy)",
        "group": "1f50c834885d8903",
        "order": 2,
        "width": 5,
        "height": 1,
        "passthru": true,
        "topic": "",
        "topicType": "str",
        "x": 100,
        "y": 2580,
        "wires": [
            [
                "2d887167a5a0b792",
                "ebb5afcb59638585"
            ]
        ]
    },
    {
        "id": "2d887167a5a0b792",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Date Picker to Object",
        "func": "var dateStr = msg.payload;\nif (typeof dateStr === 'number') {\n    var date = new Date(dateStr);\n    dateStr = ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + '/' + date.getFullYear();\n    msg.payload = dateStr;\n} else {\n    var match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\n    if (!match) {\n        node.error('Invalid date format: ' + dateStr);\n        return null;\n    }\n    var month = parseInt(match[1], 10) - 1;\n    var day = parseInt(match[2], 10);\n    var year = parseInt(match[3], 10);\n    var date = new Date(year, month, day);\n    dateStr = ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + '/' + date.getFullYear();\n    msg.payload = dateStr;\n}\nnode.warn('Date String: ' + msg.payload);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 320,
        "y": 2580,
        "wires": [
            [
                "6b2c0f793c972805",
                "ebb5afcb59638585"
            ]
        ]
    },
    {
        "id": "6b2c0f793c972805",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Set Global Trigger Date",
        "func": "var dateStr = msg.payload;\nvar match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\nif (!match) {\n    node.error('Invalid date format: ' + dateStr);\n    return null;\n}\nvar month = ('0' + match[1]).slice(-2);\nvar day = ('0' + match[2]).slice(-2);\nvar year = match[3];\nvar triggerDate = year + '-' + month + '-' + day;\nglobal.set('triggerDate', triggerDate);\nnode.warn('Trigger Date: ' + triggerDate);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 550,
        "y": 2580,
        "wires": [
            [
                "ebb5afcb59638585",
                "0c5b75be4d659033"
            ]
        ]
    },
    {
        "id": "7703ea6c4dc12194",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Set Global Trigger Time",
        "func": "var timeInput = msg.payload.trim();\nvar match = timeInput.match(/^(\\d{1,2}):(\\d{2})\\s?(AM|PM)$/i);\nif (!match) {\n    // Ignore partial or invalid inputs\n    return null;\n}\nvar hours = parseInt(match[1], 10);\nvar minutes = parseInt(match[2], 10);\nvar period = match[3].toUpperCase();\nif (period === 'PM' && hours < 12) {\n    hours += 12;\n} else if (period === 'AM' && hours === 12) {\n    hours = 0;\n}\n\nvar timeStr = ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) + ':00';\nglobal.set('triggerTime', timeStr);\nnode.warn('Trigger Time: ' + timeStr);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 330,
        "y": 2520,
        "wires": [
            [
                "ebb5afcb59638585",
                "0c5b75be4d659033"
            ]
        ]
    },
    {
        "id": "d507e86ca5868d54",
        "type": "cronplus",
        "z": "bfa8244b190d540b",
        "name": "Schedule Trigger",
        "outputField": "payload",
        "timeZone": "",
        "storeName": "",
        "commandResponseMsgOutput": "output1",
        "defaultLocation": "",
        "defaultLocationType": "default",
        "outputs": 1,
        "options": [
            {
                "name": "dynamic",
                "topic": "dynamic",
                "payloadType": "bool",
                "payload": "true",
                "expressionType": "cron",
                "expression": "* * * * *",
                "location": "",
                "offset": "0",
                "solarType": "all",
                "solarEvents": "sunrise,sunset"
            }
        ],
        "x": 1130,
        "y": 2580,
        "wires": [
            [
                "abdd1a6805037132",
                "ebb5afcb59638585"
            ]
        ]
    },
    {
        "id": "abdd1a6805037132",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Check Date and Time",
        "func": "var triggerTime = global.get('triggerTime');\nvar triggerDate = global.get('triggerDate');\nif (!triggerTime || !triggerDate) {\n    return null;\n}\nvar now = new Date();\nvar currentDate = now.getFullYear() + '-' + ('0' + (now.getMonth() + 1)).slice(-2) + '-' + ('0' + now.getDate()).slice(-2);\nvar currentTime = ('0' + now.getHours()).slice(-2) + ':' + ('0' + now.getMinutes()).slice(-2) + ':' + ('0' + now.getSeconds()).slice(-2);\n\nnode.warn('Current Date: ' + currentDate + ', Trigger Date: ' + triggerDate);\nnode.warn('Current Time: ' + currentTime + ', Trigger Time: ' + triggerTime);\n\nif (currentDate === triggerDate && currentTime === triggerTime) {\n    msg.payload = 'source11';\n    return msg;\n}\nreturn null;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1340,
        "y": 2580,
        "wires": [
            [
                "da9e15900206e03f",
                "ebb5afcb59638585"
            ]
        ]
    },
    {
        "id": "0c5b75be4d659033",
        "type": "function",
        "z": "bfa8244b190d540b",
        "name": "Update Cron Schedule",
        "func": "var triggerTime = global.get('triggerTime');\nvar triggerDate = global.get('triggerDate');\nif (!triggerTime || !triggerDate) {\n    node.error('Trigger time or date not set');\n    return null;\n}\nvar cronParts = triggerTime.split(':');\nvar cronExpression = cronParts[2] + ' ' + cronParts[1] + ' ' + cronParts[0] + ' ' + triggerDate.split('-')[2] + ' ' + triggerDate.split('-')[1] + ' *';\nmsg.payload = {\n    command: 'add',\n    name: 'dynamic',\n    expression: cronExpression,\n    type: 'cron',\n    payloadType: 'bool',\n    payload: true\n};\nnode.warn('Cron Expression: ' + cronExpression);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 880,
        "y": 2580,
        "wires": [
            [
                "d507e86ca5868d54",
                "ebb5afcb59638585"
            ]
        ]
    },
    {
        "id": "ebb5afcb59638585",
        "type": "debug",
        "z": "bfa8244b190d540b",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1380,
        "y": 2420,
        "wires": []
    },
    {
        "id": "da9e15900206e03f",
        "type": "debug",
        "z": "bfa8244b190d540b",
        "name": "Output Source 11",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "x": 1540,
        "y": 2580,
        "wires": []
    },
    {
        "id": "1f50c834885d8903",
        "type": "ui_group",
        "name": "Jason",
        "tab": "0ceb20451ccb4b40",
        "order": 1,
        "disp": true,
        "width": 9,
        "collapse": false
    },
    {
        "id": "0ceb20451ccb4b40",
        "type": "ui_tab",
        "name": "Jason Test",
        "icon": "dashboard",
        "order": 6,
        "disabled": false,
        "hidden": false
    }
]

Hi.

You need to put MORE debug nodes. Having all the messages in one is painful to read/understand.

Your Set Global Trigger Time node isn't doing much.

On the cron node, set the option to send statuses out of a separate output. Then the top output will ONLY send data when the cron schedule triggers.

Alternatively, put a switch node after Cron and ONLY allow the topic you set in the cron schedule.

No offense @JasonH but here is a rewrite of your flow.

[{"id":"6b2c0f793c972805","type":"function","z":"e2b152c436126baa","name":"Set Global Trigger Date","func":"var dateStr = msg.payload;\nvar match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\nif (!match) {\n    node.error('Invalid date format: ' + dateStr);\n    return null;\n}\nvar month = ('0' + match[1]).slice(-2);\nvar day = ('0' + match[2]).slice(-2);\nvar year = match[3];\nvar triggerDate = year + '-' + month + '-' + day;\nglobal.set('triggerDate', triggerDate);\nnode.warn('Trigger Date: ' + triggerDate);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":430,"wires":[["0c5b75be4d659033","3c7f474151e78bcf"]]},{"id":"2d887167a5a0b792","type":"function","z":"e2b152c436126baa","name":"Date Picker to Object","func":"var dateStr = msg.payload;\nif (typeof dateStr === 'number') {\n    var date = new Date(dateStr);\n    dateStr = ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + '/' + date.getFullYear();\n    msg.payload = dateStr;\n} else {\n    var match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\n    if (!match) {\n        node.error('Invalid date format: ' + dateStr);\n        return null;\n    }\n    var month = parseInt(match[1], 10) - 1;\n    var day = parseInt(match[2], 10);\n    var year = parseInt(match[3], 10);\n    var date = new Date(year, month, day);\n    dateStr = ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + '/' + date.getFullYear();\n    msg.payload = dateStr;\n}\nnode.warn('Date String: ' + msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":430,"wires":[["6b2c0f793c972805","76cc627c52fe03cd"]]},{"id":"0c5b75be4d659033","type":"function","z":"e2b152c436126baa","name":"Update Cron Schedule","func":"var triggerTime = global.get('triggerTime');\nvar triggerDate = global.get('triggerDate');\nif (!triggerTime || !triggerDate) {\n    node.error('Trigger time or date not set');\n    return null;\n}\nvar cronParts = triggerTime.split(':');\nvar cronExpression = cronParts[2] + ' ' + cronParts[1] + ' ' + cronParts[0] + ' ' + triggerDate.split('-')[2] + ' ' + triggerDate.split('-')[1] + ' *';\nmsg.payload = {\n    command: 'add',\n    name: 'dynamic',\n    expression: cronExpression,\n    type: 'cron',\n    payloadType: 'bool',\n    payload: true\n};\nnode.warn('Cron Expression: ' + cronExpression);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":910,"y":430,"wires":[["d507e86ca5868d54","b9f090680b9305d4"]]},{"id":"3c7f474151e78bcf","type":"debug","z":"e2b152c436126baa","name":"2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":770,"y":290,"wires":[]},{"id":"bfc48767bb252baf","type":"ui_date_picker","z":"e2b152c436126baa","name":"Set Trigger Date","label":"Select Date (mm/dd/yyyy)","group":"1f50c834885d8903","order":2,"width":5,"height":1,"passthru":true,"topic":"","topicType":"str","x":130,"y":430,"wires":[["2d887167a5a0b792"]]},{"id":"76cc627c52fe03cd","type":"debug","z":"e2b152c436126baa","name":"1b","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":550,"y":310,"wires":[]},{"id":"7703ea6c4dc12194","type":"function","z":"e2b152c436126baa","name":"Set Global Trigger Time","func":"var timeInput = msg.payload.trim();\nvar match = timeInput.match(/^(\\d{1,2}):(\\d{2})\\s?(AM|PM)$/i);\nif (!match) {\n    // Ignore partial or invalid inputs\n    return null;\n}\n\nnode.warn(\"Time now set\");\n\nvar hours = parseInt(match[1], 10);\nvar minutes = parseInt(match[2], 10);\nvar period = match[3].toUpperCase();\nif (period === 'PM' && hours < 12) {\n    hours += 12;\n} else if (period === 'AM' && hours === 12) {\n    hours = 0;\n}\n\nvar timeStr = ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) + ':00';\nglobal.set('triggerTime', timeStr);\nnode.warn('Trigger Time: ' + timeStr);\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":370,"wires":[["0c5b75be4d659033","ebb5afcb59638585"]]},{"id":"d507e86ca5868d54","type":"cronplus","z":"e2b152c436126baa","name":"Schedule Trigger","outputField":"payload","timeZone":"","storeName":"","commandResponseMsgOutput":"output1","defaultLocation":"","defaultLocationType":"default","outputs":1,"options":[{"name":"dynamic","topic":"dynamic","payloadType":"bool","payload":"true","expressionType":"cron","expression":"* * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":1160,"y":430,"wires":[["ab099d78ca544181"]]},{"id":"b9f090680b9305d4","type":"debug","z":"e2b152c436126baa","name":"3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1120,"y":300,"wires":[]},{"id":"dee88c7031dd55b1","type":"ui_text_input","z":"e2b152c436126baa","name":"Set Trigger Time","label":"Enter Time (hh:mm AM/PM):","tooltip":"Time needs to be in non-24-hour format (e.g., 4:00 PM)","group":"1f50c834885d8903","order":3,"width":3,"height":1,"passthru":true,"mode":"text","delay":300,"topic":"","topicType":"str","x":130,"y":370,"wires":[["7703ea6c4dc12194","3510031e58e4a7e6"]]},{"id":"ebb5afcb59638585","type":"debug","z":"e2b152c436126baa","name":"1a","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":550,"y":250,"wires":[]},{"id":"ab099d78ca544181","type":"debug","z":"e2b152c436126baa","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1350,"y":430,"wires":[]},{"id":"3510031e58e4a7e6","type":"debug","z":"e2b152c436126baa","name":"time","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":300,"y":310,"wires":[]},{"id":"1f50c834885d8903","type":"ui_group","name":"Jason","tab":"0ceb20451ccb4b40","order":1,"disp":true,"width":9,"collapse":false},{"id":"0ceb20451ccb4b40","type":"ui_tab","name":"Jason Test","icon":"dashboard","order":6,"disabled":false,"hidden":false}]

I got it working, but not sure how/why.

The afore mentioned node doesn't seem to return an output.

EDIT

SORRY.

I'm also not understanding the flow and how the messages work.

You input the date and time in the gui nodes.
Their values are passed into the their own function node that sets a GLOBAL context of the value.

Then you send that value (why?) to the next node/s.

For reasons unknown I did get it working - as said.
But there is NO GLOBAL for the time seen anywhere.

All I see is the GLOBAL for the date.

So SOMEHOW the time is slipping through and it did work.

I would (maybe) suggest using a join node rather than GLOBAL context.
When it receives two messages, it on sends the message with the time and date.
(Maybe)

You also had a function node after the cronplus node.
Not needed.
When cronplus sees a match it will output a true every..... repeatedly.

(OCD sucks)

Further looking at the flow and with more stuff added:

[{"id":"0c5b75be4d659033","type":"function","z":"e2b152c436126baa","name":"Update Cron Schedule","func":"var triggerTime = global.get('triggerTime');\nvar triggerDate = global.get('triggerDate');\nif (!triggerTime || !triggerDate) {\n    node.error('Trigger time or date not set');\n    return null;\n}\nvar cronParts = triggerTime.split(':');\nvar cronExpression = cronParts[2] + ' ' + cronParts[1] + ' ' + cronParts[0] + ' ' + triggerDate.split('-')[2] + ' ' + triggerDate.split('-')[1] + ' *';\nmsg.payload = {\n    command: 'add',\n    name: 'dynamic',\n    expression: cronExpression,\n    type: 'cron',\n    payloadType: 'bool',\n    payload: true\n};\nnode.warn('Cron Expression: ' + cronExpression);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":910,"y":430,"wires":[["d507e86ca5868d54","b9f090680b9305d4"]]},{"id":"6b2c0f793c972805","type":"function","z":"e2b152c436126baa","name":"Set Global Trigger Date","func":"var dateStr = msg.payload;\nvar match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\nif (!match) {\n    node.error('Invalid date format: ' + dateStr);\n    return null;\n}\nvar month = ('0' + match[1]).slice(-2);\nvar day = ('0' + match[2]).slice(-2);\nvar year = match[3];\nvar triggerDate = year + '-' + month + '-' + day;\nglobal.set('triggerDate', triggerDate);\nnode.warn('Trigger Date: ' + triggerDate);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":430,"wires":[["0c5b75be4d659033","3c7f474151e78bcf"]]},{"id":"7703ea6c4dc12194","type":"function","z":"e2b152c436126baa","name":"Set Global Trigger Time","func":"var timeInput = msg.payload.trim();\nvar match = timeInput.match(/^(\\d{1,2}):(\\d{2})\\s?(AM|PM)$/i);\nif (!match) {\n    // Ignore partial or invalid inputs\n    node.warn(\"Ignoring input for now\");\n    return null;\n}\n\nnode.warn(\"Time now set\");\n\nvar hours = parseInt(match[1], 10);\nvar minutes = parseInt(match[2], 10);\nvar period = match[3].toUpperCase();\nif (period === 'PM' && hours < 12) {\n    hours += 12;\n} else if (period === 'AM' && hours === 12) {\n    hours = 0;\n}\n\nvar timeStr = ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) + ':00';\nglobal.set('triggerTime', timeStr);\nnode.warn('Trigger Time: ' + timeStr);\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":370,"wires":[["0c5b75be4d659033","ebb5afcb59638585"]]},{"id":"d507e86ca5868d54","type":"cronplus","z":"e2b152c436126baa","name":"Schedule Trigger","outputField":"payload","timeZone":"","storeName":"","commandResponseMsgOutput":"output1","defaultLocation":"","defaultLocationType":"default","outputs":1,"options":[{"name":"dynamic","topic":"dynamic","payloadType":"bool","payload":"true","expressionType":"cron","expression":"* * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":1160,"y":430,"wires":[["ab099d78ca544181"]]},{"id":"b9f090680b9305d4","type":"debug","z":"e2b152c436126baa","name":"3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1120,"y":300,"wires":[]},{"id":"2d887167a5a0b792","type":"function","z":"e2b152c436126baa","name":"Date Picker to Object","func":"var dateStr = msg.payload;\nif (typeof dateStr === 'number') {\n    var date = new Date(dateStr);\n    dateStr = ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + '/' + date.getFullYear();\n    msg.payload = dateStr;\n} else {\n    var match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\n    if (!match) {\n        node.error('Invalid date format: ' + dateStr);\n        return null;\n    }\n    var month = parseInt(match[1], 10) - 1;\n    var day = parseInt(match[2], 10);\n    var year = parseInt(match[3], 10);\n    var date = new Date(year, month, day);\n    dateStr = ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + '/' + date.getFullYear();\n    msg.payload = dateStr;\n}\nnode.warn('Date String: ' + msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":430,"wires":[["6b2c0f793c972805","76cc627c52fe03cd"]]},{"id":"3c7f474151e78bcf","type":"debug","z":"e2b152c436126baa","name":"2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":770,"y":290,"wires":[]},{"id":"dee88c7031dd55b1","type":"ui_text_input","z":"e2b152c436126baa","name":"Set Trigger Time","label":"Enter Time (hh:mm AM/PM):","tooltip":"Time needs to be in non-24-hour format (e.g., 4:00 PM)","group":"1f50c834885d8903","order":3,"width":3,"height":1,"passthru":true,"mode":"text","delay":300,"topic":"","topicType":"str","x":130,"y":370,"wires":[["7703ea6c4dc12194","3510031e58e4a7e6"]]},{"id":"ebb5afcb59638585","type":"debug","z":"e2b152c436126baa","name":"1a","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":550,"y":250,"wires":[]},{"id":"5b5341fd82d48998","type":"inject","z":"e2b152c436126baa","name":"stop-all (needed while testing)","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"stop-all","payload":"{\"command\": \"stop-all\"}","payloadType":"json","x":890,"y":490,"wires":[["d507e86ca5868d54"]]},{"id":"ab099d78ca544181","type":"debug","z":"e2b152c436126baa","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1350,"y":430,"wires":[]},{"id":"bfc48767bb252baf","type":"ui_date_picker","z":"e2b152c436126baa","name":"Set Trigger Date","label":"Select Date (mm/dd/yyyy)","group":"1f50c834885d8903","order":2,"width":5,"height":1,"passthru":true,"topic":"","topicType":"str","x":130,"y":430,"wires":[["2d887167a5a0b792"]]},{"id":"76cc627c52fe03cd","type":"debug","z":"e2b152c436126baa","name":"1b","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":550,"y":310,"wires":[]},{"id":"3510031e58e4a7e6","type":"debug","z":"e2b152c436126baa","name":"time","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":300,"y":310,"wires":[]},{"id":"1f50c834885d8903","type":"ui_group","name":"Jason","tab":"0ceb20451ccb4b40","order":1,"disp":true,"width":9,"collapse":false},{"id":"0ceb20451ccb4b40","type":"ui_tab","name":"Jason Test","icon":"dashboard","order":6,"disabled":false,"hidden":false}]

This is ringing some bells.

I set the time for 7:53:00
and given the date is set as needed.

The code:

var timeInput = msg.payload.trim();
var match = timeInput.match(/^(\d{1,2}):(\d{2})\s?(AM|PM)$/i);
if (!match) {
    // Ignore partial or invalid inputs
    node.warn("Ignoring input for now");
    return null;
}

node.warn("Time now set");

var hours = parseInt(match[1], 10);
var minutes = parseInt(match[2], 10);
var period = match[3].toUpperCase();
if (period === 'PM' && hours < 12) {
    hours += 12;
} else if (period === 'AM' && hours === 12) {
    hours = 0;
}

var timeStr = ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) + ':00';
global.set('triggerTime', timeStr);
node.warn('Trigger Time: ' + timeStr);
return msg;

The match line seems to not be happy with what it is receiving.

This is what I have now. When my date picker opens I have to choose the day before to get it to use the date of today. So I have to pick 5/27/2024 to get it to use 5/28/2024. Your code did the same thing when I tried to run it. It will run the cronplus job, but then wants to run it every minute thereafter. It should run it once and then wait for the global source triggerDate and triggerTime to update to a new value in the future. Unsure how to get it to do this and why my date picker is a day ahead when choosing the date. Any advice and thanks for your help so far? My global context for a 5/27/2024 entry at a time of 4:16 PM EST/EDT |triggerDate|"2024-05-28 and |triggerTime|"16:14:00"|

[{"id":"25f563ed019bb9fc","type":"function","z":"bfa8244b190d540b","name":"Set Global Trigger Date","func":"var dateStr = msg.payload;\nvar match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\nif (!match) {\n    node.error('Invalid date format: ' + dateStr);\n    return null;\n}\nvar month = ('0' + match[1]).slice(-2);\nvar day = ('0' + match[2]).slice(-2);\nvar year = match[3];\nvar triggerDate = year + '-' + month + '-' + day;\nglobal.set('triggerDate', triggerDate);\nnode.warn('Trigger Date: ' + triggerDate);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":2180,"wires":[["b5e98c56b020f804","4207d9feae15b84e"]]},{"id":"ee02a5aeed964c38","type":"function","z":"bfa8244b190d540b","name":"Date Picker to Object","func":"var dateStr = msg.payload;\nif (typeof dateStr === 'number') {\n    var date = new Date(dateStr);\n    dateStr = ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + '/' + date.getFullYear();\n    msg.payload = dateStr;\n} else {\n    var match = dateStr.match(/^(\\d{1,2})\\/(\\d{1,2})\\/(\\d{4})$/);\n    if (!match) {\n        node.error('Invalid date format: ' + dateStr);\n        return null;\n    }\n    var month = parseInt(match[1], 10) - 1;\n    var day = parseInt(match[2], 10);\n    var year = parseInt(match[3], 10);\n    var date = new Date(year, month, day);\n    dateStr = ('0' + (date.getMonth() + 1)).slice(-2) + '/' + ('0' + date.getDate()).slice(-2) + '/' + date.getFullYear();\n    msg.payload = dateStr;\n}\nnode.warn('Date String: ' + msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":2180,"wires":[["25f563ed019bb9fc","c9e535fc24432233"]]},{"id":"b5e98c56b020f804","type":"function","z":"bfa8244b190d540b","name":"Update Cron Schedule","func":"var triggerTime = global.get('triggerTime');\nvar triggerDate = global.get('triggerDate');\nif (!triggerTime || !triggerDate) {\n    node.error('Trigger time or date not set');\n    return null;\n}\n\n// Remove existing cron job\nvar removeMsg = { payload: { command: 'remove', name: 'dynamic' } };\nnode.send([removeMsg, null]);\n\n// Convert triggerDate and triggerTime to UTC\nvar dateParts = triggerDate.split('-');\nvar timeParts = triggerTime.split(':');\n\n// Create a new Date object in local timezone\nvar localDate = new Date(`${dateParts[0]}-${dateParts[1]}-${dateParts[2]}T${timeParts[0]}:${timeParts[1]}:${timeParts[2]}`);\n\n// Get the UTC time from the local time\nvar utcYear = localDate.getUTCFullYear();\nvar utcMonth = localDate.getUTCMonth() + 1; // Months are zero-indexed\nvar utcDay = localDate.getUTCDate();\nvar utcHour = localDate.getUTCHours();\nvar utcMinute = localDate.getUTCMinutes();\nvar utcSecond = localDate.getUTCSeconds();\n\n// Create cron expression based on UTC time\nvar utcCronExpression = `${utcSecond} ${utcMinute} ${utcHour} ${utcDay} ${utcMonth} *`;\n\n// Add new cron job\nmsg.payload = {\n    command: 'add',\n    name: 'dynamic',\n    expression: utcCronExpression,\n    type: 'cron',\n    payloadType: 'bool',\n    payload: true,\n    limit: 1 // Ensure it fires only once\n};\nnode.warn('Cron Expression: ' + utcCronExpression);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":2180,"wires":[["50a4e626850e3d69","5be8e01188dafd4c"]]},{"id":"4207d9feae15b84e","type":"debug","z":"bfa8244b190d540b","name":"2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":810,"y":2080,"wires":[]},{"id":"dfe440bca3d9b171","type":"ui_date_picker","z":"bfa8244b190d540b","name":"Set Trigger Date","label":"Select Date","group":"1f50c834885d8903","order":2,"width":6,"height":1,"passthru":true,"topic":"","topicType":"str","x":160,"y":2180,"wires":[["ee02a5aeed964c38"]]},{"id":"c9e535fc24432233","type":"debug","z":"bfa8244b190d540b","name":"1b","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":580,"y":2060,"wires":[]},{"id":"5ca632538f77a049","type":"function","z":"bfa8244b190d540b","name":"Set Global Trigger Time","func":"var timeInput = msg.payload.trim();\nvar match = timeInput.match(/^(\\d{1,2}):(\\d{2})\\s?(AM|PM)$/i);\nif (!match) {\n    // Ignore partial or invalid inputs\n    return null;\n}\n\nnode.warn(\"Time now set\");\n\nvar hours = parseInt(match[1], 10);\nvar minutes = parseInt(match[2], 10);\nvar period = match[3].toUpperCase();\nif (period === 'PM' && hours < 12) {\n    hours += 12;\n} else if (period === 'AM' && hours === 12) {\n    hours = 0;\n}\n\nvar timeStr = ('0' + hours).slice(-2) + ':' + ('0' + minutes).slice(-2) + ':00';\nglobal.set('triggerTime', timeStr);\nnode.warn('Trigger Time: ' + timeStr);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":2120,"wires":[["b5e98c56b020f804","a84edd966e05365b"]]},{"id":"50a4e626850e3d69","type":"cronplus","z":"bfa8244b190d540b","name":"Schedule Trigger","outputField":"payload","timeZone":"","storeName":"","commandResponseMsgOutput":"output1","defaultLocation":"","defaultLocationType":"default","outputs":1,"options":[{"name":"dynamic","topic":"dynamic","payloadType":"bool","payload":"true","expressionType":"cron","expression":"* * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":1110,"y":2180,"wires":[["465bbe507f4d0843"]]},{"id":"5be8e01188dafd4c","type":"debug","z":"bfa8244b190d540b","name":"3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1090,"y":2080,"wires":[]},{"id":"42634a7f74217050","type":"ui_text_input","z":"bfa8244b190d540b","name":"Set Trigger Time","label":"Enter Time (hh:mm AM/PM):","tooltip":"Time needs to be in non-24-hour format (e.g., 4:00 PM)","group":"1f50c834885d8903","order":4,"width":6,"height":1,"passthru":true,"mode":"text","delay":300,"topic":"","topicType":"str","x":160,"y":2120,"wires":[["5ca632538f77a049","04c8d45c6c30bf49"]]},{"id":"a84edd966e05365b","type":"debug","z":"bfa8244b190d540b","name":"1a","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":580,"y":2000,"wires":[]},{"id":"465bbe507f4d0843","type":"debug","z":"bfa8244b190d540b","name":"Output","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1390,"y":2080,"wires":[]},{"id":"04c8d45c6c30bf49","type":"debug","z":"bfa8244b190d540b","name":"time","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":330,"y":2060,"wires":[]},{"id":"1f50c834885d8903","type":"ui_group","name":"Jason","tab":"0ceb20451ccb4b40","order":1,"disp":false,"width":"8","collapse":false},{"id":"0ceb20451ccb4b40","type":"ui_tab","name":"Jason Test","icon":"dashboard","order":6,"disabled":false,"hidden":false}]

you can use the start-all stop-all input commands to run cron plus on demand.
there are extensive examples in the cron-plus

[{"id":"65892a57.612d44","type":"cronplus","z":"ad26319aa43f2957","name":"","outputField":"payload","timeZone":"","persistDynamic":false,"storeName":"","commandResponseMsgOutput":"output2","outputs":2,"options":[{"name":"e15","topic":"Every 15","payloadType":"default","payload":"","expressionType":"cron","expression":"0 15,30,45 * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"},{"name":"noon","topic":"noon","payloadType":"default","payload":"","expressionType":"cron","expression":"0 0 12 * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":660,"y":1530,"wires":[["8a452815.9ceb68"],["e60daf12.48c83"]]},{"id":"8a452815.9ceb68","type":"debug","z":"ad26319aa43f2957","name":"Sched Trigger","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":940,"y":1505,"wires":[]},{"id":"e60daf12.48c83","type":"debug","z":"ad26319aa43f2957","name":"Control Reply","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":940,"y":1555,"wires":[]},{"id":"b247f14a.cf2f","type":"inject","z":"ad26319aa43f2957","name":"start-all","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"start-all","payload":"","payloadType":"date","x":410,"y":1580,"wires":[["65892a57.612d44"]]},{"id":"6ea9b27a.04bf6c","type":"inject","z":"ad26319aa43f2957","name":"stop-all","repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"stop-all","payload":"{\"command\": \"stop-all\"}","payloadType":"json","x":400,"y":1480,"wires":[["65892a57.612d44"]]}]

The dashboard nodes don't seem to be set/configured correctly.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.