node-red-contrib-ui-time-scheduler icon indicating copy to clipboard operation
node-red-contrib-ui-time-scheduler copied to clipboard

[FR] Fire event on change

Open Sineos opened this issue 3 years ago • 4 comments

I'm using events to schedule my room heating. If the event value is changed, I need to wait until the event is due before the change actually is applied.

It would be great if you added an option to fire the event when changed, provided the change is within the current time range and selected days.

I current work around this with a function node, which has the same number of outputs like ui-time-scheduler and this hacky code:

const CurTS = new Date();
const TempTS = new Date();
// Return 6 for Sunday and 0 for Monday
const CurWeekDay = (CurTS.getDay() + 6) % 7;
// Initialize an array with the number of outputs. Use "null"
// to avoid setting one if skipped in the compare
const OutArray = [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null];
const data = JSON.parse(msg.payload);

data.timers.forEach((obj) => {
  const temp = new Date(obj.starttime);
  const CompareTS = TempTS.setHours(temp.getHours(), temp.getMinutes(), 0);

  if (CurTS.getTime() > CompareTS && Number(obj.days[CurWeekDay]) === 1) {
    OutArray[Number(obj.output)] = {payload: Number(obj.event)};
  }
});
return OutArray; 

Basically using the JSON status output on port 0 to create another message. This is a weak solution since it again forces all values, so an improvement would be highly appreciated. Unfortunately my JS skills are too basic for your node to send a PR.

Sineos avatar Apr 12 '22 06:04 Sineos

Hi Sineos,

I am a little confused about "if it's within time range". You said you use the event mode, and the event mode is literally a single point in time. So you can't really figure out if it's within some range. Comparing it against new Date() is problematic as there could be multiple events after the one currently evaluated.

What is your definition of "within range" and would your scenario maybe work better if the default mode (from/to) would support something like custom payloads?

fellinga avatar Apr 13 '22 03:04 fellinga

Thanks for coming back to this and sorry for not being clear in the first place.

A typical entry looks like: grafik

  • At 04:30 my thermostat receives the 21°C event
  • If I now change the target at 10:30 to say 22°C, I need to wait until next day 04:30 until it becomes effective

What the function node does:

  • Takes the JSON output on port 0 that is generated on change
  • Compares if the (Current Local Time) is greater than the (Event Time): 10:30 is greater than 04:30 but below the second time 22:00 --> This is what I meant "within range"
  • Compares if the (days array) == 1 for (current week day)
  • Outputs the (event value) on the respective port of the function node and thus sets the new (event value) to the thermostat

would your scenario maybe work better if the default mode (from/to) would support something like custom payloads?

This would be a nice solution as well, but would need:

  • Custom payload to be set in the UI
  • Also "fire once" on change or it will be the same as explained above

Many thanks for considering.

Sineos avatar Apr 13 '22 08:04 Sineos

The approach to compare two entries in the event mode is problematic. First of all, the reason why the event mode was created is to schedule single events at a single time. Comparing one event to other events in the list is therefore something that does not feel right. Also, if there is no second element in the list then things would become a little confusing, since I would have to choose to update always, or never.

The default mode works a little different. It already updates regularly (once per minute, customizable) and also on change. That would work well with custom payloads, but not quite. Updating regularly currently means it sends an on signal (true) or an off signal (false) whether one of the schedules are currently active or not. I am not quite sure what I would need to send outside of schedules times then.. false, some fixed payload, nothing?

EDIT: Thought about it a little more, wouldn't it make a lot more sense to have something like a separate temperate control as well? This would additionally allow you to change the temperature just temporarily until the next scheduled timer sends some target temperature.

target

I know that this is not a direct solution to what you have been asking for but with the additional controls you can easily readjust the temperature after a timer change and it also provides an additional nice feature to your flow.

Here is the flow: [{"id":"72e35c14764a9618","type":"ui_time_scheduler","z":"0982b67c87526224","group":"35837a9dea40e7b4","name":"","startDay":"1","refresh":60,"devices":["Heating"],"singleOff":false,"onlySendChange":false,"customPayload":true,"eventMode":true,"eventOptions":[],"sendTopic":false,"lat":"48.30","lon":"14.28","customContextStore":"","outputs":2,"order":0,"width":"6","height":"3","x":650,"y":120,"wires":[["46347ecd3c620adc"],["07989680e14b979b"]]},{"id":"bae8c716543de8cb","type":"inject","z":"0982b67c87526224","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":120,"wires":[["a408d6657218240f"]]},{"id":"46347ecd3c620adc","type":"file","z":"0982b67c87526224","name":"","filename":"/home/ubuntu/dev/demofiles/timer0.txt","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":930,"y":100,"wires":[[]]},{"id":"a408d6657218240f","type":"file in","z":"0982b67c87526224","name":"","filename":"/home/ubuntu/dev/demofiles/timer0.txt","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":370,"y":120,"wires":[["72e35c14764a9618"]]},{"id":"e0b77f543347275d","type":"ui_text","z":"0982b67c87526224","group":"35837a9dea40e7b4","order":1,"width":"4","height":"1","name":"","label":"TargetTemp","format":"{{msg.payload}} °","layout":"row-spread","className":"","x":1050,"y":200,"wires":[]},{"id":"ba441257ae85d545","type":"ui_button","z":"0982b67c87526224","name":"","group":"35837a9dea40e7b4","order":2,"width":"1","height":"1","passthru":false,"label":"-","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"-1","payloadType":"num","topic":"topic","topicType":"msg","x":450,"y":220,"wires":[["b9da02470573233e"]]},{"id":"d0dd6b6b2858a6c4","type":"ui_button","z":"0982b67c87526224","name":"","group":"35837a9dea40e7b4","order":2,"width":"1","height":"1","passthru":false,"label":"+","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"+1","payloadType":"num","topic":"topic","topicType":"msg","x":450,"y":180,"wires":[["b9da02470573233e"]]},{"id":"b9da02470573233e","type":"function","z":"0982b67c87526224","name":"calcTargetTemp","func":"msg.payload = (flow.get('targetTemp') || 0) + msg.payload;\nflow.set('targetTemp', msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":200,"wires":[["e0b77f543347275d"]]},{"id":"07989680e14b979b","type":"function","z":"0982b67c87526224","name":"setTargetTemp","func":"flow.set('targetTemp', msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":140,"wires":[["e0b77f543347275d"]]},{"id":"35837a9dea40e7b4","type":"ui_group","name":"Default","tab":"f4725a966718a27d","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"f4725a966718a27d","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]

fellinga avatar Apr 16 '22 18:04 fellinga

Many thanks for your support. Really appreciated.

Comparing one event to other events in the list is therefore something that does not feel right. Also, if there is no second element in the list then things would become a little confusing, since I would have to choose to update always, or never.

I'm not really happy with this either, this is why I opened this request.

I know that this is not a direct solution to what you have been asking for but with the additional controls you can easily readjust the temperature after a timer change and it also provides an additional nice feature to your flow.

Nice one 👍 Unless I'm now missing something, this works perfectly for one event. My heating control works on a room basis, so I currently have 15 rooms with different events, according to its usage profiles, i.e. school time, weekend etc. In addition, I'm storing away the JSON output in an flow context array, so I can create different "profiles", e.g. a temp setting for all rooms in autumn, spring and winter.

Updating regularly currently means it sends an on signal (true) or an off signal (false) whether one of the schedules are currently active or not. I am not quite sure what I would need to send outside of schedules times then.. false, some fixed payload, nothing?

For my usage scenario, a combination of "default mode" and "event mode" would be perfect. I.e. being able to provide a custom value for each timer.

Sineos avatar Apr 17 '22 11:04 Sineos

Going to close this issue since a combination of "default mode" and "event mode" is not planned.

fellinga avatar Dec 30 '23 12:12 fellinga