Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retain schedules after restart #11

Closed
pietrofranceschi opened this issue Jun 20, 2020 · 10 comments
Closed

Retain schedules after restart #11

pietrofranceschi opened this issue Jun 20, 2020 · 10 comments

Comments

@pietrofranceschi
Copy link

Dear Steve,
first of all many thanks for the nice piece of code!
I've some issues with my schedules when node-red restarts after a power cut or a system restart.
I've been setting my schedules inside the node, but after a system restart they do not run anymore even if they appear normally inside the node.
Am I missing something?
all the best

Pietro

@Steve-Mcl
Copy link
Owner

Steve-Mcl commented Jun 25, 2020

Hi,

That is a concern!

To be clear,

  • you enter 1? 2? or more schedules in the UI.
  • You deploy the flow
  • After a restart/power cut, the schedules are still in the UI but dont run?
    Is that correct?

Some questions to help me help you if you dont mind...

  • Are you using the latest version (V1.0.3)?
  • What hardware is this on (Rasperry?)
  • What OS (Windows? Raspian etc?)
  • What nodejs version & node-red version also please?
  • could you export the node (Click the CRON node, Press CTRL+E, copy) and paste the flow code it in a reply?

I am eager to fix this if its a bug.

Thanks for feedback.

@Steve-Mcl
Copy link
Owner

One more thing - your title says "Retain schedules after restart"

On the latest version (V1+) there is a new feature "Persist Dynamic Schedules"

@pietrofranceschi
Copy link
Author

Hi Steve,
thanks for the reply.
I've been checking and I was not using the latest version!
Before bothering you again I'll try to go through the tests I did and check if now the node behaves as expected.

To sum up:

  • I'm on a RaspberryPi3 with raspbian and node-red 1.0.6 (node js v12.16.3)
  • my idea is to use cronplus to trigger the on-off of my watering system by using two separate schedules, which were manually configured in the node
  • I'm enabling/disabling the schedules through a switch in the UI
  • to retain the state of my system even in the presence of a power cut, I'm setting the state of the scheduler (enable/disable) injecting at startup the content of a global variable
  • doing that I've found (garden flooding ;-)))) that the schedules were not retained (even if present inside the node) after a power cut. The system was indeed behaving erratically.

My interpretation was that I was somehow mixing the dynamic setting of the node (I'm indeed injecting something) with the "static" operation (my schedules are written in the node).

I'll come back to you if I find the same problems with the latest version.

I conclude thanking you for the node. I really appreciate the flexibility it allows!

Great idea

all the best

Pietro

@Steve-Mcl
Copy link
Owner

Ah so let me see if I understand this correctly.

  1. Enter static schedules
  2. You disable them
  3. You reboot - and they are re-enabled

That would be the expected behaviour because the nodes static settings are re-loaded on a reboot.

Is my summary correct?


1 solution could be...

  • update to latest version
  • enable persistence option
  • add and remove schedules dynamically as required (the persistence option will be updated each time you add/remove a schedule)
    • this is quite easy and there are lots of examples in the built in demos (CTRL_I to import > examples > node-red-contrib-cron-plus)

If you need help on that I can assist.

Please let me know either way.

@pietrofranceschi
Copy link
Author

Hi Steve,
I did my tests but my problem persists also after the upgrade. I try to explain better what I'm doing

  1. I create two static schedules inside the node
  2. I would like to enable/disable them with a button in the UI
  3. To do that I'm injecting a message with a JSON payload (for starting them, for example {"command":"start-all"}) into the node

So far so good

  1. I would like to retain the state (enable/disable) of my schedule even if, for some reason, the system reboots
  2. To do that I'm feeding the "control" message into a global variable, which is then re-injected into the CRON node after the restart

If I do like that the CRON node somehow freezes ... it is now telling to me that it will restart ten minutes ago ...
If I look into the node the static schedules are there

From your message, I understand that a possible workaround could be to set dynamic schedules and retain them after reboot. But I find more "clean" to rely on static schedules and simply enable/disable them in a dynamic way.

I'm attaching here my test flow (... so you will discover that I'm doing some stupid error ... ;-))

Many thanks for your time!

Pietro

[{"id":"9da5cf6c.f75a7","type":"cronplus","z":"698357b1.93c218","name":"","outputField":"payload","timeZone":"","persistDynamic":false,"commandResponseMsgOutput":"output1","outputs":1,"options":[{"name":"start","topic":"start","payloadType":"str","payload":"on","expressionType":"cron","expression":"0 10 23 * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"},{"name":"stop","topic":"stop","payloadType":"str","payload":"off","expressionType":"cron","expression":"0 15 23 * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":640,"y":740,"wires":[["624510bb.2c239"]]},{"id":"a44ce1d7.1a3dd","type":"inject","z":"698357b1.93c218","name":"stop all","topic":"","payload":"{"command":"stop-all"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":350,"y":720,"wires":[["9da5cf6c.f75a7","18347cec.6fe003"]]},{"id":"18347cec.6fe003","type":"change","z":"698357b1.93c218","name":"","rules":[{"t":"set","p":"test","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":860,"wires":[[]]},{"id":"c2d2fea5.c8a94","type":"inject","z":"698357b1.93c218","name":"","topic":"","payload":"test","payloadType":"global","repeat":"","crontab":"","once":true,"onceDelay":"1","x":210,"y":640,"wires":[["9da5cf6c.f75a7"]]},{"id":"703ed550.31a50c","type":"inject","z":"698357b1.93c218","name":"start all","topic":"","payload":"{"command":"start-all"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":350,"y":760,"wires":[["9da5cf6c.f75a7","18347cec.6fe003"]]},{"id":"624510bb.2c239","type":"debug","z":"698357b1.93c218","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":970,"y":760,"wires":[]}]

@pietrofranceschi
Copy link
Author

Ah, if I manually re-inject a stop-start sequence the CRON node is back in its expected working state

@Steve-Mcl
Copy link
Owner

Ah, if I manually re-inject a stop-start sequence the CRON node is back in its expected working state

Yes, that is one way (see V1 in image) however unless you enable persistent context Global is reset when node-red restarts.

So I did 2 demos of how you can handle this...

V1 uses a contrib node that saves values to FILE for you. I use this node often as its simple and effective.

V2 uses fully dynamic mode - i.e. I add / remove the schedules with persistence enabled.

image

The demo flow...

[{"id":"2644b8d4.fdbb38","type":"cronplus","z":"7b57d2de.05cecc","name":"","outputField":"payload","timeZone":"","persistDynamic":false,"commandResponseMsgOutput":"output1","outputs":1,"options":[{"name":"start","topic":"start","payloadType":"str","payload":"on","expressionType":"cron","expression":"0 10 23 * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"},{"name":"stop","topic":"stop","payloadType":"str","payload":"off","expressionType":"cron","expression":"0 15 23 * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":600,"y":240,"wires":[["23a1e8e8.23bfc8"]]},{"id":"812a297c.686338","type":"inject","z":"7b57d2de.05cecc","name":"stop all","props":[{"p":"payload","v":"{\"command\":\"stop-all\"}","vt":"json"},{"p":"topic","v":"","vt":"string"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"stop-all\"}","payloadType":"json","x":370,"y":300,"wires":[["2644b8d4.fdbb38","1afd0cde.c511b3"]]},{"id":"8c2ce58f.f21e18","type":"inject","z":"7b57d2de.05cecc","name":"start all","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"command\":\"start-all\"}","payloadType":"json","x":370,"y":240,"wires":[["2644b8d4.fdbb38","1afd0cde.c511b3"]]},{"id":"23a1e8e8.23bfc8","type":"debug","z":"7b57d2de.05cecc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":890,"y":240,"wires":[]},{"id":"fd9afa7e.1524f8","type":"comment","z":"7b57d2de.05cecc","name":"V1 : Save & restore state ( Uses node-red-contrib-key-value-store )","info":"","x":560,"y":140,"wires":[]},{"id":"1afd0cde.c511b3","type":"key-value-write","z":"7b57d2de.05cecc","store":"a9c78f02.bf5e5","action":"set","key":"schedule-state","keyvalue":"","name":"Save schedule-state","x":640,"y":300,"wires":[[]]},{"id":"226a87f1.704668","type":"inject","z":"7b57d2de.05cecc","name":"Start up pulse","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":400,"y":180,"wires":[["fcb100cd.944fe"]]},{"id":"fcb100cd.944fe","type":"key-value-read","z":"7b57d2de.05cecc","store":"a9c78f02.bf5e5","key":"schedule-state","name":"Read schedule-state","x":640,"y":180,"wires":[["2644b8d4.fdbb38","967fa014.30d1a"]]},{"id":"967fa014.30d1a","type":"debug","z":"7b57d2de.05cecc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":890,"y":180,"wires":[]},{"id":"c620d1e1.a85c","type":"cronplus","z":"7b57d2de.05cecc","name":"","outputField":"payload","timeZone":"","persistDynamic":true,"commandResponseMsgOutput":"output1","outputs":1,"options":[],"x":600,"y":440,"wires":[["a84ebb16.0e94b8"]]},{"id":"ff51201c.1c537","type":"inject","z":"7b57d2de.05cecc","name":"Add schedules","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[{\"command\":\"add\",\"topic\":\"start\",\"name\":\"start\",\"payloadType\":\"str\",\"payload\":\"on\",\"limit\":null,\"expressionType\":\"cron\",\"expression\":\"0 10 23 * * * *\"},{\"command\":\"add\",\"topic\":\"stop\",\"name\":\"stop\",\"payloadType\":\"str\",\"payload\":\"off\",\"limit\":null,\"expressionType\":\"cron\",\"expression\":\"0 15 23 * * * *\"}]","payloadType":"json","x":400,"y":420,"wires":[["c620d1e1.a85c"]]},{"id":"ddc4fbc9.8c6868","type":"inject","z":"7b57d2de.05cecc","name":"Remove schedules","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"remove-all","payload":"","payloadType":"date","x":410,"y":480,"wires":[["c620d1e1.a85c"]]},{"id":"a84ebb16.0e94b8","type":"debug","z":"7b57d2de.05cecc","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":890,"y":440,"wires":[]},{"id":"245006a4.90a91a","type":"comment","z":"7b57d2de.05cecc","name":"V2 : Add / Remove schedules with persistence","info":"","x":490,"y":380,"wires":[]},{"id":"a9c78f02.bf5e5","type":"key-value-store","z":"","filepath":"store.json","namespace":"","name":""}]

@pietrofranceschi
Copy link
Author

Hi Steve,
many thanks for the flows!
I tested V1 since it fits with my initial idea.
As far as I can understand the problem is not yet solved. What I did:

  1. set up some schedules and test if the schedule-state is saved and can be read in. OK
  2. test the system (without rebooting) playing with the start/stop injection nodes. OK
  3. set-up a schedule and then reboot the raspberry before the start time. When I re-enter the flow editor everything seems to be ok (the CRON node shows to me the correct scheduling in the tiny message field), but the node does not fire at the right time (I tested that with the real watering valve to be sure that the problem was not the refresh of the debug nodes).
  4. if I modify the static schedules and re-deploy the node the system works normally
  5. I've tried with the node without all the "injections" ad it works as expected (resuming the static schedules) after a restart
    It seems that the problem arises on the static schedules when the "start-all" command is injected after the startup.

Let me know what you think!

all the best

Pietro

@Steve-Mcl
Copy link
Owner

Hi @pietrofranceschi - I have found the issue and "contained it" for now (I have raised an issue on an underlying library).

Can you please update to V1.0.6 and let me know 🤞

Thanks for your patience and support.

Steve.

@pietrofranceschi
Copy link
Author

Dear Steve,
sorry for my slow reply. I was away!
I tested the updated version and now everything seems to work smoothly.
In the next days, I'll try to perform some more checks, but it seems you fixed the issue.
Many thanks to you for your patience, support end efforts!
I owe you one.
all the best

Pietro

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants