Calculer les horaires ON/OFF

Bonjour à tous,

Je débute avec NodeRed. Je créé un flow qui se déclenche à 0h05 chaque jour pour calculer les horaires de mise en marche et d’arrêt de ma pompe de filtration. Ma question, une fois que j’ai calculé mes horaires, comment faire pour dire à HA de démarrer la filtration à 5h35 puis de l’éteindre à 8h35 par exemple ?

Merci d’avance.

Voici mon flow :

[
  {
    "id": "e54b160f.e9e4f8",
    "type": "tab",
    "label": "Piscine",
    "disabled": false,
    "info": ""
  },
  {
    "id": "5a9f229f.4501ac",
    "type": "inject",
    "z": "e54b160f.e9e4f8",
    "name": "Every day at 00:05",
    "props": [
      {
        "p": "payload"
      },
      {
        "p": "topic",
        "vt": "str"
      }
    ],
    "repeat": "",
    "crontab": "05 00 * * *",
    "once": false,
    "onceDelay": 0.1,
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "x": 160,
    "y": 100,
    "wires": [
      [
        "df7ae9c2.ee3e18"
      ]
    ]
  },
  {
    "id": "df7ae9c2.ee3e18",
    "type": "api-current-state",
    "z": "e54b160f.e9e4f8",
    "name": "",
    "server": "cfe85b65.cca4e8",
    "version": 1,
    "outputs": 1,
    "halt_if": "",
    "halt_if_type": "str",
    "halt_if_compare": "is",
    "override_topic": false,
    "entity_id": "input_number.pool_temperature",
    "state_type": "str",
    "state_location": "temperature",
    "override_payload": "msg",
    "entity_location": "",
    "override_data": "none",
    "blockInputOverrides": false,
    "x": 300,
    "y": 160,
    "wires": [
      [
        "e8e6c528.5d79d8"
      ]
    ]
  },
  {
    "id": "7cca0364.28ee2c",
    "type": "debug",
    "z": "e54b160f.e9e4f8",
    "name": "",
    "active": true,
    "tosidebar": true,
    "console": false,
    "tostatus": false,
    "complete": "true",
    "targetType": "full",
    "statusVal": "",
    "statusType": "auto",
    "x": 590,
    "y": 280,
    "wires": []
  },
  {
    "id": "36f45a3b.b5e726",
    "type": "function",
    "z": "e54b160f.e9e4f8",
    "name": "Compute Time Filtration",
    "func": "// Pour assurer un temps minimum de filtration la temperature de calcul est forcée a 10°C\nvar temperature = Math.max(10, msg.temperature);\n\n// Calcul de la durée de filtration suivant l'équation\nvar duration = Math.floor(((0.00335 * Math.pow(temperature, 3)) + (-0.14953 * Math.pow(temperature, 2)) + (2.43489 * temperature) - 10.72859) * 60);\n// La durée de filtration ne peux etre inférieure à 3h et supérieure à 14h\nduration = Math.min(Math.max(duration, 3*60), 14*60);\nmsg.duration = duration;\n\n// Par défaut, l'heure pivot est à 13h\nvar pivot = new Date();\npivot.setHours(13, 0, 0);\n// L'hiver, l'heure pivot est le levé du soleil\nif (msg.season == \"off\") {\n    // Trouver comment récupérer l'heure de levée du soleil\n\n}\n\n// On calcul les heures de début et de fin de filtration\nvar first_part = (msg.season == \"off\") ? 2/3 : 1/2;\nvar second_part = (msg.season == \"off\") ? 1/3 : 1/2;\nmsg.filtration_start = new Date(pivot.getTime() - duration * first_part * 60000);\nmsg.filtration_end = new Date(pivot.getTime() + duration * second_part * 60000);\n\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "x": 330,
    "y": 280,
    "wires": [
      [
        "7cca0364.28ee2c"
      ]
    ]
  },
  {
    "id": "1760779a.db8268",
    "type": "comment",
    "z": "e54b160f.e9e4f8",
    "name": "Calcul des horaires de filtration de la piscine",
    "info": "",
    "x": 210,
    "y": 60,
    "wires": []
  },
  {
    "id": "e8e6c528.5d79d8",
    "type": "api-current-state",
    "z": "e54b160f.e9e4f8",
    "name": "",
    "server": "cfe85b65.cca4e8",
    "version": 1,
    "outputs": 1,
    "halt_if": "",
    "halt_if_type": "str",
    "halt_if_compare": "is",
    "override_topic": false,
    "entity_id": "input_boolean.swimming_season",
    "state_type": "str",
    "state_location": "season",
    "override_payload": "msg",
    "entity_location": "",
    "override_data": "none",
    "blockInputOverrides": false,
    "x": 340,
    "y": 220,
    "wires": [
      [
        "36f45a3b.b5e726"
      ]
    ]
  },
  {
    "id": "cfe85b65.cca4e8",
    "type": "server",
    "name": "Home Assistant",
    "legacy": false,
    "addon": true,
    "rejectUnauthorizedCerts": true,
    "ha_boolean": "y|yes|true|on|home|open",
    "connectionDelay": true,
    "cacheJson": true
  }
]

Bonsoir Arnault,
Je stockerais les heures de démarrage et arrêt dans des variables global.
J’utiliserais ces heures avec le nod « time-inject » de la palette sun position pour les déclenchements.

Et une autre façon de faire avec cron-plus node-red-contrib-cron-plus (node) - Node-RED, le couteau suisse de la programmation temporelle sous nodered (soleil, cron, date…)

[{"id":"6efce329.92592c","type":"cronplus","z":"e54b160f.e9e4f8","name":"","outputField":"payload","timeZone":"","persistDynamic":false,"commandResponseMsgOutput":"output1","outputs":1,"options":[],"x":600,"y":280,"wires":[["afb4a66.e78da58"]]},{"id":"998a2878.73f558","type":"inject","z":"e54b160f.e9e4f8","name":"Get status-all","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"status-all","payload":"","payloadType":"date","x":410,"y":340,"wires":[["6efce329.92592c"]]},{"id":"36f45a3b.b5e726","type":"function","z":"e54b160f.e9e4f8","name":"Compute Time Filtration","func":"// Pour assurer un temps minimum de filtration la temperature de calcul est forcée a 10°C\nvar temperature = Math.max(10, msg.temperature);\n\n// Calcul de la durée de filtration suivant l'équation\nvar duration = Math.floor(((0.00335 * Math.pow(temperature, 3)) + (-0.14953 * Math.pow(temperature, 2)) + (2.43489 * temperature) - 10.72859) * 60);\n// La durée de filtration ne peux etre inférieure à 3h et supérieure à 14h\nduration = Math.min(Math.max(duration, 3*60), 14*60);\nmsg.duration = duration;\n\n// Par défaut, l'heure pivot est à 13h\nvar pivot = new Date();\npivot.setHours(13, 0, 0);\n// L'hiver, l'heure pivot est le levé du soleil\nif (msg.season == \"off\") {\n    // Trouver comment récupérer l'heure de levée du soleil\n\n}\n\n// On calcul les heures de début et de fin de filtration\nvar first_part = (msg.season == \"off\") ? 2/3 : 1/2;\nvar second_part = (msg.season == \"off\") ? 1/3 : 1/2;\nlet filtration_start = new Date(pivot.getTime() - duration * first_part * 60000 );\nlet filtration_end = new Date(pivot.getTime() + duration * second_part * 60000 );\n\nmsg.payload = [ {\n    \"command\":\"add\",\n    \"name\":\"DynamicStart\",\n    \"topic\":\"DynamicStart\",\n    \"payload\" : \"Start\",\n    \"expression\" : filtration_start,\n    \"type\":\"default\" \n} ,\n    {\n    \"command\":\"add\",\n    \"name\":\"DynamicEnd\",\n    \"topic\":\"DynamicEnd\",\n    \"payload\" : \"End\",\n    \"expression\" : filtration_end,\n    \"type\":\"default\" }\n    ]\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":370,"y":280,"wires":[["6efce329.92592c"]]},{"id":"c2fedc32.b2da2","type":"api-current-state","z":"e54b160f.e9e4f8","name":"","server":"cfe85b65.cca4e8","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_number.pool_temperature","state_type":"str","state_location":"temperature","override_payload":"msg","entity_location":"","override_data":"none","blockInputOverrides":false,"x":350,"y":160,"wires":[["87aa45ba.5769b8"]]},{"id":"87aa45ba.5769b8","type":"api-current-state","z":"e54b160f.e9e4f8","name":"","server":"cfe85b65.cca4e8","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.swimming_season","state_type":"str","state_location":"season","override_payload":"msg","entity_location":"","override_data":"none","blockInputOverrides":false,"x":390,"y":220,"wires":[["36f45a3b.b5e726"]]},{"id":"e64acc36.5b895","type":"cronplus","z":"e54b160f.e9e4f8","name":"","outputField":"payload","timeZone":"","persistDynamic":false,"commandResponseMsgOutput":"output1","outputs":1,"options":[{"name":"schedule1","topic":"schedule1","payloadType":"default","payload":"","expressionType":"cron","expression":"0 5 0 * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":200,"y":100,"wires":[["c2fedc32.b2da2"]]},{"id":"afb4a66.e78da58","type":"switch","z":"e54b160f.e9e4f8","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"start","vt":"str"},{"t":"eq","v":"end","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":750,"y":280,"wires":[["20a2f87d.ca2f58"],["dc04810c.f6b13"]]},{"id":"dc04810c.f6b13","type":"debug","z":"e54b160f.e9e4f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":930,"y":300,"wires":[]},{"id":"20a2f87d.ca2f58","type":"debug","z":"e54b160f.e9e4f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":930,"y":260,"wires":[]},{"id":"cfe85b65.cca4e8","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]
1 J'aime

Et j’ai vu que tu voulais aussi calculer la saison… Voilà un exemple (pas de moi).
A mettre dans une fonction.

const md = (month, day) => ({month, day})
const toMd = date => md(date.getMonth(), date.getDate())

const before = (md1, md2) => (md1.month < md2.month) 
  || ((md1.month === md2.month) && (md1.day <= md2.day)) 

const after = (md1, md2) => !before(md1, md2)

const between = (mdX, mdLow, mdHigh) => 
  after(mdX, mdLow) && before(mdX, mdHigh)
 
const season = (date, seasons) => ((md = toMd(date)) =>
  Object.keys(seasons).find(season => seasons[season](md))
)()

const MARCH_EQUINOX = md(2, 20)
const JUNE_SOLSTICE = md(5, 21)
const SEPTEMBER_EQUINOX = md(8, 23)
const DECEMBER_SOLSTICE = md(11, 21)
const NEW_YEAR = md(0, 1)

const seasons = {
  spring: d => between(d, MARCH_EQUINOX, JUNE_SOLSTICE),
  summer: d => between(d, JUNE_SOLSTICE, SEPTEMBER_EQUINOX),
  fall: d => between(d, SEPTEMBER_EQUINOX, DECEMBER_SOLSTICE),
  winter: d => 
    between(d, DECEMBER_SOLSTICE, NEW_YEAR) ||
    between(d, NEW_YEAR, MARCH_EQUINOX)
}

msg.payload = season(new Date(), seasons) 
  
return msg;

Merci pour vos réponses. J’ai commencé par installer node-red-contrib-sun-position afin de récupérer l’heure de levé du soleil qui me manquait. Ca marche bien mais il m’affiche une heure de moins que la véritable heure. Du coup comment faire pour avoir les bonnes horaires ?
Je pense que le problème est entre GMT et GMT+1 pour nous :thinking:

[{"id":"e54b160f.e9e4f8","type":"tab","label":"Piscine","disabled":false,"info":""},{"id":"5a9f229f.4501ac","type":"inject","z":"e54b160f.e9e4f8","name":"Every day at 00:05","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"05 00 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":100,"wires":[["df7ae9c2.ee3e18"]]},{"id":"df7ae9c2.ee3e18","type":"api-current-state","z":"e54b160f.e9e4f8","name":"","server":"cfe85b65.cca4e8","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_number.pool_temperature","state_type":"str","state_location":"temperature","override_payload":"msg","entity_location":"","override_data":"none","blockInputOverrides":false,"x":460,"y":100,"wires":[["e8e6c528.5d79d8"]]},{"id":"7cca0364.28ee2c","type":"debug","z":"e54b160f.e9e4f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.startTime","targetType":"msg","statusVal":"","statusType":"auto","x":700,"y":200,"wires":[]},{"id":"36f45a3b.b5e726","type":"function","z":"e54b160f.e9e4f8","name":"Compute Time Filtration","func":"// Pour assurer un temps minimum de filtration la temperature de calcul est forcée a 10°C\nvar temperature = Math.max(10, msg.temperature);\n\n// Calcul de la durée de filtration suivant l'équation\nvar duration = Math.floor(((0.00335 * Math.pow(temperature, 3)) + (-0.14953 * Math.pow(temperature, 2)) + (2.43489 * temperature) - 10.72859) * 60);\n// La durée de filtration ne peux etre inférieure à 3h et supérieure à 14h\nduration = Math.min(Math.max(duration, 3*60), 14*60);\nmsg.duration = duration;\n\n// On calcul les heures de début et de fin de filtration\nmsg.offset = {};\nmsg.offset.first_part = Math.floor(-duration * ((msg.season == \"off\") ? 2/3 : 1/2));\nmsg.offset.second_part = Math.floor(duration * ((msg.season == \"off\") ? 1/3 : 1/2));\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":230,"y":160,"wires":[["aa977ce.9e0bc8"]]},{"id":"1760779a.db8268","type":"comment","z":"e54b160f.e9e4f8","name":"Calcul des horaires de filtration de la piscine","info":"","x":210,"y":60,"wires":[]},{"id":"e8e6c528.5d79d8","type":"api-current-state","z":"e54b160f.e9e4f8","name":"","server":"cfe85b65.cca4e8","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.swimming_season","state_type":"str","state_location":"season","override_payload":"msg","entity_location":"","override_data":"none","blockInputOverrides":false,"x":860,"y":100,"wires":[["36f45a3b.b5e726"]]},{"id":"aa977ce.9e0bc8","type":"switch","z":"e54b160f.e9e4f8","name":"Is summer ?","property":"season","propertyType":"msg","rules":[{"t":"eq","v":"off","vt":"str"},{"t":"eq","v":"on","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":270,"y":220,"wires":[["bc2fa06c.a5c91"],["5eb8b825.6963a8"]]},{"id":"bc2fa06c.a5c91","type":"sun-position","z":"e54b160f.e9e4f8","name":"Sunrise","positionConfig":"10b1e3a7.2edf0c","rules":[],"onlyOnChange":"true","topic":"","outputs":1,"start":"sunriseStart","startType":"pdsTime","startOffset":"offset.first_part","startOffsetType":"msg","startOffsetMultiplier":60000,"end":"sunriseStart","endType":"pdsTime","endOffset":"offset.second_part","endOffsetType":"msg","endOffsetMultiplier":60000,"x":440,"y":200,"wires":[["7cca0364.28ee2c","f0fe6e43.917df"]]},{"id":"5eb8b825.6963a8","type":"sun-position","z":"e54b160f.e9e4f8","name":"13h00","positionConfig":"10b1e3a7.2edf0c","rules":[],"onlyOnChange":"true","topic":"","outputs":1,"start":"13:00","startType":"entered","startOffset":"offset.first_part","startOffsetType":"msg","startOffsetMultiplier":60000,"end":"13:00","endType":"entered","endOffset":"offset.second_part","endOffsetType":"msg","endOffsetMultiplier":60000,"x":430,"y":240,"wires":[["7cca0364.28ee2c","f0fe6e43.917df"]]},{"id":"f0fe6e43.917df","type":"debug","z":"e54b160f.e9e4f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload.endTime","targetType":"msg","statusVal":"","statusType":"auto","x":700,"y":240,"wires":[]},{"id":"cfe85b65.cca4e8","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true},{"id":"10b1e3a7.2edf0c","type":"position-config","name":"Pomponne","isValide":"true","longitude":"0","latitude":"0","angleType":"deg","timeZoneOffset":"99","timeZoneDST":"0","stateTimeFormat":"3","stateDateFormat":"12"}]

@golfvert , je vais essayé ensuite d’utiliser le cron que tu m’as partagé pour gérer l’allumage et l’extinction de ma pompe. Merci également pour la fonction permettant de calculer la saison, mais dans mon cas c’est fait manuellement : soit la piscine est en hivernage, soit elle est en mode été et c’est moi qui change manuellement cette info qui j’hiberne ou déshiberne la piscine.

Si tu décides d’utiliser cron plus, les événements solaires sont également gérés et correctement pour la timezone.

1 J'aime

Je viens de tester avec cron plus et il me dit aussi 6h30 au lieu de 7h30

[{"id":"8d0ea7ff.21acb8","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"b1500fae.b2e75","type":"cronplus","z":"8d0ea7ff.21acb8","name":"Sunrise","outputField":"payload","timeZone":"","persistDynamic":false,"commandResponseMsgOutput":"output1","outputs":1,"options":[{"name":"schedule1","topic":"schedule1","payloadType":"default","payload":"","expressionType":"solar","expression":"0 * * * * * *","location":"48.884549726083776 2.6959588564932346","offset":"0","solarType":"selected","solarEvents":"sunrise"}],"x":240,"y":260,"wires":[["6c39b46c.9df27c"]]},{"id":"6c39b46c.9df27c","type":"debug","z":"8d0ea7ff.21acb8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":860,"y":160,"wires":[]}]

Tu peux faire une copie d’écran ?
Je pense que l’heure est bonne mais le format te mets en erreur.
Pour info ,il est actuellement 13h32 et pourtant en GMT il est 12H32.Et c’est normal.
image

Sous le noeud Sunrise, il affiche bien 7h28 mais dans le debug nextDate est à 6h28 :

nextDate avec Z à la fin pour Zoulou, c’est l’heure GMT.
nextDateTZ avec la timezone GMT+1 qui est celle de la France, c’est l’heure locale.
Demain matin, ça se déclenchera à la « bonne » heure. 7:28:44.

2 J'aime

Plus rapide que moi mais Trés Bien expliqué. :+1:
Arnault, c’est juste une confusion due au format d’heure différent.
subflow1

1 J'aime

Ok, merci à vous deux, j’essai de mettre en place mon automatisation maintenant :pray:

Bonsoir,

J’ai bien bien galérer à comprendre comment faire fonctionner le CRON mais je m’en suis sorti. Merci à vous deux pour vos conseils.

[{"id":"e54b160f.e9e4f8","type":"tab","label":"Piscine","disabled":false,"info":""},{"id":"5a9f229f.4501ac","type":"inject","z":"e54b160f.e9e4f8","name":"Chaque jour à 00:05","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"05 00 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":180,"y":100,"wires":[["df7ae9c2.ee3e18","846aabe8.4aac38"]]},{"id":"df7ae9c2.ee3e18","type":"api-current-state","z":"e54b160f.e9e4f8","name":"Récupération de la T° de l'eau","server":"cfe85b65.cca4e8","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_number.pool_temperature","state_type":"str","state_location":"temperature","override_payload":"msg","entity_location":"","override_data":"none","blockInputOverrides":false,"x":250,"y":160,"wires":[["e8e6c528.5d79d8"]]},{"id":"36f45a3b.b5e726","type":"function","z":"e54b160f.e9e4f8","name":"Calcul du temps de filtration","func":"// Pour assurer un temps minimum de filtration la temperature de calcul est forcée a 10°C\nvar temperature = Math.max(10, msg.temperature);\n\n// Calcul de la durée de filtration suivant l'équation\nvar duration = Math.floor(((0.00335 * Math.pow(temperature, 3)) + (-0.14953 * Math.pow(temperature, 2)) + (2.43489 * temperature) - 10.72859) * 60);\n// La durée de filtration ne peux etre inférieure à 3h et supérieure à 14h\nduration = Math.min(Math.max(duration, 3*60), 14*60);\nmsg.duration = duration;\n\n// On calcul les heures de début et de fin de filtration\nmsg.offset = {};\nmsg.offset.start = Math.floor(-duration * ((msg.season == \"off\") ? 2/3 : 1/2));\nmsg.offset.end = Math.floor(duration * ((msg.season == \"off\") ? 1/3 : 1/2));\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":240,"y":280,"wires":[["aa977ce.9e0bc8"]]},{"id":"1760779a.db8268","type":"comment","z":"e54b160f.e9e4f8","name":"Calcul des horaires de filtration et de nettoyage de la piscine","info":"","x":260,"y":60,"wires":[]},{"id":"e8e6c528.5d79d8","type":"api-current-state","z":"e54b160f.e9e4f8","name":"Récupération de la saison","server":"cfe85b65.cca4e8","version":1,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","override_topic":false,"entity_id":"input_boolean.swimming_season","state_type":"str","state_location":"season","override_payload":"msg","entity_location":"","override_data":"none","blockInputOverrides":false,"x":230,"y":220,"wires":[["36f45a3b.b5e726"]]},{"id":"aa977ce.9e0bc8","type":"switch","z":"e54b160f.e9e4f8","name":"Est ce l'été ?","property":"season","propertyType":"msg","rules":[{"t":"eq","v":"off","vt":"str"},{"t":"eq","v":"on","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":190,"y":360,"wires":[["7115b4c3.b1ed0c"],["22e50bc0.c54c44"]]},{"id":"ed2007a4.083a68","type":"cronplus","z":"e54b160f.e9e4f8","name":"CRON","outputField":"payload","timeZone":"","persistDynamic":false,"commandResponseMsgOutput":"output1","outputs":1,"options":[],"x":630,"y":240,"wires":[["23421ff0.35042","e016296b.35ad38","6ec13a00.431f98"]]},{"id":"846aabe8.4aac38","type":"function","z":"e54b160f.e9e4f8","name":"Effacer les tâches","func":"msg.payload = {\n    \"command\": \"remove-all\"\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":410,"y":100,"wires":[["ed2007a4.083a68"]]},{"id":"23421ff0.35042","type":"debug","z":"e54b160f.e9e4f8","name":"Debug Ordonnanceur","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":860,"y":420,"wires":[]},{"id":"7115b4c3.b1ed0c","type":"function","z":"e54b160f.e9e4f8","name":"Ajout tâches d'hiver","func":"// On initialise notre liste de taches\nmsg.payload = [];\n\n// On ajout le CRON de démarrage de la piscine\nmsg.payload.push({\n    \"command\": \"add\",\n    \"topic\": \"start_filtration\",\n    \"name\": \"start_filtration\",\n    \"payloadType\": \"default\",\n    \"payload\": \"payload\",\n    \"type\": \"default\",\n    \"expressionType\": \"solar\",\n    \"solarType\": \"selected\",\n    \"solarEvents\": \"sunrise\",\n    \"location\": \"48.884544434795146 2.695956928655505\",\n    \"offset\": msg.offset.start\n});\n\n// On ajoute le CRON d'arrêt de la piscine\nmsg.payload.push({\n    \"command\": \"add\",\n    \"topic\": \"stop_filtration\",\n    \"name\": \"stop_filtration\",\n    \"payloadType\": \"default\",\n    \"payload\": \"payload\",\n    \"type\": \"default\",\n    \"expressionType\": \"solar\",\n    \"solarType\": \"selected\",\n    \"solarEvents\": \"sunrise\",\n    \"location\": \"48.884544434795146 2.695956928655505\",\n    \"offset\": msg.offset.end\n});\n\n// Affichage des tâches plannifiée\nmsg.payload.push({\n    \"command\": \"list-all\",\n});\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400,"y":340,"wires":[["ed2007a4.083a68"]]},{"id":"22e50bc0.c54c44","type":"function","z":"e54b160f.e9e4f8","name":"Ajout tâches d'été","func":"// On initialise notre liste de taches\nmsg.payload = [];\n\n// On défini l'heure pivot\nvar pivot = new Date();\npivot.setHours(13, 0, 0, 0);\n\n// On calcul l'heure au format CRON de la mise en marche de la piscine\nvar startTime = new Date(pivot.getTime() + msg.offset.start * 60000);\nvar cronStart = startTime.getSeconds() + \" \" + startTime.getMinutes() + \" \" +  startTime.getHours() + \" * * * *\";\n\n// On calcul l'heure au format CRON de l'arret de la piscine\nvar endTime = new Date(pivot.getTime() + msg.offset.end * 60000);\nvar cronEnd = endTime.getSeconds() + \" \" + endTime.getMinutes() + \" \" +  endTime.getHours() + \" * * * *\";\n\n// On calcul l'heure au format CRON de l'arret de la piscine\nvar endTimeRobot = new Date(pivot.getTime() + (msg.offset.start + 150) * 60000);\nvar cronEndRobot = endTimeRobot.getSeconds() + \" \" + endTimeRobot.getMinutes() + \" \" +  endTimeRobot.getHours() + \" * * * *\";\n\n// On ajout le CRON de démarrage de la piscine\nmsg.payload.push({\n    \"command\": \"add\",\n    \"topic\": \"start_filtration\",\n    \"name\": \"start_filtration\",\n    \"payloadType\": \"default\",\n    \"payload\": \"payload\",\n    \"type\": \"default\",\n    \"expressionType\": \"cron\",\n    \"expression\": cronStart\n});\n\n// On ajoute le CRON d'arrêt de la piscine\nmsg.payload.push({\n    \"command\": \"add\",\n    \"topic\": \"stop_filtration\",\n    \"name\": \"stop_filtration\",\n    \"payloadType\": \"default\",\n    \"payload\": \"payload\",\n    \"type\": \"default\",\n    \"expressionType\": \"cron\",\n    \"expression\": cronEnd\n});\n\n// On ajout le CRON de démarrage du robot de piscine\nmsg.payload.push({\n    \"command\": \"add\",\n    \"topic\": \"start_robot\",\n    \"name\": \"start_robot\",\n    \"payloadType\": \"default\",\n    \"payload\": \"payload\",\n    \"type\": \"default\",\n    \"expressionType\": \"cron\",\n    \"expression\": cronStart\n});\n\n// On ajout le CRON d'arret du robot de piscine\nmsg.payload.push({\n    \"command\": \"add\",\n    \"topic\": \"stop_robot\",\n    \"name\": \"stop_robot\",\n    \"payloadType\": \"default\",\n    \"payload\": \"payload\",\n    \"type\": \"default\",\n    \"expressionType\": \"cron\",\n    \"expression\": cronEndRobot\n});\n\n// Affichage des tâches plannifiée\nmsg.payload.push({\n    \"command\": \"list-all\",\n});\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":410,"y":380,"wires":[["ed2007a4.083a68"]]},{"id":"e016296b.35ad38","type":"switch","z":"e54b160f.e9e4f8","name":"Commandes","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"start_filtration","vt":"str"},{"t":"eq","v":"stop_filtration","vt":"str"},{"t":"eq","v":"start_robot","vt":"str"},{"t":"eq","v":"stop_robot","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":830,"y":160,"wires":[["726902af.ecba0c"],["54b1762b.de7c18"],["44b21d05.9e9bb4"],["f20641b1.71883"]]},{"id":"726902af.ecba0c","type":"api-call-service","z":"e54b160f.e9e4f8","name":"Start Filtration","server":"cfe85b65.cca4e8","version":1,"debugenabled":false,"service_domain":"automation","service":"turn_on","entityId":"switch.piscine_filtration","data":"","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1020,"y":100,"wires":[[]]},{"id":"54b1762b.de7c18","type":"api-call-service","z":"e54b160f.e9e4f8","name":"Stop Filtration","server":"cfe85b65.cca4e8","version":1,"debugenabled":false,"service_domain":"automation","service":"turn_off","entityId":"switch.piscine_filtration","data":"","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1020,"y":140,"wires":[[]]},{"id":"44b21d05.9e9bb4","type":"api-call-service","z":"e54b160f.e9e4f8","name":"Start Robot","server":"cfe85b65.cca4e8","version":1,"debugenabled":false,"service_domain":"automation","service":"turn_on","entityId":"switch.piscine_surpresseur","data":"","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1010,"y":180,"wires":[[]]},{"id":"f20641b1.71883","type":"api-call-service","z":"e54b160f.e9e4f8","name":"Stop Robot","server":"cfe85b65.cca4e8","version":1,"debugenabled":false,"service_domain":"automation","service":"turn_off","entityId":"switch.piscine_surpresseur","data":"","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1010,"y":220,"wires":[[]]},{"id":"7833840c.33350c","type":"comment","z":"e54b160f.e9e4f8","name":"Changer la saison de la piscine","info":"","x":170,"y":560,"wires":[]},{"id":"3096bc3a.7299e4","type":"inject","z":"e54b160f.e9e4f8","name":"Eté","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":130,"y":600,"wires":[["a0d71e43.6bef4"]]},{"id":"ae0e7895.c95948","type":"inject","z":"e54b160f.e9e4f8","name":"Hiver","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"false","payloadType":"bool","x":130,"y":640,"wires":[["743bb49.595014c"]]},{"id":"743bb49.595014c","type":"api-call-service","z":"e54b160f.e9e4f8","name":"Passage en mode : Hivernage","server":"cfe85b65.cca4e8","version":1,"debugenabled":true,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.swimming_season","data":"","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":350,"y":640,"wires":[[]]},{"id":"a0d71e43.6bef4","type":"api-call-service","z":"e54b160f.e9e4f8","name":"Passage en mode : Eté","server":"cfe85b65.cca4e8","version":1,"debugenabled":true,"service_domain":"input_boolean","service":"turn_on","entityId":"input_boolean.swimming_season","data":"","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":330,"y":600,"wires":[[]]},{"id":"b608ed80.ad76e","type":"inject","z":"e54b160f.e9e4f8","name":"Récupérer la liste des taches plannifiées","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"list-all","payload":"","payloadType":"date","x":340,"y":440,"wires":[["ed2007a4.083a68"]]},{"id":"6ec13a00.431f98","type":"switch","z":"e54b160f.e9e4f8","name":"Liste des tâches ?","property":"payload.command.command","propertyType":"msg","rules":[{"t":"eq","v":"list-all","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":850,"y":280,"wires":[["92d75f07.26dc7"]]},{"id":"d98bc806.e95ab8","type":"api-call-service","z":"e54b160f.e9e4f8","name":"MAJ Texte Heures Filtration","server":"cfe85b65.cca4e8","version":1,"debugenabled":false,"service_domain":"input_text","service":"set_value","entityId":"input_text.pool_pump_hours","data":"{\"value\":msg.payload}","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":980,"y":360,"wires":[[]]},{"id":"92d75f07.26dc7","type":"function","z":"e54b160f.e9e4f8","name":"Récupération heures","func":"var start = new Date(msg.payload.result.filter(elm => elm.config.name == \"start_filtration\").pop().status.nextDateTZ)\nvar end = new Date(msg.payload.result.filter(elm => elm.config.name == \"stop_filtration\").pop().status.nextDateTZ)\nmsg.payload = \"De \" + start.getHours() + \"h\" + (start.getMinutes() < 10 ? \"0\": \"\") + start.getMinutes() + \" à \" + end.getHours() + \"h\" + (end.getMinutes() < 10 ? \"0\": \"\") + end.getMinutes();\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":920,"y":320,"wires":[["d98bc806.e95ab8"]]},{"id":"cfe85b65.cca4e8","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]

Pas de quoi…
Juste un détail, à 00:05 tu lances en parallèle la suppression des tâches de la veille et tu mets en place celle du jour. Il n’y a rien dans nodered qui te garantit que l’effacement sera fait avant l’ajout. C’est vrai qu’intuitivement on peut se dire, le flot est plus long donc c’est ce qui va se passer. C’est une « Race condition » Race condition - Wikipedia
Et donc, un jour de pas de bol, ça pourrait effacer des entrée nouvellement créés Il vaudrait mieux lancer la suppression quelques minutes plus tôt et séparer les deux flux. Tu seras sûr que l’un sera toujours fait avant l’autre. Avec cron, c’est facile :wink:

1 J'aime

Merci beaucoup pour le conseil, je vais le mettre en application de suite

Il n’y a pas la possibilité de faire une pause d’une minute dans le flow ?

Oui, ça marche aussi. Avec un noeud « delai ».

1 J'aime

Un énorme merci car j’ai pu réaliser entièrement ma première automatisation avec Node-RED grâce à vous :heart_eyes:

2 J'aime

Pour une première, c’est déjà du lourd :slight_smile:

1 J'aime

Bonjour @golfvert ,

J’ai une petite question en tête que j’aimerais te poser. Si lors du ON ou du OFF via le cron, le micromodule n’est pas joignable à ce moment là. Que vas t il ce passer ? En gros faut’il rajouter un cron toutes les 5’ pour vérifier si l’état ON/OFF est correct ?

Merci