Cronplus node help

Sorry, I'm stuck.

I want an event every second week on Saturday.

Saying it starts this Saturday (8 June) what do I need to do?

I will be trying ITMT, but as Sod's law says: If I don't ask I won't (in the mean time) work it out.

(As said)

I have NEARLY got it.

0 0 7 * * 6

But that gives me every Saturday.
Not every alternate one.
(Starting with this coming one)

Oh something else!

(Sorry.)

It has to survive a reboot.
If it rebooted (powered down and left off for an unknown time) when it restarts it has to keep the same pattern.

Not just pick either Saturday (the closest one) and then do it every alternate week.
If the coming Sat' was a skip then it knows that and skips the Sat'.
If the coming Sat' was an action one, then it knows and sends the message on Sat'.

So Andrew - confirming that you do not want a set saturday (such as the 2nd saturday of every month and then the 4th saturday) but rather if i set the job today - it would run - This Saturday and then every two weeks on a saturday ?

I am pretty sure CRON (which CronPlus is based on) - does not support this natively - what you will need to do is run a script, and at the end of the script delete the current job and add another one for 14 days in the future.

So you would submit the job (say today) to run this saturday - and then every two weeks (in case the machine was off this saturday

In the script it would do the various functions you require and at the end of the script it would

  1. Update the next instance to run to be in two weeks time

as there is no way to Update a cron entry - your best bet would be to delete the job from the script and then resubmit it to run in two weeks time

This approach will not cater for the need to run the script if it is missed (i.e. the machine is turned off on a saturday when it is meant to run) and you still want to run it when the machine is next started - that becomes more difficult and requires additional files to enable a check of when it was last run etc (all of this could be translated into Node Red function nodes if required) but adds more complexity

Craig

Thanks.

Yeah, I'm looking at a lot of stuff on the net and they do tricks where they do a mod(2) on the week number and (depending on which week it is) passes if a 0 or 1.

I guess I could cheat and send the output weekly into a function node that looks at the week value and depending on the value of the mod(2) would either pass or skip sending the message.

I am still easily confused with this black magic sometimes.

I'll give that a go for now and see what happens.

Again: Thanks.

Nope i do not think you can use the Mod trick as you have said you do not want a set week i..e week 1 or week 2 of the month - you really need a script that will self modify as above or kick off a NR function that will set a context variable and work with that.

Craig

Digging, I've found this:

var todaydate = new Date();
var oneJan = new Date(todaydate.getFullYear(), 0, 1);
var numberOfDays = Math.floor((todaydate - oneJan) / (24 * 60 * 60 * 1000));
var weekOfYear = Math.ceil(( todaydate.getDay() + 1 + numberOfDays) / 7);
if (weekOfYear % 2 === 0)
{
    //even week, continue flow
    return msg;
} else
{
  //odd week, stop flow
return null;
} 

But!

let numberOfDays = Math.floor((todaydate - oneJan) / (24 * 60 * 60 * 1000));
Errors on todaydate and oneJan

So I'm stuck at this point now.

Oh, my meaning of the mod(2) was on the bigger week value.

(from epoch)

Sorry. My bad.

Check the code I just posted as that may work in some way.
But for now it is kind of just getting the feel for how to get the bigger week number and checking it's value.

RETHINK!

Ok so the function node does this:

Receives a message.
Looks at the epoch week value.
mod 2 the value. (0 or 1)
Depending on the result and which of the two weeks I want to use (the result will be 0 or 1) either returns the message or doesn't.

The code I posted is a bit of overkill I know.

Just what I found while digging.

Thought on the above:

So this bit of code:

[{"id":"91dab0a14efeb873","type":"moment","z":"60d0e3e966d484ae","name":"","topic":"","input":"payload","inputType":"msg","inTz":"Australia/Sydney","adjAmount":0,"adjType":"days","adjDir":"add","format":"WW","locale":"en-AU","output":"week","outputType":"msg","outTz":"Australia/Sydney","x":1790,"y":460,"wires":[["1c4ae4187049235c"]]},{"id":"10b5080bedf365cb","type":"inject","z":"60d0e3e966d484ae","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1717460918852","payloadType":"num","x":1580,"y":460,"wires":[["91dab0a14efeb873"]]},{"id":"1c4ae4187049235c","type":"debug","z":"60d0e3e966d484ae","name":"debug 2525","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2120,"y":460,"wires":[]}]

Given: THIS Saturday is a day I want to use.
Given: 1717460918852 is Now.

The above code gives me 23. (odd number) No big deal.

So I then look at msg.week (next function node - NOT included) and do a mod 2 and if I get a 1 then I pass on the message.

Sound like a good idea?

Remaining questions:
Will that survive a new year?
Or is WW from the moment node give me the week of this (actual) year and not *from the given timestamp? 1717460918852

Not at my PC to run this until later today - will do it then and have a look at your code

Craig

1 Like

Edit - I think you already solved it...

According to stackoverflow, the number of weeks since Jan 1 1970 is given by

const weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)

So this function will alternate between 0 and 1 every week:

const weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)
msg.payload = Number(weekno) % 2  // Not sure if Number() is needed
return msg;

So use your weekly cron and only run the downstream code if the function returns 0

demo flow:

[{"id":"937524d4abdadb79","type":"function","z":"5d7e1a0f2e73e424","name":"First week 8th June 07:00","func":"let timestamp = new Date(\"2024-06-08 07:00:00\").getTime()\nconst weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)\nmsg.payload = Number(weekno) % 2\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":40,"wires":[["96cdb55923eb10f9"]]},{"id":"96cdb55923eb10f9","type":"debug","z":"5d7e1a0f2e73e424","name":"0 or 1","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":530,"y":40,"wires":[]},{"id":"09b6e8013f76f0e5","type":"inject","z":"5d7e1a0f2e73e424","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"go","payloadType":"str","x":100,"y":40,"wires":[["937524d4abdadb79","ce38be64eda29a71","44c7b0eae01b689b","cc1a6bf62abb3035","20f3c1f767942e77"]]},{"id":"ce38be64eda29a71","type":"function","z":"5d7e1a0f2e73e424","name":"Second week 15th June 07:00","func":"let timestamp = new Date(\"2024-06-15 07:00:00\").getTime()\nconst weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)\nmsg.payload = weekno % 2\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":100,"wires":[["c375d43fa73f977d"]]},{"id":"44c7b0eae01b689b","type":"function","z":"5d7e1a0f2e73e424","name":"Third week 22nd June 07:00","func":"let timestamp = new Date(\"2024-06-22 07:00:00\").getTime()\nconst weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)\nmsg.payload = weekno % 2\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":160,"wires":[["0ace5d59302d94f8"]]},{"id":"cc1a6bf62abb3035","type":"function","z":"5d7e1a0f2e73e424","name":"Fourth week 29th June 07:00","func":"let timestamp = new Date(\"2024-06-29 07:00:00\").getTime()\nconst weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)\nmsg.payload = weekno % 2\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":220,"wires":[["48a47ed504696bcc"]]},{"id":"20f3c1f767942e77","type":"function","z":"5d7e1a0f2e73e424","name":"Fifth week 6th July 07:00","func":"let timestamp = new Date(\"2024-07-06 07:00:00\").getTime()\nconst weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)\nmsg.payload = weekno % 2\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":280,"wires":[["d967aa29bbfd863b"]]},{"id":"c375d43fa73f977d","type":"debug","z":"5d7e1a0f2e73e424","name":"0 or 1","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":530,"y":100,"wires":[]},{"id":"0ace5d59302d94f8","type":"debug","z":"5d7e1a0f2e73e424","name":"0 or 1","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":530,"y":160,"wires":[]},{"id":"48a47ed504696bcc","type":"debug","z":"5d7e1a0f2e73e424","name":"0 or 1","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":530,"y":220,"wires":[]},{"id":"d967aa29bbfd863b","type":"debug","z":"5d7e1a0f2e73e424","name":"0 or 1","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":530,"y":280,"wires":[]}]

If anyone else is reading this:

(and Craig)

Rather than using the moment node to get the week number

(Ok, I've seen @jbudd post)

make the function node in the code I posted do that?

Thanks.

But your code - I'm still looking at it - the date changes in every function node.

I need it to be one function node for all dates to come.
This year, next, and so on.

I can't afford to have function nodes for every week.

But I'll look at the maths in the node/s and see what I can learn.

I may be able to work them out but what are those two magic numbers?

Yes it does but it's only a demo/proof of concept.
For the real thing, make cronplus send the current timestamp; the function becomes

const timestamp = msg.payload
const weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)
msg.payload = Number(weekno) % 2
return msg;
1 Like

Oh, ok.

We were going at it in two different ways.

My latest post (the code) sends a FIXED value for now.
That means that the week % 2 will always be 1. (no big deal)
And the moment node gets the week number.
Alas I don't know if that is relative to the year. But anyway....

So your way gets now from the cronplus node and compared it to ....... those magic numbers.
(just quickly: why the _ and not a , as separators?
345,600,000 you show as 345_600_000 Any reason? Just asking.

As you are using timestamp the weeks will alternate 0 and 1. Ok, with you there.

So your code kind of skips what I did by basing it on now (this weekend's week value) and uses the epoch one.
Ok, good.

Sorry, I seem to be slow on the uptake just now.

Starting to make sense.

Umm. Good question!
The stackoverflow post i linked to has underscores.
I don't think commas would work, I am surprised underscores do. :grinning:
Best not to use either - 345600000 and 604800000

1 Like

No problems.

So this is what I have for the function node now:

const timestamp = msg.payload
const weekno = Math.floor((timestamp + 345_600_000) / 604_800_000)
const result_ = Number(weekno) % 2
if (result_ == 0)
{
    //  return message
    return msg;
}
else
//  do nothing
return;

Sorry, I've expanded it a bit only for personal clarity and the payload is going to be changed here rather than in another node.

But is that right?

I don't think you need to return from the function node if the flow stops there, so the else return is redundant.

Another way to do it is a switch node
image

1 Like

Ok, you got me there.

I only added it for clarity.

Will remove it.

But

if (result_ == 0)
{
    //  return message
    msg.payload = "this is needed at the next stage"
    return msg;
}

Is more like how it really is.

And THANKS for that help.

It went from a somewhat complex thing to somewhat easy.

I just got an error from the code I found:

let todaydate = new Date();
let oneJan = new Date(2024);
let numberOfDays = Math.floor((todaydate - oneJan) / (24 * 60 * 60 * 1000));
let weekOfYear = Math.ceil(( todaydate.getDay() + 1 + numberOfDays) / 7);
if (weekOfYear % 2 === 0)
{
    //even week, continue flow
    return msg;
} else
{
    //odd week, stop flow
    return null;
} 

showed up as this for me:

Line 4
And I didn't know why.

indulge me the node.warn that was me trying to find what was going on

Todaydate and oneJan are date objects so you can't just subtract one from the other.

But this is legal code. At this time of night I can't tell what impact it has on your calculation

let todaydate = new Date().getTime();  // milliseconds since Jan 1970
let oneJan = new Date(2024).getTime();
let numberOfDays = Math.floor((todaydate - oneJan) / (24 * 60 * 60 * 1000));
1 Like

No problem.

I wasn't blaming you for that.

I was just saying I found that code - which supposedly works - and it threw an error at me so the whole thing fell apart.

Hmmmm.... seems I didn't copy ALL the code.
Works now.

But I still prefer your way. :wink:

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