UPDATE: V1.2.1 node-red-contrib-cron-plus scheduler (incl solar events and Timezone support)

Thanks - I'll study it later as it's my IoT Club today.

I'm reasonably sure I can port it to use Telegram in about an hour or so, and I need a distraction from an overhaul to my current flow so be sure to check back later :stuck_out_tongue:


Stop the clock, it's working :wink:
I technically had the flow finished in an hour, spent the last 15 minutes squashing a bug in it :joy:

[{"id":"d12e2291.f01a4","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"7e97b34c.f9bc5c","type":"chatbot-telegram-receive","z":"d12e2291.f01a4","bot":"784718d7.7053e","botProduction":"","x":130,"y":180,"wires":[["398dd694.5e493a"]]},{"id":"c063b4af.f7e87","type":"chatbot-debug","z":"d12e2291.f01a4","x":750,"y":160,"wires":[]},{"id":"398dd694.5e493a","type":"chatbot-authorized","z":"d12e2291.f01a4","x":330,"y":180,"wires":[["aec4d27f.f70cd8"],[]]},{"id":"1a4a9de0.983f72","type":"chatbot-conversation","z":"d12e2291.f01a4","name":"","botTelegram":"784718d7.7053e","botTelegramProduction":"","botSlack":"","botSlackProduction":"","botFacebook":"","botFacebookProduction":"","botViber":"","botViberProduction":"","botUniversal":"","botUniversalProduction":"","botTwilio":"","botTwilioProduction":"","botDiscord":"","botDiscordProduction":"","chatId":"","transport":"telegram","messageId":"","contextMessageId":false,"store":"","x":110,"y":420,"wires":[["2d509d49.cfb3ba"]]},{"id":"8494496f.986818","type":"chatbot-message","z":"d12e2291.f01a4","name":"Send notification to user","message":[],"answer":false,"silent":false,"x":510,"y":420,"wires":[["d2872997.824c"]]},{"id":"fc85fbeb.6802","type":"cronplus","z":"d12e2291.f01a4","name":"Reminders","outputField":"payload","timeZone":"","options":[{"topic":"drink_water","payload":"{\"readableTitle\":\"Remember to drink\",\"message\":\"It's time to drink some water or tea.\",\"to\":{\"username\":\"afelix\"}}","type":"json","expression":"0 0 9,11,13,15,17,19,21 * * *"}],"x":110,"y":280,"wires":[["ff3061e4.af867"]]},{"id":"ff3061e4.af867","type":"switch","z":"d12e2291.f01a4","name":"Is reminder?","property":"cronplus.triggerTimestamp","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":290,"y":280,"wires":[["cebf1bde.f1ea4"],[]],"outputLabels":["regular output","control message"]},{"id":"aec4d27f.f70cd8","type":"switch","z":"d12e2291.f01a4","name":"User seen before?","property":"known_chats","propertyType":"flow","rules":[{"t":"hask","v":"payload.userId","vt":"msg"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":530,"y":160,"wires":[[],["c063b4af.f7e87","c118e5b.a2b4198"]],"outputLabels":["yes","no"]},{"id":"c118e5b.a2b4198","type":"function","z":"d12e2291.f01a4","name":"Store user for future interactions","func":"const known_chats = flow.get('known_chats') || {};\n\nknown_chats[msg.payload.userId] = {\n    \"userId\": msg.payload.userId, // yes redundant but it might spare an extra lookup\n    \"chatId\": msg.payload.chatId,\n    \"transport\": msg.payload.transport\n};\n\nflow.set('known_chats', known_chats);\nreturn msg;","outputs":1,"noerr":0,"x":830,"y":200,"wires":[[]]},{"id":"d2872997.824c","type":"chatbot-telegram-send","z":"d12e2291.f01a4","bot":"784718d7.7053e","botProduction":"","track":false,"passThrough":false,"outputs":0,"x":750,"y":420,"wires":[]},{"id":"cebf1bde.f1ea4","type":"function","z":"d12e2291.f01a4","name":"Prepare for sending to the right user","func":"// Incoming payload:\n//{\n//    \"readableTitle\": \"Remember to drink\",\n//    \"message\": \"It's time to drink some water or tea.\",\n//    \"to\": {\n//        \"username\": \"afelix\"\n//    }\n//}\nconst known_chats = flow.get('known_chats') || {};\n\nif (known_chats.hasOwnProperty(msg.payload.to.username)) {\n    const user_details = known_chats[msg.payload.to.username];\n    \n    msg._outgoing_text = `**${msg.payload.readableTitle}**\\n${msg.payload.message}`;\n\n    msg.payload = {\n        'chatId': user_details.chatId\n    }\n    return msg;\n}\nelse {\n    node.error(`The user (${msg.payload.to.username}) set to receive this message is not known to the Telegram bot yet. Please start a conversation first.`, msg);\n}","outputs":1,"noerr":0,"x":590,"y":280,"wires":[["1a4a9de0.983f72","205697b0.a7c4c8"]]},{"id":"e782f439.df1568","type":"comment","z":"d12e2291.f01a4","name":"Create flow store on first run","info":"","x":140,"y":20,"wires":[]},{"id":"eb39eb9a.ebde8","type":"comment","z":"d12e2291.f01a4","name":"Actual handler","info":"","x":90,"y":140,"wires":[]},{"id":"4c5e468d.08c67","type":"inject","z":"d12e2291.f01a4","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":110,"y":60,"wires":[["3ab07597.e87632"]]},{"id":"3ab07597.e87632","type":"function","z":"d12e2291.f01a4","name":"Create flow store if needed","func":"const known_chats = flow.get('known_chats') || {};\nnode.warn(known_chats);\nif (Object.keys(known_chats).length === 0) {\n    // new store\n    flow.set('known_chats', known_chats);\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":60,"wires":[[]]},{"id":"205697b0.a7c4c8","type":"debug","z":"d12e2291.f01a4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":850,"y":280,"wires":[]},{"id":"2d509d49.cfb3ba","type":"change","z":"d12e2291.f01a4","name":"Set text as payload","rules":[{"t":"move","p":"_outgoing_text","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":290,"y":420,"wires":[["8494496f.986818"]]},{"id":"784718d7.7053e","type":"chatbot-telegram-node","z":"","botname":"<username of your bot>","usernames":"<your own username/user-id to set as authorised>","providerToken":"","polling":"1000","store":"f2eb2047.10f9e","log":"","parseMode":"","debug":true,"webHook":"","connectMode":"polling"},{"id":"f2eb2047.10f9e","type":"chatbot-context-store","z":"","name":"context-memory","contextStorage":"memory","contextParams":""}]

Required nodes: node-red-contrib-cron-plus (duh) and node-red-contrib-chatbot (for the telegram nodes).


You're most welcome. And thanks for the kind words. Take care.

@afelix - I created something similar a while ago when a family member was ill (and I kept forgetting her meds!!)
The biggest failing I found was that if I was busy - on phone, cooking, showering etc, I'd acknowledge the alert, but then a little later forget to give the meds... sound familiar??

I wanted to create (but never got around to it) an interface with a 'done' & 'snooze' button, so if I got distracted, the alert would sound again 10 minutes later, and re-occur until I pressed 'done'.

1 Like

I can actually do that with Pushcut, but haven't gotten around yet to set it up properly. Setting an action to the alert that when clicking the "done" button/"snooze" button a message is POSTed back to Node-RED (would work as long as I'm local) to either acknowledge the action, or send it again 10 minutes later.

1 Like

That sounds ideal. I've never heard of Pushcut, but I'll check it out.

Ah, it's an app for apple lovers - no android version!

It's an app specifically to connect push messages to Apple's own Shortcuts system, hence the name. So you can start Shortcuts running on your phone/tablet through a notification being send, where you are in control of which notifications and when. I use it with another Apple-only app: Pythonista

With Telegram, you can do it both ways with a simple command.

I finally got round to building a dashboard controlled demo...

Dynamic cron schedules / timers via dashboard control

Hopefully of some use to people

(Apologies for spamming - I first replied to a another thread then realised I should have updated this thread first & simply posted a link to this entry - live and learn)


UPDATE V0.4.0 released & published in NPM

  • Fix bug with some cron expressions not parsing correctly
  • Improve editor layout
    • moved the dynamic cron description to a tooltip to reduce need for scrolling
    • maximized the schedule list size

Should be in the flow library and pallet soon


This is eithor a docup or a bug. Look at the time (I'm in the US east coast). It is 9:39 AM. The doc for the node says 0 0 12 * * * means it will run everyday at noon, which is 2 hours and 20 minutes and some seconds away. However the yellow description area says it will next run in 22 hours and 20 minutes and a 27 seconds.

Something doesn't jib.

Do you have the latest version because there were certainly timezone issues in the previous version

Sorry I should have added it is v0.4.0 - I upgraded after I saw the issue, restarted NR nand cleared the browsers cache and even used another browser. Same issue shows up.

Where is node-red running and what is the timezone on that machine? -4h?

Also, what is the timezone where the browser is running?

Looks like a bug. Bah.

Friday bug tracking is Verboten!

1 Like

Just noticed localhost in browser address (so I know node-red and browser are on same machine)

So could you also tell me what version of nodejs and node-red please? Have a sneaky suspicion on something.

Here you go Steve
25 Oct 19:07:19 - [info] Node-RED version: v1.0.2
25 Oct 19:07:19 - [info] Node.js version: v10.15.3
25 Oct 19:07:19 - [info] Darwin 17.7.0 x64 LE
25 Oct 19:07:23 - [info] Dashboard version 2.17.1 started at /ui

Running on a Mac macOS 10.13.6

And just to confirm, your Mac is set to GMT-4 right?

Oh and one other thing., If you don't mind, leave that flow in operation with the browser open and a debug node attached - I believe it will trigger at system time 12:00 (I hope anyway).

Or attach a flogger or file log or something so we can determine when it triggers.

Either way, it will give a head start.

Thanks for your support

yes it is set to GMT-4 - I'll leave it running overnight
would it help if I changed my system clock and did some testing?

Also here are the settings with the Timezone option filled in

and the Tmezone option empty