Cron+ node - formatting inputs

I've added a new function to my dashboard, where I can schedule start/stop sessions for my EV charger. So far, I have the time selectors and set/cancel buttons which all seem to work OK.
The resulting messages into node-RED from the front-end takes the format of;

To set the start and end time;

{
  "topic": "chargerSchedule",
  "payload": {
    "start": 1,
    "end": 24
  },
}

...and to clear the schedule

{
  "topic": "chargerSchedule",
  "payload": { "cancel": true }
}

Could I gather ideas what the best approach would be to manipulate those messages into a format that I could use to inject a dynamic schedule/clear schedule into Cron+

chargecontrol

There is built in demo for making dynamic schedules. Use the "dates" type to set fixed date schedules.

Same for the command "remove"

I posted my EV scheduling flows in the other thread too.

Yeah, I’m using uibuilder and not DB2, and also wanted something less complex, because it’s for use on a phone.

Yes, I’m familiar with that, but dates requires an actual formatted timestamp, and my interface is just producing the hour to switch on or off (a number between 1 and 24).
So I somehow need to turn both start & end numbers into future timestamps, and that's where I'm stuck :woozy_face:
I guess that I should have explored this issue before spending a whole day writing the front end, but I am where I am…

The scheduling doesn't change. Just steal the bits I did in that flow?!?!

You can add hours to a date epoch adding x*1000*60*60 to Date.now() (epochs are accepted in the add schedule code)

I'm not at a computer to provide code but this is very likely one that chatgpt can help with. Ooooo chatgpt can write this on my phone too. Let's see....

It said

// Get the current date and time
const now = new Date();

// Extract the start and end hours from the incoming message payload
const startHour = msg.payload.start;
const endHour = msg.payload.end;

// Create the start date
const startDate = new Date(now);
startDate.setHours(startHour, 0, 0, 0); // Set hour, minute, second, and millisecond

// Check if the start date is in the past, if so, move it to the next day
if (startDate.getTime() < now.getTime()) {
    startDate.setDate(startDate.getDate() + 1);
}

// Create the end date
const endDate = new Date(now);
endDate.setHours(endHour, 0, 0, 0);

// Check if the end date is in the past, if so, move it to the next day
if (endDate.getTime() < now.getTime()) {
    endDate.setDate(endDate.getDate() + 1);
}

// Ensure the end date is after the start date, handling cases that cross midnight
if (endDate.getTime() < startDate.getTime()) {
    endDate.setDate(endDate.getDate() + 1);
}

I haven't read it nor tested it. :crossed_fingers:

1 Like

And it looks gorgeous for it Paul! :smiley:

1 Like

I finally ended up with this, which interacts directly with cron-plus, setting and removing dynamic schedules.

Thanks for the suggestions.

// Input examples:
// { topic: "chargerSchedule", payload: { start: 15, end: 20 } }
// { topic: "chargerSchedule", payload: { cancel: true } }

if (msg.topic !== "chargerSchedule") {
    // Ignore all other messages
    return null;
}

const input = msg.payload || {};

// Handle cancel → exactly {"topic":"remove-all-dynamic"}
if (input.cancel) {
    return { topic: "remove-all-dynamic" };
}

// Validate
const startHour = Number(input.start);
const endHour   = Number(input.end);

if (!Number.isInteger(startHour) || startHour < 0 || startHour > 23) {
    node.error("payload.start must be an integer 0–23", msg);
    return null;
}
if (!Number.isInteger(endHour) || endHour < 0 || endHour > 23) {
    node.error("payload.end must be an integer 0–23", msg);
    return null;
}

const now = new Date();

// Compute start: next occurrence of startHour (today or tomorrow)
let start = new Date(now);
start.setHours(startHour, 0, 0, 0);
if (start <= now) start.setDate(start.getDate() + 1);

// Compute end relative to start; handle 24 == midnight next day
let end = new Date(start);
if (endHour === 24) {
    end.setDate(end.getDate() + 1);
    end.setHours(0, 0, 0, 0);
} else {
    end.setHours(endHour, 0, 0, 0);
    if (end <= start) end.setDate(end.getDate() + 1);
}

// Build cron-plus dynamic schedules (absolute ISO times)
const schedules = [
    {
        command: "add",
        name: "schedule start",
        expression: start.toISOString(),
        payload: "Start",
        type: "date",
        limit: 1
    },
    {
        command: "add",
        name: "schedule finish",
        expression: end.toISOString(),
        payload: "Stop",
        type: "date",
        limit: 1
    }
];

// For a single-output Function node, return a "message sequence":
// 1) remove-all-dynamic, 2) add new schedules
return [[
    { topic: "remove-all-dynamic" },
    { payload: schedules }
]];
1 Like