Forum Francophone Home Assistant

Gestion des horaires de chauffage avec Schedy

Ce qui est bien est parfois un peu compliqué à appréhender. Et c’est le cas de Shedy. En plus la prise en compte des modifs yaml sous AppDaemon est dynamique et c’est top. La philosophie yaml reste identique à HA. Je me sert aussi de ControlerX qui est sous AppDaemon.

Il y a aussi le scheduler très bien qui est ici https://community.home-assistant.io/t/scheduler-card-custom-component/ qui devrait être suffisant dans la majorité des cas.

Quant à NR, la réponse est non, c’est pas juste que je n’aime pas, je déteste. Bon, blague à part, c’est bien et même intéressant, surtout pour ceux qui ne réussissent pas à entrer dans la logique yaml, ce qui se comprends très bien. Mais dans l’absolu ça n’a pas besoin de HA, à part pour l’interface, ah oui NR n’a pas d’interface utilisateur, juste une interface dev. Bon, après chacun son truc.

Il y a aussi les Blueprint, et ça va changer bcp de choses sous HA je crois.

Bref, dans toutes ces solutions, seul Shedy sait faire de la replanification dynamique, c-a-d que toutes les x minutes il reconsidère l’état des lieux et agit en fonction. Les autres se contentent de faire ON au début et OFF à la fin (ou augmenter la consigne et la baisser).

Au printemps dernier je n’avais pas pris le temps de vraiment creuser Schedy, mais je vais peut être reconsidérer, au moins pour expliquer et écrire un article. Après le manque d’interface est cruel !

Joyeuses fêtes!

Bonjour,

Merci pour ton partage d’expérience @pyg
Je suis également fan de Node Red, mais comme l’indique @Canaletto je crois que les blueprint vont être une très bonne alternative. J’ai vaguement regardé et cela s’annonce pas mal dutout.
La notion de partage sur le même principe que ce que propose Node Red est un grand plus et vu que je suis partisan dès que possible d’utiliser les fonctions les plus proche du Core pour des raisons de maintenabilité entre les versions et bien je vais essayer de migrer vers les Blueprint.

J’ai un peu creusé Schedy qui me plait de plus en plus, et j’ai essayé de lui offrir une interface… (si tu te lasses de NR :wink:

2 J'aimes

Bonjour,
Merci pour ton « ping » et ton article. Tu as réussi à raviver la flamme Schedy :wink:
Malgré son côté austère, il a de nombreux avantages : robuste/stable, les fautes de syntaxe sont faciles à identifier, logs bien détaillés pour comprendre les décisions prise, ré-envoi en cas d’échec de prise en compte des commandes, gestion des réglables manuels et reprise du « scheduling » après un certain délai.

Merci pour tes astuces: 1) externaliser les variables de Schedy, 2) fichiers de variables dans /config/packages/*.yaml, 3) typages de variables pour créer une interface facilement dans Lovelace.

  • Variables Home Assistant

OK ça fait beaucoup de variables (booléen, début, fin, templates, …) mais ça se génère bien à coup de script.

Exemple pour 3 pièces et 4 planifications par pièces
/bin/bash
test -d /config/packages || mkdir /config/packages
cd /config/packages
cat >heating_global.yaml<<EOF
input_boolean:
  heating_enabled:
    name: Heating Global
    icon: mdi:toggle-switch
EOF
for room in bureau sdb_rdc sdb_1er
do
for period in {1..4}
do
cat >${room}_heating_period_${period}.yaml<<EOF
input_datetime:
  ${room}_heating_period_${period}_start:
    name: "Heating Period ${period} Start Time"
    has_date: false
    has_time: true
  ${room}_heating_period_${period}_end:
    name: "Heating Period ${period} End Time"
    has_date: false
    has_time: true
sensor:
  platform: template
  sensors:
    ${room}_heating_period_${period}_start:
      value_template: "{{ (state_attr('input_datetime.${room}_heating_period_${period}_start', 'timestamp') / 60)|int }}"
    ${room}_heating_period_${period}_end:
      value_template: "{{ (state_attr('input_datetime.${room}_heating_period_${period}_end', 'timestamp') / 60)|int }}"
input_number:
  ${room}_heating_period_${period}_temperature:
    name: Heating Period ${period} Temperature
    min: 18
    max: 25
    step: 1
    unit_of_measurement: °C
input_boolean:
  ${room}_heating_period_${period}:
    name: Heating Period ${period} Enabled
    icon: mdi:toggle-switch
EOF
done
done
exit

Puis tester la configuration « check configuration » et recharger les éléments nécessaire:
« reload input booleans »
« reload input date times »
« reload input numbers »
« reload templates entities »

  • Application Schedy
/config/appdaemon/apps/schedy_heating.yaml
schedy_heating:
  module: hass_apps_loader
  class: SchedyApp
  
  actor_type: thermostat
  
  actor_templates:
    default:
      send_retry_interval: 30
      send_retries: 10
      supports_hvac_modes: false
    danfoss:
      template: default
      send_retry_interval: 60
      supports_hvac_modes: false
      off_temp: 18
  
  watched_entities:
  - input_boolean.homeoffice
  - binary_sensor.workday_sensor
  - binary_sensor.holiday_sensor
  - input_boolean.heating_enabled
  
  expression_environment: |
    def homeoffice():
      return is_on("input_boolean.homeoffice")
    def workday():
      return is_on("binary_sensor.workday_sensor")
    def holiday():
      return is_on("binary_sensor.holiday_sensor")
    def time_between(start, end):
        start = int(state(start))
        end = int(state(end))
        current = time.hour * 60 + time.minute + 1
        if start >= end:
            return current >= start or current < end
        return current >= start and current < end

  schedule_prepend:
  - x: "14 if is_off('input_boolean.heating_enabled') else Next()"
  
  rooms:
    bureau:
      allow_manual_changes: true
      rescheduling_delay: 120
      actors:
        climate.danfoss_heating:
          template: danfoss
      watched_entities:
      - input_number.bureau_heating_period_1_temperature
      - input_boolean.bureau_heating_period_1
      - sensor.bureau_heating_period_1_start
      - sensor.bureau_heating_period_1_end
      - input_number.bureau_heating_period_2_temperature
      - input_boolean.bureau_heating_period_2
      - sensor.bureau_heating_period_2_start
      - sensor.bureau_heating_period_2_end
      - input_number.bureau_heating_period_3_temperature
      - input_boolean.bureau_heating_period_3
      - sensor.bureau_heating_period_3_start
      - sensor.bureau_heating_period_3_end
      - input_number.bureau_heating_period_4_temperature
      - input_boolean.bureau_heating_period_4
      - sensor.bureau_heating_period_4_start
      - sensor.bureau_heating_period_4_end
      schedule:
      - rules:
        # not homeoffice
        - rules:
          - x: "Break() if homeoffice() else Next()"
          - x: >
              state("input_number.bureau_heating_period_1_temperature")
              if (is_on("input_boolean.bureau_heating_period_1")
              and time_between("sensor.bureau_heating_period_1_start", "sensor.bureau_heating_period_1_end"))
              else Next()
          - x: >
              state("input_number.bureau_heating_period_2_temperature")
              if (is_on("input_boolean.bureau_heating_period_2")
              and time_between("sensor.bureau_heating_period_2_start", "sensor.bureau_heating_period_2_end"))
              else Next()
          - x: "Break(2)"
        # homeoffice
        - rules:
          - x: >
              state("input_number.bureau_heating_period_3_temperature")
              if (is_on("input_boolean.bureau_heating_period_3")
              and time_between("sensor.bureau_heating_period_3_start", "sensor.bureau_heating_period_3_end"))
              else Next()
          - x: >
              state("input_number.bureau_heating_period_4_temperature")
              if (is_on("input_boolean.bureau_heating_period_4")
              and time_between("sensor.bureau_heating_period_4_start", "sensor.bureau_heating_period_4_end"))
              else Next()
          - x: "Break(2)"
      # default
      - v: 20
    sdb_rdc:
      allow_manual_changes: true
      replicate_changes: true
      rescheduling_delay: 30
      actors:
        climate.fgt001_fenetre_sdb_rdc:
        climate.fgt001_serviettes_sdb_rdc:
      watched_entities:
      - input_number.sdb_rdc_heating_period_1_temperature
      - input_boolean.sdb_rdc_heating_period_1
      - sensor.sdb_rdc_heating_period_1_start
      - sensor.sdb_rdc_heating_period_1_end
      - input_number.sdb_rdc_heating_period_2_temperature
      - input_boolean.sdb_rdc_heating_period_2
      - sensor.sdb_rdc_heating_period_2_start
      - sensor.sdb_rdc_heating_period_2_end
      - input_number.sdb_rdc_heating_period_3_temperature
      - input_boolean.sdb_rdc_heating_period_3
      - sensor.sdb_rdc_heating_period_3_start
      - sensor.sdb_rdc_heating_period_3_end
      - input_number.sdb_rdc_heating_period_4_temperature
      - input_boolean.sdb_rdc_heating_period_4
      - sensor.sdb_rdc_heating_period_4_start
      - sensor.sdb_rdc_heating_period_4_end
      schedule:
      - rules:
        # workday
        - rules:
          - x: "Break() if workday() else Next()"
          - x: >
              state("input_number.sdb_rdc_heating_period_1_temperature")
              if (is_on("input_boolean.sdb_rdc_heating_period_1")
              and time_between("sensor.sdb_rdc_heating_period_1_start", "sensor.sdb_rdc_heating_period_1_end"))
              else Next()
          - x: >
              state("input_number.sdb_rdc_heating_period_2_temperature")
              if (is_on("input_boolean.sdb_rdc_heating_period_2")
              and time_between("sensor.sdb_rdc_heating_period_2_start", "sensor.sdb_rdc_heating_period_2_end"))
              else Next()
          - x: "Break(2)"
        # not workday
        - rules:
          - x: >
              state("input_number.sdb_rdc_heating_period_3_temperature")
              if (is_on("input_boolean.sdb_rdc_heating_period_3")
              and time_between("sensor.sdb_rdc_heating_period_3_start", "sensor.sdb_rdc_heating_period_3_end"))
              else Next()
          - x: >
              state("input_number.sdb_rdc_heating_period_4_temperature")
              if (is_on("input_boolean.sdb_rdc_heating_period_4")
              and time_between("sensor.sdb_rdc_heating_period_4_start", "sensor.sdb_rdc_heating_period_4_end"))
              else Next()
          - x: "Break(2)"
      # default
      - v: 21
    sdb_1er:
      allow_manual_changes: true
      replicate_changes: true
      rescheduling_delay: 30
      actors:
        climate.fgt001_fenetre_sdb_1er:
        climate.fgt001_serviettes_sdb_1er:
      watched_entities:
      - input_number.sdb_1er_heating_period_1_temperature
      - input_boolean.sdb_1er_heating_period_1
      - sensor.sdb_1er_heating_period_1_start
      - sensor.sdb_1er_heating_period_1_end
      - input_number.sdb_1er_heating_period_2_temperature
      - input_boolean.sdb_1er_heating_period_2
      - sensor.sdb_1er_heating_period_2_start
      - sensor.sdb_1er_heating_period_2_end
      - input_number.sdb_1er_heating_period_3_temperature
      - input_boolean.sdb_1er_heating_period_3
      - sensor.sdb_1er_heating_period_3_start
      - sensor.sdb_1er_heating_period_3_end
      - input_number.sdb_1er_heating_period_4_temperature
      - input_boolean.sdb_1er_heating_period_4
      - sensor.sdb_1er_heating_period_4_start
      - sensor.sdb_1er_heating_period_4_end
      schedule:
      - rules:
        # workday
        - rules:
          - x: "Break() if workday() else Next()"
          - x: >
              state("input_number.sdb_1er_heating_period_1_temperature")
              if (is_on("input_boolean.sdb_1er_heating_period_1")
              and time_between("sensor.sdb_1er_heating_period_1_start", "sensor.sdb_1er_heating_period_1_end"))
              else Next()
          - x: >
              state("input_number.sdb_1er_heating_period_2_temperature")
              if (is_on("input_boolean.sdb_1er_heating_period_2")
              and time_between("sensor.sdb_1er_heating_period_2_start", "sensor.sdb_1er_heating_period_2_end"))
              else Next()
          - x: "Break(2)"
        # not workday
        - rules:
          - x: >
              state("input_number.sdb_1er_heating_period_3_temperature")
              if (is_on("input_boolean.sdb_1er_heating_period_3")
              and time_between("sensor.sdb_1er_heating_period_3_start", "sensor.sdb_1er_heating_period_3_end"))
              else Next()
          - x: >
              state("input_number.sdb_1er_heating_period_4_temperature")
              if (is_on("input_boolean.sdb_1er_heating_period_4")
              and time_between("sensor.sdb_1er_heating_period_4_start", "sensor.sdb_1er_heating_period_4_end"))
              else Next()
          - x: "Break(2)"
      # default
      - v: 21
  • View Lovelace
Exemple basic mais fonctionnel
type: grid
columns: 3
square: true
cards:
  - type: vertical-stack
    cards:
      - type: entities
        entities:
          - entity: input_boolean.sdb_rdc_heating_period_3
          - entity: input_datetime.sdb_rdc_heating_period_3_start
          - entity: input_datetime.sdb_rdc_heating_period_3_end
          - entity: input_number.sdb_rdc_heating_period_3_temperature
          - entity: input_boolean.sdb_rdc_heating_period_4
          - entity: input_datetime.sdb_rdc_heating_period_4_start
          - entity: input_datetime.sdb_rdc_heating_period_4_end
          - entity: input_number.sdb_rdc_heating_period_4_temperature
        title: SDB RDC Workdays
        show_header_toggle: false
      - type: entities
        entities:
          - entity: input_boolean.sdb_rdc_heating_period_1
          - entity: input_datetime.sdb_rdc_heating_period_1_start
          - entity: input_datetime.sdb_rdc_heating_period_1_end
          - entity: input_number.sdb_rdc_heating_period_1_temperature
          - entity: input_boolean.sdb_rdc_heating_period_2
          - entity: input_datetime.sdb_rdc_heating_period_2_start
          - entity: input_datetime.sdb_rdc_heating_period_2_end
          - entity: input_number.sdb_rdc_heating_period_2_temperature
        title: SDB RDC Not-workdays
        show_header_toggle: false
      - type: button
        name: Reset Schedy for SDB RDC
        show_state: false
        tap_action:
          action: call-service
          service: script.schedy_reevaluate
          service_data:
            room: sdb_rdc
  - type: vertical-stack
    cards:
      - type: entities
        entities:
          - entity: input_boolean.sdb_1er_heating_period_3
          - entity: input_datetime.sdb_1er_heating_period_3_start
          - entity: input_datetime.sdb_1er_heating_period_3_end
          - entity: input_number.sdb_1er_heating_period_3_temperature
          - entity: input_boolean.sdb_1er_heating_period_4
          - entity: input_datetime.sdb_1er_heating_period_4_start
          - entity: input_datetime.sdb_1er_heating_period_4_end
          - entity: input_number.sdb_1er_heating_period_4_temperature
        title: SDB 1er Workdays
        show_header_toggle: false
      - type: entities
        entities:
          - entity: input_boolean.sdb_1er_heating_period_1
          - entity: input_datetime.sdb_1er_heating_period_1_start
          - entity: input_datetime.sdb_1er_heating_period_1_end
          - entity: input_number.sdb_1er_heating_period_1_temperature
          - entity: input_boolean.sdb_1er_heating_period_2
          - entity: input_datetime.sdb_1er_heating_period_2_start
          - entity: input_datetime.sdb_1er_heating_period_2_end
          - entity: input_number.sdb_1er_heating_period_2_temperature
        title: SDB 1er Not-workdays
        show_header_toggle: false
      - type: button
        name: Reset Schedy for SDB 1er
        show_state: false
        tap_action:
          action: call-service
          service: script.schedy_reevaluate
          service_data:
            room: sdb_1er
  - type: vertical-stack
    cards:
      - type: entities
        entities:
          - entity: input_boolean.bureau_heating_period_3
          - entity: input_datetime.bureau_heating_period_3_start
          - entity: input_datetime.bureau_heating_period_3_end
          - entity: input_number.bureau_heating_period_3_temperature
          - entity: input_boolean.bureau_heating_period_4
          - entity: input_datetime.bureau_heating_period_4_start
          - entity: input_datetime.bureau_heating_period_4_end
          - entity: input_number.bureau_heating_period_4_temperature
        title: Bureau Homeoffice
        show_header_toggle: false
      - type: entities
        entities:
          - entity: input_boolean.bureau_heating_period_1
          - entity: input_datetime.bureau_heating_period_1_start
          - entity: input_datetime.bureau_heating_period_1_end
          - entity: input_number.bureau_heating_period_1_temperature
          - entity: input_boolean.bureau_heating_period_2
          - entity: input_datetime.bureau_heating_period_2_start
          - entity: input_datetime.bureau_heating_period_2_end
          - entity: input_number.bureau_heating_period_2_temperature
        title: Bureau Not-Homeoffice
        show_header_toggle: false
      - type: button
        name: Reset Schedy for Bureau
        show_state: false
        tap_action:
          action: call-service
          service: script.schedy_reevaluate
          service_data:
            room: bureau
2 J'aimes

Super merci pour ton partage :smiley:

@pyg Ton script est redoutable… On voit la différence, moi je ne suis pas dev ! (hassos tu le lance ou ?)

Je vais tester dès que j’ai un peu de temps

Bonjour

Well done @pyg

Re-sending value due to missing confirmation …

Petite update pour le paramétrage Shedy, avec l’option par défaut « supports_hvac_modes: true », il envoie dans la foulée un « climate.set_hvac_mode » et un « climate.set_temperature ». Chez moi avec mes Fibaro Heat Controller, dans la plupart des cas, la deuxième instruction « climate.set_temperature » était ignorée (droppée ?). Shedy passait son température à faire des « Re-sending value due to missing confirmation ».
Avec l’option « supports_hvac_modes: false », OK le chauffage n’est plus jamais mis en OFF mais à une température de chauffe basse (kif-kik nan ?), ainsi Shedy n’envoie que la commande « climate.set_temperature » qui, chez moi, passe dès le premier coup.

1 J'aime

@pyg
Merci pour ton script, j’ai adapté à mon besoin et mis à jour mon article. Pour bien faire je vais ajouter la création des input_number pour les consignes par defaut (chauffage off et plage off).

Il me faut également trouver une solution pour planifier les 1/2 journées de travail (cas de qq un qui bosse le samedi matin…) Idées welcome :wink:

Il semblerait que si j’ai une plage qui se termine à 10.30 et une autre qui commence à 10.30 ça ne fonctionne pas. C’est ce que je voudrais utiliser pour juste changer la température de consigne.

Il me reste à l’adapter au mode froid pour cet été…

EDIT : En fait les plages ne sont pas prises en compte correctement. As tu changé qq chose ?

@pyg en fait j’ai trouvé une autre solution à base de binary afin d’éviter trop de choses dans Schedy.