biddster / node-red-contrib-schedex

Scheduler for node-red which allows you to enter on/off times as 24hr clock (e.g. 01:10) or suncalc events (e.g. goldenHour). It also allows you to offset times and randomise the time within the offset.
22 stars 17 forks source link

Is is possible to resend the current state of the timer ? #67

Closed dionmes closed 4 years ago

dionmes commented 4 years ago

Is there a command to send to a schedex node to resend the current state of the timer as the on/off payload ? Info gives a complete object, but I just need to resend the current state after I have suspended the schedule.

Use case: I suspend some schedules when I am home. And when I leave they get unsuspended. When I unsuspend the timers I want them to send the current state so the situation of the switches becomes the state they would actually have as if they were not suspended at all.


Update: I just added some code that implements a 'resend' command and testing now. If I am ok with it I will do a push.

drmibell commented 4 years ago

I think there are simple ways to meet your requirement without modifying the schedex node, and the results may actually be better. If I understand correctly, you want to be able to re-activate the timers and have your control system go into the state it would have reached if the timers had not been suspended. In general, it will not be enough for the timers to send out their current state, either "on" or "off". The downstream flow might require the last actual message that timer would have sent, including the correct onpayload or offpayload as well as possibly ontopic or offtopic if mqtt is being used to transmit messages.

I would suggest that rather than changing the suspended state of the timer, you send its output to a q-gate node (node-red-contrib-queue-gate), configured to save the most recent message, as described in the second example in the README, except with Default State = open. Then use the "at home" signal to put the gate into the queueing state and the "away" signal to send an open message to the gate. I think this gives the result you want, using exactly the last message that the timer would have sent if it had not been suspended.

dionmes commented 4 years ago

That is a great suggestion and probably would solve my use case. But it wasn't so hard to implement a resend command in the code and this way I will have a little less clutter and complexity in the flow. It will send the on or off payload, I will check if the topic also needs to be send as I don't use it myself.

drmibell commented 4 years ago

I often send the outputs of a number of schedex nodes directly to the input of a single mqtt out node. Not having the topic available would mean adding a change node to each timer, and would probably be a deal breaker for me. In general, requiring the re-sent message to be handled differently from other messages from the node is probably not a good idea.

I hope you won't object to a few questions about how you want this feature to work.

dionmes commented 4 years ago

Hi. I also added that it now sends the topic so that should be fine.

This is how I have it working now ;

drmibell commented 4 years ago

I assume that If no scheduled (configured) events occurred while the node was suspended, it will resend the last configured event that was sent before it was suspended.

The flow I suggested differs from this feature in two ways:

dionmes commented 4 years ago

So to abstract my requirement for the new functionality would be this;

A command which enables the system to go to the scheduled state as stored in the schedex node.

  • Your first suggestion would conflict with this. The system would go to the last command which could conflict with the scheduled state.
  • I see no added value in only allowing this once. It would offer redundancy by allowing it multiple times.
drmibell commented 4 years ago

Right. I did not mean that one approach was better, just that they are slightly different. The decision to have the schedule override possible user input from the dashboard or elsewhere could be left to the user rather than built into the node. Multiple resends certainly might be useful in some cases.

Ultimately, the author/maintainer of the node will have to decide whether to accept a PR for the change, but the beauty of open source is that we can all customize versions to suit our needs.

biddster commented 4 years ago

Thank you both for the input. I'm more than open to a PR for this.

dionmes commented 4 years ago

Hi. Great to hear. Just one thing, any suggestion how to name the command. Currently I have it named 'resend' but this might be confusing because it does not resend the last command. It sends the 'state'. So my suggestion would be to name it ; 'sendstate' , if that is ok with you?

biddster commented 4 years ago

I've been musing this one over. Feels like the action is to synchronise the state. So sync_state or something?

drmibell commented 4 years ago

Good point, but we have focused on synchronizing the state of the timer, when I think we should be trying to make sure the user can synchronize/restore the state of the downstream flow. I can imagine cases where the flow has some dependence on the history or sequence of events and would need to see all the outputs the node would have sent while it was suspended. My suggestion, and I realize it includes features we haven't discussed before, would be: add a drop-down menu next to the "Suspend scheduling" checkbox with the label "On re-activation send" and the options "Nothing", "Most recent skipped event"", and "All skipped events". If the first option is the default, this would not break existing flows. If you are interested in the idea, there are some fine points we should discuss.

biddster commented 4 years ago

I need to let this fester a bit.

I'm not keen on the unbounded "all skipped events" as who knows how people are using schedex? All events could potentially be millions? And then we're potentially into memory issues.

dionmes commented 4 years ago

I don't think we should make it overly complex. The core functionality request comes from using the scheduling info inside the schedex node.

drmibell commented 4 years ago

OK, we are into the "fine points" I mentioned.

All events could potentially be millions?

In principle, yes, depending on how long the timer was suspended, but events are typically generated only two per day, and it would be reasonable to limit the size of the queue to something quite small.

skipped events are only the scheduled events ?

True, but if the timer is suspended long enough, more than one scheduled event might be skipped. Synchronizing the downstream flow could require knowing about all of them, not just the most recent one.

I don't think we should make it overly complex.

Agreed, but there may be a tradeoff between complexity and utility. I can understand your wanting the simplest change that will meet your specific requirement. I was suggesting a more general approach that might be more widely useful if we can accept a bit more complexity.

dionmes commented 4 years ago

Could you suggest a use case where it would be necessary to resend all passed scheduled events when the timer was in suspended mode?

drmibell commented 4 years ago

Sure. I have an alarm that once triggered requires a reset before it can be triggered again. If both the reset and trigger occur when the timer is suspended, it will not respond if only the trigger sent when the timer is re-enabled.

dionmes commented 4 years ago

So a message of caution, nodered is not a persistent system. After a restart or shutdown, you are back at your configured state, so for example for schedex this means that after a restart the suspended state is lifted if it is not its default/configured state. So if you do not want to miss any alarms be aware of this and create your own persistency by for example writing queues to storage.

So back to your use case, the function works like this; 1) lift suspended mode 2) send resync command. It would then either sent the 'alarm' or 'reset' command depending on the time. And of course the alarm will fail if like you said the 'reset time' was in suspended mode.

In your case you should do; 1) lift suspended mode. 2) send reset 3) send resync command

But to make a more robust system I would suggest that every time you triggered the alarm you immediately sent the reset command after. If that is not possible, send the reset command everytime before you send the alarm command. You then get a much more reliable situation.

If you would like a longer queue/persistency then I don't think schedex is the right node for that.

drmibell commented 4 years ago

@dionmes, I understand and agree with everything you have said. That is why I use schedex nodes only to generate events at specified times. I handle everything else with external logic. This includes deciding which messages to act upon, ignore, delay, or combine with other messages and how to program the timers and persist the programs. All this was possible even before Node-RED added persistent storage and before the timer info command and programming capability had all the features I requested, although these changes help greatly. Along the way, I developed the node-red-contrib-simple-gate and node-red-contrib-queue-gate nodes to support the logic I need.

Since the only time I suspend a schedex node is during development and testing, your use case initially struck me as odd, although it makes perfect sense. (As the README says "This setting is provided for the situation where you temporarily don't want time based activation and don't want to rewire your Node-RED flow.")

I appreciate your suggestions concerning my alarm system. I solved this issue long ago and mentioned it only because you asked for a use case. I came into this discussion to offer my advice (for what it's worth) to @biddster on how or whether to modify the schedex node. I don't think I have anything more to add.

dionmes commented 4 years ago

@drmibell I apologise if I come over blunt, must be my Dutch directness but I do appreciate your input. I will push now with the command named 'sync_state'.

drmibell commented 4 years ago

@dionmes, no worries. My thesis advisor was from Leiden.

dionmes commented 4 years ago

This is great. Thx.

biddster commented 4 years ago

No problem. It all looks good in test. The only thing I'm deliberating is if send_state should send 'suspended' if the node is suspended?

dionmes commented 4 years ago

It could. For me the safest (most compatible) is to not send anything. But there is a case to make for sending suspended as it is the most informative.

biddster commented 4 years ago

I think I'm going to include the suspended state as it valid.

biddster commented 4 years ago

Nah, changed my mind. Under routine operation, Schedex emits nothing if suspended. The send_state should work the same.

dionmes commented 4 years ago

Haha, yeah this is one of those choices.

biddster commented 4 years ago

Fixed in 1.8.0