How to change time from message payload

I have a HomeAssistant automation that writes the date and time to a sensor when i press an RF button. So i have that node in NR and use the current_state node to read. It outputs the message as msg.payload (as below)

2020-05-10 17:01:44

What would i need to do to take that and add 72 hours for example? I know i could use a delay timer but if NR is restarted that automation would fail. Id like to add 72 hours, save that and then when that date and time is reached trigger something else (lights etc).

For context its a RF button i use when the plants are watered, 72 hours later it should remind me to water the plants. Only if someone is at home, and only trigger the alert at a certain time of day.

I assume this would be done with the function node but i dont have a clue on how to format, output and store that and then trigger the rest of my flow

If you want to do it in a function node, take a look at JS date

Or you might take a look at the moment node

1 Like

First, there are probably lots of ways to attack this so for any suggestion I have there are probably lots more and maybe better. You need to get the time into some format you can use. By that I mean you just can't add 72 hours to the time. That winds up with some weird number the computer can't understand. The way I'd do it would be to convert the time to epoch time. This is the time since Jan 1, 1970. There's lot of code on the web to convert the time into epoch. Then you can easily add 72 hours to that and come up with some time in the future. Alternatively you could find a timer then feed it with a 72 hour time period that would give the same result. Again, a number of ways to do it. But if you use a timer then if you lose power you would need to re-initialize the timer. One drawback. To store the time or any variable you need to use look for the commands for context and flow saves. This can write your data to memory or to a file to store your data for future use it's flow.set('var name',variable) and there are several ways to store it and various commands to modify it. Again, search for the command and you should get lots of code examples. As for the rest, only if someone is home, and writing alerts you may want to take small bites at this until you get to the end. Start with adding 72 hours and saving the variables then add code to get the other parts. Hopefully this will get you started. If you need to, come back to the forum and ask additional questions.

1 Like

An additional thought, someone else suggested in another question that you sit down and literally write out what you want to happen. I though this was an excellent suggestion. It forces you to consider what the code should do and would give you an outline your code would follow. As an example.

  1. get time
  2. add 72 hours
  3. check if someone home (how do you determine that)
  4. check if it's between a certain time
  5. send alert
    (just an example)

Off the top of my head...

  1. When the msg is received, store it to file as "last_event" or whatever you like. You can use node-red-contrib-key-value-store to make your life easy
  2. Have an inject node set to fire every minute (or every 60min if you want) that loads the last_event value from node-red-contrib-key-value-store. If it is a valid time value, add 72 hours & compare to now time. If it's within the timeframe then send your reminder then clear out the last_event value.

Ps, use the info the other guys provided on converting your string time to an actual time (my info was deliberately a high level concept to show you a possible way of persisting your time stamp and how you might handle a power cycle)

The moment node actually does exactly what i need, thanks for that! Next challenge is now working out how i can check the updates date / time message payload against the current date and time. If its not yet passed, then loop and check until it has.

Thank you for taking the time with those suggestions! Wasnt aware of that option and im sure that will be useful. Ive found the moment node has actually done what i need but i thought the next part would be simple. Now i have the moment node to set the correct format, a change node whichs adds 72 hours. I thought i would be able to use a timecheck node but it doesnt look at date, only time. Is there a node i can use to check if the input is more than the current date and time, if so do x y z and if not loop back and check again until it has.

This is my flow at the moment. Im just missing something to check if its the correct day. I only want the alert to trigger between certain hours so before that node it should check if its the correct day i guess, unless i can do that from the inject node which is sending flow.time_plus_72

Use a function node (some times you have to get your hands durt because there either isnt a node or its just overkill adding a custom node).

Demo...

function code of "check time" - NOTE I heavily commented it so you can evaluate it & tweak it if necessary...


if(!msg.payload){
    node.warn("msg.payload is empty - not gonna do anything - returning null to stop the msg from travelling to next node!")
    return null;// stop processing - payload is empty
}

//some basic setup...
msg._72h = 72*60*60*1000; //calculate 72h as a number of ms
let time72hoursAgo = Date.now() - msg._72h;//get epoch of 72h ago
msg.time72hoursAgo = new Date(time72hoursAgo);//Add  time72hoursAgo  to the msg (for easy debugging)
msg.now = new Date(); //get now time (and add it to the msg for easy debugging)
msg.last_event = new Date(msg.payload);//get last_event as a Date object (and add it to the msg for easy debugging)
msg.diff = msg.now - msg.last_event; //calculate difference

//now check see if diffeence is greater or equal to 72h
if(msg.diff >= msg._72h){
    msg.info = "its time to do something"
    msg.payload = true;
} else { 
    msg.info = "not time yet";
    msg.payload = false;
    //return null;// optionally - just stop processing by returning null
}

//return a msg so it flows to next node
return msg;

My demo flow (for importing if you wanna look at the demo parts)

[{"id":"24a4273c.7f7e78","type":"function","z":"f39c9e91.8598c","name":"check time","func":"\nif(!msg.payload){\n    node.warn(\"msg.payload is empty - not gonna do anything - returning null to stop the msg from travelling to next node!\")\n    return null;// stop processing - payload is empty\n}\n\n//some basic setup...\nmsg._72h = 72*60*60*1000; //calculate 72h as a number of ms\nlet time72hoursAgo = Date.now() - msg._72h;//get epoch of 72h ago\nmsg.time72hoursAgo = new Date(time72hoursAgo);//Add  time72hoursAgo  to the msg (for easy debugging)\nmsg.now = new Date(); //get now time (and add it to the msg for easy debugging)\nmsg.last_event = new Date(msg.payload);//get last_event as a Date object (and add it to the msg for easy debugging)\nmsg.diff = msg.now - msg.last_event; //calculate difference\n\n//now check see if diffeence is greater or equal to 72h\nif(msg.diff >= msg._72h){\n    msg.info = \"its time to do something\"\n    msg.payload = true;\n} else { \n    msg.info = \"not time yet\";\n    msg.payload = false;\n    //return null;// optionally - just stop processing by returning null\n}\n\n//return a msg so it flows to next node\nreturn msg;","outputs":1,"noerr":0,"x":1270,"y":60,"wires":[["7f320d98.3c3684"]]},{"id":"7f320d98.3c3684","type":"debug","z":"f39c9e91.8598c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1310,"y":120,"wires":[]},{"id":"f641f1ce.2e56e","type":"inject","z":"f39c9e91.8598c","name":"now","topic":"now","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":810,"y":80,"wires":[["24a4273c.7f7e78"]]},{"id":"455087b6.fa7e18","type":"inject","z":"f39c9e91.8598c","name":"71 hours ago","topic":"71 hours ago","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":830,"y":120,"wires":[["f5cec086.89f7d"]]},{"id":"f5cec086.89f7d","type":"function","z":"f39c9e91.8598c","name":"demo - calc 71 hours ago","func":"var d = new Date();\nd.setTime(d.getTime() - (71*60*60*1000));\nmsg.payload=d;\nreturn msg;","outputs":1,"noerr":0,"x":1050,"y":120,"wires":[["24a4273c.7f7e78"]]},{"id":"7d456c4d.1a0954","type":"function","z":"f39c9e91.8598c","name":"demo - calc 72 hours ago","func":"var d = new Date();\nd.setTime(d.getTime() - (72*60*60*1000));\nmsg.payload=d;\nreturn msg;","outputs":1,"noerr":0,"x":1050,"y":160,"wires":[["24a4273c.7f7e78"]]},{"id":"943bafa3.b342c","type":"inject","z":"f39c9e91.8598c","name":"","topic":"72 hours ago","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":830,"y":160,"wires":[["7d456c4d.1a0954"]]},{"id":"f519f8ac.1403e8","type":"inject","z":"f39c9e91.8598c","name":"nothing","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":810,"y":40,"wires":[["24a4273c.7f7e78"]]}]

no looping back - just dont pass the message on & wait for the next trigger

Ah - i just noticed you have a working solution - good.

Ignore my post above.

As for only operating at certain times - you could use a function node to check the time and do some simple logic - OR - use something like cron-plus

The cron-plus node will permit pretty much any thing you can think of e.g...

Here is where the path you choose has different consequences. Going down one path may make it seemingly easier at first but lead to bigger problems later. If you used the epoch time and added 72 hours then converted back the day and time problem would have been solved easier in my opinion but using the Moment node is definitely an easy way to get time up front. There is no right or wrong just different. @Steve-Mcl shows one of the ways (which is how I would do it).
I use cron-plus a lot but there are other ways to schedule as well. There is a within-time node that can be used to see if a time is within a certain range. Not sure if it would work well here or not.

2 Likes

Cant say thanks enough for the support! Really good community here :slightly_smiling_face:

Ive ended up with this so far. So regardless of any system reboots the date and time will always be correct and only alert me 3 days later, if someone is at home between 4-7pm. The alert will trigger every 30min until i hit the button, creating a updates timestamp which puts it 3 days later again. :smiley:

[{"id":"b95b265a.908868","type":"api-current-state","z":"bfb78147.85536","name":"","server":"9109b9bf.04e218","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_datetime.water_plants","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":370,"y":680,"wires":[["37e8b62.5c2314a"]]},{"id":"8d3a8516.8dc9b8","type":"inject","z":"bfb78147.85536","name":"","topic":"","payload":"","payloadType":"date","repeat":"60","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":680,"wires":[["b95b265a.908868"]]},{"id":"7d1aefd3.6ecd2","type":"time-range-switch","z":"bfb78147.85536","name":"","lat":"","lon":"","startTime":"15:00","endTime":"20:00","startOffset":0,"endOffset":0,"x":790,"y":680,"wires":[["2fa0f65b.19993a"],[]]},{"id":"22f8a2ca.ad7a7e","type":"alexa-remote-routine","z":"bfb78147.85536","name":"","account":"9433d58f.c0d298","routineNode":{"type":"speak","payload":{"type":"regular","text":{"type":"str","value":"Litter Tray needs cleaning"},"devices":["G090P308745508M3","G070RQ1080260CHE"]}},"x":1420,"y":700,"wires":[[]]},{"id":"37e8b62.5c2314a","type":"function","z":"bfb78147.85536","name":"check time","func":"\nif(!msg.payload){\n    node.warn(\"msg.payload is empty - not gonna do anything - returning null to stop the msg from travelling to next node!\")\n    return null;// stop processing - payload is empty\n}\n\n//some basic setup...\nmsg._72h = 72*60*60*1000; //calculate 72h as a number of ms\nlet time72hoursAgo = Date.now() - msg._72h;//get epoch of 72h ago\nmsg.time72hoursAgo = new Date(time72hoursAgo);//Add  time72hoursAgo  to the msg (for easy debugging)\nmsg.now = new Date(); //get now time (and add it to the msg for easy debugging)\nmsg.last_event = new Date(msg.payload);//get last_event as a Date object (and add it to the msg for easy debugging)\nmsg.diff = msg.now - msg.last_event; //calculate difference\n\n//now check see if diffeence is greater or equal to 72h\nif(msg.diff >= msg._72h){\n    msg.info = \"its time to do something\"\n    msg.payload = true;\n} else { \n    msg.info = \"not time yet\";\n    msg.payload = false;\n    //return null;// optionally - just stop processing by returning null\n}\n\n//return a msg so it flows to next node\nreturn msg;","outputs":1,"noerr":0,"x":630,"y":680,"wires":[["7d1aefd3.6ecd2"]]},{"id":"2fa0f65b.19993a","type":"api-current-state","z":"bfb78147.85536","name":"","server":"9109b9bf.04e218","version":1,"outputs":2,"halt_if":"home","halt_if_type":"str","halt_if_compare":"is","override_topic":true,"entity_id":"person.tom","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":true,"x":1050,"y":660,"wires":[["22f8a2ca.ad7a7e"],["8bf90602.fa20c8"]]},{"id":"8bf90602.fa20c8","type":"api-current-state","z":"bfb78147.85536","name":"","server":"9109b9bf.04e218","version":1,"outputs":2,"halt_if":"home","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"person.lolo","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":1050,"y":740,"wires":[["22f8a2ca.ad7a7e"],[]]},{"id":"9109b9bf.04e218","type":"server","z":"","name":"Home Assistant","legacy":false,"hassio":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true},{"id":"9433d58f.c0d298","type":"alexa-remote-account","z":"","name":"alexatts","authMethod":"proxy","proxyOwnIp":"192.168.0.8","proxyPort":"3456","cookieFile":"authFile","refreshInterval":"3","alexaServiceHost":"alexa.amazon.co.uk","amazonPage":"amazon.co.uk","acceptLanguage":"en-UK","userAgent":"","useWsMqtt":"on","autoInit":"on"}]